]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.db.common/src/org/simantics/db/common/utils/ValueType.java
Fixed all line endings of the repository
[simantics/platform.git] / bundles / org.simantics.db.common / src / org / simantics / db / common / utils / ValueType.java
index ce4103d1bf11f0def99121735617aed67e2d0d04..97c2e798036ff447feac7f83756ed5885c820d0d 100644 (file)
-/*******************************************************************************\r
- * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
- * in Industry THTH ry.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- *     VTT Technical Research Centre of Finland - initial API and implementation\r
- *******************************************************************************/\r
-package org.simantics.db.common.utils;\r
-\r
-public abstract class ValueType {\r
-\r
-    private ValueType() {\r
-    }    \r
-\r
-    public abstract int     getConstantSize(); // returns -1 if not constant size\r
-    public abstract void    serialize(ByteBuffer buffer, Object obj);\r
-    public abstract void    unsafeSerialize(ByteBuffer buffer, Object obj);\r
-    public abstract Object  deserialize(ByteBuffer buffer);\r
-\r
-    public boolean supportsNativeArray() {\r
-        return false;\r
-    }\r
-    public void serializeNativeArray(ByteBuffer buffer, Object obj, int length) {\r
-        // TODO Throw exception\r
-    }\r
-\r
-    public Object deserializeNativeArray(ByteBuffer buffer, int length) {\r
-        // TODO Throw exception\r
-        return null;\r
-    }\r
-\r
-    public byte[] serialize(Object obj) {\r
-        int constantSize = getConstantSize();\r
-        ByteBuffer buffer = new ByteBuffer(constantSize >= 0 ? constantSize : 0);\r
-        serialize(buffer, obj);\r
-        return buffer.content();\r
-    }\r
-\r
-    public Object deserialize(byte[] bytes) {\r
-        return deserialize(new ByteBuffer(bytes));\r
-    }    \r
-\r
-    public static class BooleanType extends ValueType {\r
-        public BooleanType() {}       \r
-\r
-        @Override\r
-        public int getConstantSize() {\r
-            return 1;\r
-        }        \r
-        @Override\r
-        public void serialize(ByteBuffer buffer, Object obj) {\r
-            buffer.needs(1);\r
-            buffer.putByte( (Boolean)obj == true ? (byte)1 : (byte)0 );\r
-\r
-        }\r
-        @Override\r
-        public void  unsafeSerialize(ByteBuffer buffer, Object obj) {\r
-            buffer.putByte( (Boolean)obj == true ? (byte)1 : (byte)0 );            \r
-        }\r
-        @Override\r
-        public Object deserialize(ByteBuffer buffer) {\r
-            return buffer.getByte() != 0;\r
-        }\r
-    }\r
-\r
-    public static class ByteType extends ValueType {\r
-        public ByteType() {}       \r
-\r
-        @Override\r
-        public int getConstantSize() {\r
-            return 1;\r
-        }        \r
-        @Override\r
-        public void serialize(ByteBuffer buffer, Object obj) {\r
-            buffer.needs(1);\r
-            buffer.putByte((Byte)obj);\r
-\r
-        }\r
-        @Override\r
-        public void  unsafeSerialize(ByteBuffer buffer, Object obj) {\r
-            buffer.putByte((Byte)obj);            \r
-        }\r
-        @Override\r
-        public Object deserialize(ByteBuffer buffer) {\r
-            return buffer.getByte();\r
-        }\r
-    }\r
-\r
-    public static class IntegerType extends ValueType {\r
-        public IntegerType() {}       \r
-\r
-        @Override\r
-        public int getConstantSize() {\r
-            return 4;\r
-        }        \r
-        @Override\r
-        public void serialize(ByteBuffer buffer, Object obj) {\r
-            buffer.needs(4);\r
-            buffer.putInt((Integer)obj);\r
-\r
-        }\r
-        @Override\r
-        public void  unsafeSerialize(ByteBuffer buffer, Object obj) {\r
-            buffer.putInt((Integer)obj);            \r
-        }\r
-        @Override\r
-        public Object deserialize(ByteBuffer buffer) {\r
-            return buffer.getInt();\r
-        }\r
-    }\r
-\r
-    public static class LongType extends ValueType {\r
-        public LongType() {}       \r
-\r
-        @Override\r
-        public int getConstantSize() {\r
-            return 8;\r
-        }        \r
-        @Override\r
-        public void serialize(ByteBuffer buffer, Object obj) {\r
-            buffer.needs(8);\r
-            buffer.putLong((Long)obj);\r
-\r
-        }\r
-        @Override\r
-        public void  unsafeSerialize(ByteBuffer buffer, Object obj) {\r
-            buffer.putLong((Long)obj);            \r
-        }\r
-        @Override\r
-        public Object deserialize(ByteBuffer buffer) {\r
-            return buffer.getLong();\r
-        }\r
-    }\r
-    \r
-    public static class FloatType extends ValueType {\r
-        public FloatType() {}       \r
-\r
-        @Override\r
-        public int getConstantSize() {\r
-            return 4;\r
-        }        \r
-        @Override\r
-        public void serialize(ByteBuffer buffer, Object obj) {\r
-            buffer.needs(4);\r
-            buffer.putFloat((Float)obj);\r
-\r
-        }\r
-        @Override\r
-        public void  unsafeSerialize(ByteBuffer buffer, Object obj) {\r
-            buffer.putFloat((Float)obj);            \r
-        }\r
-        @Override\r
-        public Object deserialize(ByteBuffer buffer) {\r
-            return buffer.getFloat();\r
-        }\r
-    }\r
-\r
-    public static class DoubleType extends ValueType {\r
-        public DoubleType() {}       \r
-\r
-        @Override\r
-        public int getConstantSize() {\r
-            return 8;\r
-        }        \r
-        @Override\r
-        public void serialize(ByteBuffer buffer, Object obj) {\r
-            buffer.needs(8);\r
-            buffer.putDouble((Double)obj);\r
-\r
-        }\r
-        @Override\r
-        public void  unsafeSerialize(ByteBuffer buffer, Object obj) {\r
-            buffer.putDouble((Double)obj);            \r
-        }\r
-        @Override\r
-        public Object deserialize(ByteBuffer buffer) {\r
-            return buffer.getDouble();\r
-        }\r
-        public boolean supportsNativeArray() {\r
-            return true;\r
-        }\r
-        public void serializeNativeArray(ByteBuffer buffer, Object obj, int length) {\r
-            double[] array = (double[])obj;\r
-            if(length < 0)\r
-                buffer.putInt(array.length);\r
-            else\r
-                ; // TODO check\r
-            for(double d : array)\r
-                buffer.putDouble(d);\r
-        }\r
-\r
-        public Object deserializeNativeArray(ByteBuffer buffer, int length) {\r
-            double[] ret = new double[length];\r
-            for(int i=0;i<length;++i)\r
-                ret[i] = buffer.getDouble();\r
-            return ret;\r
-        }\r
-    }\r
-\r
-    public static class StringType extends ValueType {\r
-        public StringType() {}       \r
-\r
-        @Override\r
-        public int getConstantSize() {\r
-            return -1;\r
-        }        \r
-        @Override\r
-        public void serialize(ByteBuffer buffer, Object obj) {\r
-            buffer.putString((String)obj);\r
-\r
-        }\r
-        @Override\r
-        public void  unsafeSerialize(ByteBuffer buffer, Object obj) {\r
-            // TODO Throw exception\r
-        }\r
-        @Override\r
-        public Object deserialize(ByteBuffer buffer) {\r
-            return buffer.getString();\r
-        }\r
-    }\r
-\r
-    public static class ProductType extends ValueType {\r
-        public final ValueType[] baseTypes;\r
-        private int constantSize;\r
-\r
-        public ProductType(ValueType[] baseTypes) {\r
-            this.baseTypes = baseTypes;\r
-            constantSize = 0;\r
-            for(ValueType b : baseTypes) {\r
-                int temp = b.getConstantSize();\r
-                if(temp==-1) {\r
-                    constantSize = -1;\r
-                    break;\r
-                }\r
-                constantSize += temp;\r
-            }\r
-        }\r
-\r
-        @Override\r
-        public int getConstantSize() {\r
-            return constantSize;\r
-        }        \r
-        @Override\r
-        public void serialize(ByteBuffer buffer, Object obj) {\r
-            if(constantSize >= 0) {\r
-                buffer.needs(constantSize);\r
-                unsafeSerialize(buffer, obj);\r
-            }\r
-            else {\r
-                Object[] subobjects = (Object[])obj;\r
-                // FIXME Catch cast exception\r
-                // FIXME Check length\r
-                for(int i=0;i<baseTypes.length;++i)\r
-                    baseTypes[i].serialize(buffer, subobjects[i]);\r
-            }\r
-        }\r
-        @Override\r
-        public void  unsafeSerialize(ByteBuffer buffer, Object obj) {\r
-            Object[] subobjects = (Object[])obj;\r
-            // FIXME Catch cast exception\r
-            // FIXME Check length\r
-            for(int i=0;i<baseTypes.length;++i)\r
-                baseTypes[i].unsafeSerialize(buffer, subobjects[i]);\r
-        }\r
-        @Override\r
-        public Object deserialize(ByteBuffer buffer) {\r
-            Object[] ret = new Object[baseTypes.length];\r
-            for(int i=0;i<baseTypes.length;++i)\r
-                ret[i] = baseTypes[i].deserialize(buffer);\r
-            return ret;\r
-        }\r
-    }\r
-\r
-    public static class Construction {\r
-        int constructor;\r
-        Object value;\r
-    }\r
-\r
-    public static class SumType extends ValueType {\r
-        public final ValueType[] baseTypes;\r
-        private int constantSize;\r
-\r
-        public SumType(ValueType[] baseTypes) {\r
-            this.baseTypes = baseTypes;\r
-            constantSize = -2;\r
-            for(ValueType b : baseTypes) {\r
-                int temp = b.getConstantSize();\r
-                if(temp != constantSize) {\r
-                    if(constantSize==-2 && temp >= 0)\r
-                        constantSize = temp;                        \r
-                    else {\r
-                        constantSize = -1;\r
-                        break;\r
-                    }\r
-                }\r
-            }\r
-            if(constantSize >= 0)\r
-                constantSize += 4;\r
-        }\r
-\r
-        @Override\r
-        public int getConstantSize() {\r
-            return constantSize;\r
-        }        \r
-        @Override\r
-        public void serialize(ByteBuffer buffer, Object obj) {\r
-            if(constantSize >= 0) {\r
-                buffer.needs(constantSize);\r
-                unsafeSerialize(buffer, obj);\r
-            }\r
-            else {\r
-                Construction construction = (Construction)obj;\r
-                // FIXME validate construction.constructor\r
-                buffer.needs(4);\r
-                buffer.putInt(construction.constructor);\r
-                baseTypes[construction.constructor].serialize(buffer, construction.value);\r
-            }\r
-        }\r
-        @Override\r
-        public void  unsafeSerialize(ByteBuffer buffer, Object obj) {\r
-            Construction construction = (Construction)obj;\r
-            // FIXME validate construction.constructor\r
-            buffer.putInt(construction.constructor);\r
-            baseTypes[construction.constructor].unsafeSerialize(buffer, construction.value);\r
-        }\r
-        @Override\r
-        public Object deserialize(ByteBuffer buffer) {\r
-            Construction ret = new Construction();\r
-            ret.constructor = buffer.getInt();\r
-            // FIXME validate construction.constructor\r
-            ret.value = baseTypes[ret.constructor].deserialize(buffer);\r
-            return ret;\r
-        }\r
-    }\r
-\r
-    public static class VariableLengthArrayType extends ValueType {\r
-        public final ValueType baseType;\r
-        private int baseTypeConstantSize;\r
-        private boolean supportsNativeArray;\r
-\r
-        public VariableLengthArrayType(ValueType baseType) {\r
-            this.baseType = baseType;\r
-            baseTypeConstantSize = baseType.getConstantSize();\r
-            supportsNativeArray = baseType.supportsNativeArray();\r
-        }\r
-\r
-        @Override\r
-        public int getConstantSize() {\r
-            return -1;\r
-        }        \r
-\r
-        @Override\r
-        public void serialize(ByteBuffer buffer, Object obj) {\r
-            if(baseTypeConstantSize >= 0) {\r
-                if(obj instanceof Object[]) {\r
-                    Object[] subobjects = (Object[])obj;              \r
-                    buffer.needs(4 + subobjects.length * baseTypeConstantSize);\r
-                    buffer.putInt(subobjects.length);\r
-                    for(Object subobj : subobjects)\r
-                        baseType.unsafeSerialize(buffer, subobj);\r
-                }\r
-                else if(supportsNativeArray) \r
-                    baseType.serializeNativeArray(buffer, obj, -1);\r
-                else\r
-                    ; // TODO exc\r
-\r
-            }\r
-            else {\r
-                Object[] subobjects = (Object[])obj;              \r
-                buffer.needs(4);\r
-                buffer.putInt(subobjects.length);\r
-                for(Object subobj : subobjects)\r
-                    baseType.serialize(buffer, subobj);\r
-            }\r
-        }\r
-        @Override\r
-        public void  unsafeSerialize(ByteBuffer buffer, Object obj) {\r
-            // TODO Throw exception\r
-        }\r
-        @Override\r
-        public Object deserialize(ByteBuffer buffer) {\r
-            int length = buffer.getInt();\r
-            if(supportsNativeArray) \r
-                return baseType.deserializeNativeArray(buffer, length);\r
-            else {\r
-                Object[] ret = new Object[length];\r
-                for(int i=0;i<length;++i)\r
-                    ret[i] = baseType.deserialize(buffer);\r
-                return ret;\r
-            }\r
-        }\r
-    }\r
-\r
-    public static class FixedLengthArrayType extends ValueType {\r
-        public final ValueType baseType;\r
-        public final int dimension;\r
-        private int constantSize;\r
-        private boolean supportsNativeArray;\r
-\r
-        public FixedLengthArrayType(ValueType baseType, int dimension) {\r
-            this.baseType = baseType;\r
-            this.dimension = dimension;\r
-            constantSize = baseType.getConstantSize();\r
-            if(constantSize >= 0) {\r
-                constantSize *= dimension;\r
-                supportsNativeArray = baseType.supportsNativeArray();\r
-            }\r
-        }\r
-\r
-        @Override\r
-        public int getConstantSize() {\r
-            return constantSize;\r
-        }        \r
-\r
-        @Override\r
-        public void serialize(ByteBuffer buffer, Object obj) {\r
-            if(constantSize >= 0) {\r
-                buffer.needs(constantSize);\r
-                unsafeSerialize(buffer, obj);\r
-            }\r
-            else {\r
-                Object[] subobjects = (Object[])obj;              \r
-                // FIXME checks\r
-                for(Object subobj : subobjects)\r
-                    baseType.serialize(buffer, subobj);\r
-            }\r
-        }\r
-        @Override\r
-        public void  unsafeSerialize(ByteBuffer buffer, Object obj) {\r
-            if(supportsNativeArray)\r
-                baseType.serializeNativeArray(buffer, obj, dimension);\r
-            else {\r
-                Object[] subobjects = (Object[])obj;              \r
-                // FIXME checks\r
-                for(Object subobj : subobjects)\r
-                    baseType.unsafeSerialize(buffer, subobj);\r
-            }\r
-        }\r
-        @Override\r
-        public Object deserialize(ByteBuffer buffer) {\r
-            if(supportsNativeArray) \r
-                return baseType.deserializeNativeArray(buffer, dimension);\r
-            else {\r
-                Object[] ret = new Object[dimension];\r
-                for(int i=0;i<dimension;++i)\r
-                    ret[i] = baseType.deserialize(buffer);\r
-                return ret;\r
-            }\r
-        }\r
-    }    \r
-\r
-    static final private class ByteBuffer {\r
-        public byte[] bytes;\r
-        public int    offset;\r
-\r
-        public ByteBuffer(int capacity) {\r
-            this.bytes = new byte[capacity];\r
-            this.offset = 0;\r
-        }\r
-\r
-        public ByteBuffer(byte[] bytes) {\r
-            this.bytes = bytes;\r
-            this.offset = 0;\r
-        }\r
-\r
-        public void needs(int size) {\r
-            if(offset + size > bytes.length) {\r
-                // FIXME bytes = Arrays.copyOf(bytes, newSize);\r
-                byte[] newBytes = new byte[offset*2 + size];\r
-                for(int i=0;i<bytes.length;++i)\r
-                    newBytes[i] = bytes[i];\r
-                bytes = newBytes;\r
-            }\r
-        }\r
-\r
-        public byte[] content() {\r
-            if(offset == bytes.length)\r
-                return bytes;\r
-            // FIXME bytes = Arrays.copyOf(bytes, offset);\r
-            byte[] newBytes = new byte[offset];\r
-            for(int i=0;i<offset;++i)\r
-                newBytes[i] = bytes[i];\r
-            return newBytes;\r
-        }\r
-\r
-        public void putByte(byte v) {\r
-            bytes[offset] = v;\r
-            offset += 1;\r
-        }\r
-        public void putShort(short v) {\r
-            bytes[offset] = (byte) v;\r
-            bytes[offset+1] = (byte) (v >>> 8);\r
-            offset += 2;\r
-        }\r
-        public void putInt(int v) {\r
-            bytes[offset] = (byte) v;\r
-            bytes[offset+1] = (byte) (v >>> 8);\r
-            bytes[offset+2] = (byte) (v >>> 16);\r
-            bytes[offset+3] = (byte) (v >>> 24);\r
-            offset += 4;\r
-        }\r
-        public void putLong(long v) {\r
-            bytes[offset] = (byte) v;\r
-            bytes[offset+1] = (byte) (v >>> 8);\r
-            bytes[offset+2] = (byte) (v >>> 16);\r
-            bytes[offset+3] = (byte) (v >>> 24);\r
-            bytes[offset+4] = (byte) (v >>> 32);\r
-            bytes[offset+5] = (byte) (v >>> 40);\r
-            bytes[offset+6] = (byte) (v >>> 48);\r
-            bytes[offset+7] = (byte) (v >>> 56);\r
-            offset += 8;\r
-        }\r
-        public void putFloat(float _v) {\r
-            int v = Float.floatToIntBits(_v);\r
-            bytes[offset] = (byte) v;\r
-            bytes[offset+1] = (byte) (v >>> 8);\r
-            bytes[offset+2] = (byte) (v >>> 16);\r
-            bytes[offset+3] = (byte) (v >>> 24);\r
-            offset += 4;\r
-        }\r
-        public void putDouble(double _v) {\r
-            long v = Double.doubleToLongBits(_v);\r
-            bytes[offset] = (byte) v;\r
-            bytes[offset+1] = (byte) (v >>> 8);\r
-            bytes[offset+2] = (byte) (v >>> 16);\r
-            bytes[offset+3] = (byte) (v >>> 24);\r
-            bytes[offset+4] = (byte) (v >>> 32);\r
-            bytes[offset+5] = (byte) (v >>> 40);\r
-            bytes[offset+6] = (byte) (v >>> 48);\r
-            bytes[offset+7] = (byte) (v >>> 56);\r
-            offset += 8;\r
-        }\r
-        public void putString(String str) {\r
-\r
-            // UTF-16 -> modified UTF-8\r
-\r
-            int length = 4;\r
-            for(int i=0;i<str.length();++i) {\r
-                char c = str.charAt(i);\r
-                if(c < 0x80)\r
-                    length += 1;\r
-                else if(c < 0x800)\r
-                    length += 2;\r
-                else \r
-                    length += 3;\r
-            }\r
-            needs(length);\r
-            putInt(str.length());\r
-            for(int i=0;i<str.length();++i) {\r
-                char c = str.charAt(i);\r
-                if(c < 0x80) {\r
-                    bytes[offset] = (byte)c;\r
-                    offset += 1;\r
-                }\r
-                else if(c < 0x800) {\r
-                    bytes[offset]   = (byte)(0xc0 + (c >>> 6));\r
-                    bytes[offset+1] = (byte)(0x80 + (c & 0x3f));\r
-                    offset += 2;\r
-                }\r
-                else {\r
-                    // FIXME handle range D800 - DFFF\r
-                    bytes[offset]   = (byte)(0xe0 + (c >>> 12));\r
-                    bytes[offset+1] = (byte)(0x80 + ((c >>> 6) & 0x3f));\r
-                    bytes[offset+2] = (byte)(0x80 + (c & 0x3f));\r
-                    offset += 3;\r
-                }\r
-            }\r
-        }\r
-        public byte getByte() {\r
-            ++offset;\r
-            return bytes[offset-1];\r
-        }\r
-        public short getShort() {\r
-            int v = bytes[offset] & 0xFF;\r
-            v += (bytes[offset+1] & 0xFF) << 8;\r
-            offset += 2;\r
-            return (short)v;\r
-        }\r
-        public int getInt() {\r
-            int v = bytes[offset] & 0xFF;\r
-            v += (bytes[offset+1] & 0xFF) << 8;\r
-            v += (bytes[offset+2] & 0xFF) << 16;\r
-            v += (bytes[offset+3] & 0xFF) << 24;\r
-            offset += 4;\r
-            return v;\r
-        }\r
-        public long getLong() {\r
-            long v = bytes[offset] & 0xFFL;\r
-            v += (bytes[offset+1] & 0xFFL) << 8;\r
-            v += (bytes[offset+2] & 0xFFL) << 16;\r
-            v += (bytes[offset+3] & 0xFFL) << 24;\r
-            v += (bytes[offset+4] & 0xFFL) << 32;\r
-            v += (bytes[offset+5] & 0xFFL) << 40;\r
-            v += (bytes[offset+6] & 0xFFL) << 48;\r
-            v += (bytes[offset+7] & 0xFFL) << 56;\r
-            offset += 8;\r
-            return v;\r
-        }\r
-        public float getFloat() {\r
-            int v = bytes[offset] & 0xFF;\r
-            v += (bytes[offset+1] & 0xFF) << 8;\r
-            v += (bytes[offset+2] & 0xFF) << 16;\r
-            v += (bytes[offset+3] & 0xFF) << 24;\r
-            offset += 4;\r
-            return Float.intBitsToFloat(v);\r
-        }\r
-        public double getDouble() {\r
-            long v = bytes[offset] & 0xFFL;\r
-            v += (bytes[offset+1] & 0xFFL) << 8;\r
-            v += (bytes[offset+2] & 0xFFL) << 16;\r
-            v += (bytes[offset+3] & 0xFFL) << 24;\r
-            v += (bytes[offset+4] & 0xFFL) << 32;\r
-            v += (bytes[offset+5] & 0xFFL) << 40;\r
-            v += (bytes[offset+6] & 0xFFL) << 48;\r
-            v += (bytes[offset+7] & 0xFFL) << 56;\r
-            offset += 8;\r
-            return Double.longBitsToDouble(v);\r
-        }\r
-        public String getString() {\r
-            int length = getInt();\r
-            char[] chars = new char[length];\r
-            for(int i=0;i<length;++i) {\r
-                int b0 = (int)bytes[offset];\r
-                int c;\r
-                if(b0 >= 0) {\r
-                    c = b0;\r
-                    offset += 1;\r
-                }\r
-                else if(b0 < 0xe0-256) {\r
-                    c = ((b0 & 0x1f) << 6) +\r
-                        (bytes[offset+1] & 0x3f);\r
-                    offset += 2;\r
-                }\r
-                else if(b0 < 0xf0-256) {\r
-                    c = ((b0 & 0x0f) << 12) +\r
-                        ((bytes[offset+1] & 0x3f) << 6) +\r
-                        (bytes[offset+2] & 0x3f);\r
-                    offset += 3;\r
-                }\r
-                else\r
-                    c = 0; // FIXME\r
-                chars[i] = (char)c;\r
-            }\r
-            return new String(chars);\r
-        }\r
-        \r
-    }\r
-    \r
-}\r
+/*******************************************************************************
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management
+ * in Industry THTH ry.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     VTT Technical Research Centre of Finland - initial API and implementation
+ *******************************************************************************/
+package org.simantics.db.common.utils;
+
+public abstract class ValueType {
+
+    private ValueType() {
+    }    
+
+    public abstract int     getConstantSize(); // returns -1 if not constant size
+    public abstract void    serialize(ByteBuffer buffer, Object obj);
+    public abstract void    unsafeSerialize(ByteBuffer buffer, Object obj);
+    public abstract Object  deserialize(ByteBuffer buffer);
+
+    public boolean supportsNativeArray() {
+        return false;
+    }
+    public void serializeNativeArray(ByteBuffer buffer, Object obj, int length) {
+        // TODO Throw exception
+    }
+
+    public Object deserializeNativeArray(ByteBuffer buffer, int length) {
+        // TODO Throw exception
+        return null;
+    }
+
+    public byte[] serialize(Object obj) {
+        int constantSize = getConstantSize();
+        ByteBuffer buffer = new ByteBuffer(constantSize >= 0 ? constantSize : 0);
+        serialize(buffer, obj);
+        return buffer.content();
+    }
+
+    public Object deserialize(byte[] bytes) {
+        return deserialize(new ByteBuffer(bytes));
+    }    
+
+    public static class BooleanType extends ValueType {
+        public BooleanType() {}       
+
+        @Override
+        public int getConstantSize() {
+            return 1;
+        }        
+        @Override
+        public void serialize(ByteBuffer buffer, Object obj) {
+            buffer.needs(1);
+            buffer.putByte( (Boolean)obj == true ? (byte)1 : (byte)0 );
+
+        }
+        @Override
+        public void  unsafeSerialize(ByteBuffer buffer, Object obj) {
+            buffer.putByte( (Boolean)obj == true ? (byte)1 : (byte)0 );            
+        }
+        @Override
+        public Object deserialize(ByteBuffer buffer) {
+            return buffer.getByte() != 0;
+        }
+    }
+
+    public static class ByteType extends ValueType {
+        public ByteType() {}       
+
+        @Override
+        public int getConstantSize() {
+            return 1;
+        }        
+        @Override
+        public void serialize(ByteBuffer buffer, Object obj) {
+            buffer.needs(1);
+            buffer.putByte((Byte)obj);
+
+        }
+        @Override
+        public void  unsafeSerialize(ByteBuffer buffer, Object obj) {
+            buffer.putByte((Byte)obj);            
+        }
+        @Override
+        public Object deserialize(ByteBuffer buffer) {
+            return buffer.getByte();
+        }
+    }
+
+    public static class IntegerType extends ValueType {
+        public IntegerType() {}       
+
+        @Override
+        public int getConstantSize() {
+            return 4;
+        }        
+        @Override
+        public void serialize(ByteBuffer buffer, Object obj) {
+            buffer.needs(4);
+            buffer.putInt((Integer)obj);
+
+        }
+        @Override
+        public void  unsafeSerialize(ByteBuffer buffer, Object obj) {
+            buffer.putInt((Integer)obj);            
+        }
+        @Override
+        public Object deserialize(ByteBuffer buffer) {
+            return buffer.getInt();
+        }
+    }
+
+    public static class LongType extends ValueType {
+        public LongType() {}       
+
+        @Override
+        public int getConstantSize() {
+            return 8;
+        }        
+        @Override
+        public void serialize(ByteBuffer buffer, Object obj) {
+            buffer.needs(8);
+            buffer.putLong((Long)obj);
+
+        }
+        @Override
+        public void  unsafeSerialize(ByteBuffer buffer, Object obj) {
+            buffer.putLong((Long)obj);            
+        }
+        @Override
+        public Object deserialize(ByteBuffer buffer) {
+            return buffer.getLong();
+        }
+    }
+    
+    public static class FloatType extends ValueType {
+        public FloatType() {}       
+
+        @Override
+        public int getConstantSize() {
+            return 4;
+        }        
+        @Override
+        public void serialize(ByteBuffer buffer, Object obj) {
+            buffer.needs(4);
+            buffer.putFloat((Float)obj);
+
+        }
+        @Override
+        public void  unsafeSerialize(ByteBuffer buffer, Object obj) {
+            buffer.putFloat((Float)obj);            
+        }
+        @Override
+        public Object deserialize(ByteBuffer buffer) {
+            return buffer.getFloat();
+        }
+    }
+
+    public static class DoubleType extends ValueType {
+        public DoubleType() {}       
+
+        @Override
+        public int getConstantSize() {
+            return 8;
+        }        
+        @Override
+        public void serialize(ByteBuffer buffer, Object obj) {
+            buffer.needs(8);
+            buffer.putDouble((Double)obj);
+
+        }
+        @Override
+        public void  unsafeSerialize(ByteBuffer buffer, Object obj) {
+            buffer.putDouble((Double)obj);            
+        }
+        @Override
+        public Object deserialize(ByteBuffer buffer) {
+            return buffer.getDouble();
+        }
+        public boolean supportsNativeArray() {
+            return true;
+        }
+        public void serializeNativeArray(ByteBuffer buffer, Object obj, int length) {
+            double[] array = (double[])obj;
+            if(length < 0)
+                buffer.putInt(array.length);
+            else
+                ; // TODO check
+            for(double d : array)
+                buffer.putDouble(d);
+        }
+
+        public Object deserializeNativeArray(ByteBuffer buffer, int length) {
+            double[] ret = new double[length];
+            for(int i=0;i<length;++i)
+                ret[i] = buffer.getDouble();
+            return ret;
+        }
+    }
+
+    public static class StringType extends ValueType {
+        public StringType() {}       
+
+        @Override
+        public int getConstantSize() {
+            return -1;
+        }        
+        @Override
+        public void serialize(ByteBuffer buffer, Object obj) {
+            buffer.putString((String)obj);
+
+        }
+        @Override
+        public void  unsafeSerialize(ByteBuffer buffer, Object obj) {
+            // TODO Throw exception
+        }
+        @Override
+        public Object deserialize(ByteBuffer buffer) {
+            return buffer.getString();
+        }
+    }
+
+    public static class ProductType extends ValueType {
+        public final ValueType[] baseTypes;
+        private int constantSize;
+
+        public ProductType(ValueType[] baseTypes) {
+            this.baseTypes = baseTypes;
+            constantSize = 0;
+            for(ValueType b : baseTypes) {
+                int temp = b.getConstantSize();
+                if(temp==-1) {
+                    constantSize = -1;
+                    break;
+                }
+                constantSize += temp;
+            }
+        }
+
+        @Override
+        public int getConstantSize() {
+            return constantSize;
+        }        
+        @Override
+        public void serialize(ByteBuffer buffer, Object obj) {
+            if(constantSize >= 0) {
+                buffer.needs(constantSize);
+                unsafeSerialize(buffer, obj);
+            }
+            else {
+                Object[] subobjects = (Object[])obj;
+                // FIXME Catch cast exception
+                // FIXME Check length
+                for(int i=0;i<baseTypes.length;++i)
+                    baseTypes[i].serialize(buffer, subobjects[i]);
+            }
+        }
+        @Override
+        public void  unsafeSerialize(ByteBuffer buffer, Object obj) {
+            Object[] subobjects = (Object[])obj;
+            // FIXME Catch cast exception
+            // FIXME Check length
+            for(int i=0;i<baseTypes.length;++i)
+                baseTypes[i].unsafeSerialize(buffer, subobjects[i]);
+        }
+        @Override
+        public Object deserialize(ByteBuffer buffer) {
+            Object[] ret = new Object[baseTypes.length];
+            for(int i=0;i<baseTypes.length;++i)
+                ret[i] = baseTypes[i].deserialize(buffer);
+            return ret;
+        }
+    }
+
+    public static class Construction {
+        int constructor;
+        Object value;
+    }
+
+    public static class SumType extends ValueType {
+        public final ValueType[] baseTypes;
+        private int constantSize;
+
+        public SumType(ValueType[] baseTypes) {
+            this.baseTypes = baseTypes;
+            constantSize = -2;
+            for(ValueType b : baseTypes) {
+                int temp = b.getConstantSize();
+                if(temp != constantSize) {
+                    if(constantSize==-2 && temp >= 0)
+                        constantSize = temp;                        
+                    else {
+                        constantSize = -1;
+                        break;
+                    }
+                }
+            }
+            if(constantSize >= 0)
+                constantSize += 4;
+        }
+
+        @Override
+        public int getConstantSize() {
+            return constantSize;
+        }        
+        @Override
+        public void serialize(ByteBuffer buffer, Object obj) {
+            if(constantSize >= 0) {
+                buffer.needs(constantSize);
+                unsafeSerialize(buffer, obj);
+            }
+            else {
+                Construction construction = (Construction)obj;
+                // FIXME validate construction.constructor
+                buffer.needs(4);
+                buffer.putInt(construction.constructor);
+                baseTypes[construction.constructor].serialize(buffer, construction.value);
+            }
+        }
+        @Override
+        public void  unsafeSerialize(ByteBuffer buffer, Object obj) {
+            Construction construction = (Construction)obj;
+            // FIXME validate construction.constructor
+            buffer.putInt(construction.constructor);
+            baseTypes[construction.constructor].unsafeSerialize(buffer, construction.value);
+        }
+        @Override
+        public Object deserialize(ByteBuffer buffer) {
+            Construction ret = new Construction();
+            ret.constructor = buffer.getInt();
+            // FIXME validate construction.constructor
+            ret.value = baseTypes[ret.constructor].deserialize(buffer);
+            return ret;
+        }
+    }
+
+    public static class VariableLengthArrayType extends ValueType {
+        public final ValueType baseType;
+        private int baseTypeConstantSize;
+        private boolean supportsNativeArray;
+
+        public VariableLengthArrayType(ValueType baseType) {
+            this.baseType = baseType;
+            baseTypeConstantSize = baseType.getConstantSize();
+            supportsNativeArray = baseType.supportsNativeArray();
+        }
+
+        @Override
+        public int getConstantSize() {
+            return -1;
+        }        
+
+        @Override
+        public void serialize(ByteBuffer buffer, Object obj) {
+            if(baseTypeConstantSize >= 0) {
+                if(obj instanceof Object[]) {
+                    Object[] subobjects = (Object[])obj;              
+                    buffer.needs(4 + subobjects.length * baseTypeConstantSize);
+                    buffer.putInt(subobjects.length);
+                    for(Object subobj : subobjects)
+                        baseType.unsafeSerialize(buffer, subobj);
+                }
+                else if(supportsNativeArray) 
+                    baseType.serializeNativeArray(buffer, obj, -1);
+                else
+                    ; // TODO exc
+
+            }
+            else {
+                Object[] subobjects = (Object[])obj;              
+                buffer.needs(4);
+                buffer.putInt(subobjects.length);
+                for(Object subobj : subobjects)
+                    baseType.serialize(buffer, subobj);
+            }
+        }
+        @Override
+        public void  unsafeSerialize(ByteBuffer buffer, Object obj) {
+            // TODO Throw exception
+        }
+        @Override
+        public Object deserialize(ByteBuffer buffer) {
+            int length = buffer.getInt();
+            if(supportsNativeArray) 
+                return baseType.deserializeNativeArray(buffer, length);
+            else {
+                Object[] ret = new Object[length];
+                for(int i=0;i<length;++i)
+                    ret[i] = baseType.deserialize(buffer);
+                return ret;
+            }
+        }
+    }
+
+    public static class FixedLengthArrayType extends ValueType {
+        public final ValueType baseType;
+        public final int dimension;
+        private int constantSize;
+        private boolean supportsNativeArray;
+
+        public FixedLengthArrayType(ValueType baseType, int dimension) {
+            this.baseType = baseType;
+            this.dimension = dimension;
+            constantSize = baseType.getConstantSize();
+            if(constantSize >= 0) {
+                constantSize *= dimension;
+                supportsNativeArray = baseType.supportsNativeArray();
+            }
+        }
+
+        @Override
+        public int getConstantSize() {
+            return constantSize;
+        }        
+
+        @Override
+        public void serialize(ByteBuffer buffer, Object obj) {
+            if(constantSize >= 0) {
+                buffer.needs(constantSize);
+                unsafeSerialize(buffer, obj);
+            }
+            else {
+                Object[] subobjects = (Object[])obj;              
+                // FIXME checks
+                for(Object subobj : subobjects)
+                    baseType.serialize(buffer, subobj);
+            }
+        }
+        @Override
+        public void  unsafeSerialize(ByteBuffer buffer, Object obj) {
+            if(supportsNativeArray)
+                baseType.serializeNativeArray(buffer, obj, dimension);
+            else {
+                Object[] subobjects = (Object[])obj;              
+                // FIXME checks
+                for(Object subobj : subobjects)
+                    baseType.unsafeSerialize(buffer, subobj);
+            }
+        }
+        @Override
+        public Object deserialize(ByteBuffer buffer) {
+            if(supportsNativeArray) 
+                return baseType.deserializeNativeArray(buffer, dimension);
+            else {
+                Object[] ret = new Object[dimension];
+                for(int i=0;i<dimension;++i)
+                    ret[i] = baseType.deserialize(buffer);
+                return ret;
+            }
+        }
+    }    
+
+    static final private class ByteBuffer {
+        public byte[] bytes;
+        public int    offset;
+
+        public ByteBuffer(int capacity) {
+            this.bytes = new byte[capacity];
+            this.offset = 0;
+        }
+
+        public ByteBuffer(byte[] bytes) {
+            this.bytes = bytes;
+            this.offset = 0;
+        }
+
+        public void needs(int size) {
+            if(offset + size > bytes.length) {
+                // FIXME bytes = Arrays.copyOf(bytes, newSize);
+                byte[] newBytes = new byte[offset*2 + size];
+                for(int i=0;i<bytes.length;++i)
+                    newBytes[i] = bytes[i];
+                bytes = newBytes;
+            }
+        }
+
+        public byte[] content() {
+            if(offset == bytes.length)
+                return bytes;
+            // FIXME bytes = Arrays.copyOf(bytes, offset);
+            byte[] newBytes = new byte[offset];
+            for(int i=0;i<offset;++i)
+                newBytes[i] = bytes[i];
+            return newBytes;
+        }
+
+        public void putByte(byte v) {
+            bytes[offset] = v;
+            offset += 1;
+        }
+        public void putShort(short v) {
+            bytes[offset] = (byte) v;
+            bytes[offset+1] = (byte) (v >>> 8);
+            offset += 2;
+        }
+        public void putInt(int v) {
+            bytes[offset] = (byte) v;
+            bytes[offset+1] = (byte) (v >>> 8);
+            bytes[offset+2] = (byte) (v >>> 16);
+            bytes[offset+3] = (byte) (v >>> 24);
+            offset += 4;
+        }
+        public void putLong(long v) {
+            bytes[offset] = (byte) v;
+            bytes[offset+1] = (byte) (v >>> 8);
+            bytes[offset+2] = (byte) (v >>> 16);
+            bytes[offset+3] = (byte) (v >>> 24);
+            bytes[offset+4] = (byte) (v >>> 32);
+            bytes[offset+5] = (byte) (v >>> 40);
+            bytes[offset+6] = (byte) (v >>> 48);
+            bytes[offset+7] = (byte) (v >>> 56);
+            offset += 8;
+        }
+        public void putFloat(float _v) {
+            int v = Float.floatToIntBits(_v);
+            bytes[offset] = (byte) v;
+            bytes[offset+1] = (byte) (v >>> 8);
+            bytes[offset+2] = (byte) (v >>> 16);
+            bytes[offset+3] = (byte) (v >>> 24);
+            offset += 4;
+        }
+        public void putDouble(double _v) {
+            long v = Double.doubleToLongBits(_v);
+            bytes[offset] = (byte) v;
+            bytes[offset+1] = (byte) (v >>> 8);
+            bytes[offset+2] = (byte) (v >>> 16);
+            bytes[offset+3] = (byte) (v >>> 24);
+            bytes[offset+4] = (byte) (v >>> 32);
+            bytes[offset+5] = (byte) (v >>> 40);
+            bytes[offset+6] = (byte) (v >>> 48);
+            bytes[offset+7] = (byte) (v >>> 56);
+            offset += 8;
+        }
+        public void putString(String str) {
+
+            // UTF-16 -> modified UTF-8
+
+            int length = 4;
+            for(int i=0;i<str.length();++i) {
+                char c = str.charAt(i);
+                if(c < 0x80)
+                    length += 1;
+                else if(c < 0x800)
+                    length += 2;
+                else 
+                    length += 3;
+            }
+            needs(length);
+            putInt(str.length());
+            for(int i=0;i<str.length();++i) {
+                char c = str.charAt(i);
+                if(c < 0x80) {
+                    bytes[offset] = (byte)c;
+                    offset += 1;
+                }
+                else if(c < 0x800) {
+                    bytes[offset]   = (byte)(0xc0 + (c >>> 6));
+                    bytes[offset+1] = (byte)(0x80 + (c & 0x3f));
+                    offset += 2;
+                }
+                else {
+                    // FIXME handle range D800 - DFFF
+                    bytes[offset]   = (byte)(0xe0 + (c >>> 12));
+                    bytes[offset+1] = (byte)(0x80 + ((c >>> 6) & 0x3f));
+                    bytes[offset+2] = (byte)(0x80 + (c & 0x3f));
+                    offset += 3;
+                }
+            }
+        }
+        public byte getByte() {
+            ++offset;
+            return bytes[offset-1];
+        }
+        public short getShort() {
+            int v = bytes[offset] & 0xFF;
+            v += (bytes[offset+1] & 0xFF) << 8;
+            offset += 2;
+            return (short)v;
+        }
+        public int getInt() {
+            int v = bytes[offset] & 0xFF;
+            v += (bytes[offset+1] & 0xFF) << 8;
+            v += (bytes[offset+2] & 0xFF) << 16;
+            v += (bytes[offset+3] & 0xFF) << 24;
+            offset += 4;
+            return v;
+        }
+        public long getLong() {
+            long v = bytes[offset] & 0xFFL;
+            v += (bytes[offset+1] & 0xFFL) << 8;
+            v += (bytes[offset+2] & 0xFFL) << 16;
+            v += (bytes[offset+3] & 0xFFL) << 24;
+            v += (bytes[offset+4] & 0xFFL) << 32;
+            v += (bytes[offset+5] & 0xFFL) << 40;
+            v += (bytes[offset+6] & 0xFFL) << 48;
+            v += (bytes[offset+7] & 0xFFL) << 56;
+            offset += 8;
+            return v;
+        }
+        public float getFloat() {
+            int v = bytes[offset] & 0xFF;
+            v += (bytes[offset+1] & 0xFF) << 8;
+            v += (bytes[offset+2] & 0xFF) << 16;
+            v += (bytes[offset+3] & 0xFF) << 24;
+            offset += 4;
+            return Float.intBitsToFloat(v);
+        }
+        public double getDouble() {
+            long v = bytes[offset] & 0xFFL;
+            v += (bytes[offset+1] & 0xFFL) << 8;
+            v += (bytes[offset+2] & 0xFFL) << 16;
+            v += (bytes[offset+3] & 0xFFL) << 24;
+            v += (bytes[offset+4] & 0xFFL) << 32;
+            v += (bytes[offset+5] & 0xFFL) << 40;
+            v += (bytes[offset+6] & 0xFFL) << 48;
+            v += (bytes[offset+7] & 0xFFL) << 56;
+            offset += 8;
+            return Double.longBitsToDouble(v);
+        }
+        public String getString() {
+            int length = getInt();
+            char[] chars = new char[length];
+            for(int i=0;i<length;++i) {
+                int b0 = (int)bytes[offset];
+                int c;
+                if(b0 >= 0) {
+                    c = b0;
+                    offset += 1;
+                }
+                else if(b0 < 0xe0-256) {
+                    c = ((b0 & 0x1f) << 6) +
+                        (bytes[offset+1] & 0x3f);
+                    offset += 2;
+                }
+                else if(b0 < 0xf0-256) {
+                    c = ((b0 & 0x0f) << 12) +
+                        ((bytes[offset+1] & 0x3f) << 6) +
+                        (bytes[offset+2] & 0x3f);
+                    offset += 3;
+                }
+                else
+                    c = 0; // FIXME
+                chars[i] = (char)c;
+            }
+            return new String(chars);
+        }
+        
+    }
+    
+}