]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.databoard/src/org/simantics/databoard/serialization/impl/UnionSerializer.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.databoard / src / org / simantics / databoard / serialization / impl / UnionSerializer.java
1 package org.simantics.databoard.serialization.impl;\r
2 \r
3 import gnu.trove.map.hash.TObjectIntHashMap;\r
4 \r
5 import java.io.DataInput;\r
6 import java.io.DataOutput;\r
7 import java.io.IOException;\r
8 import java.util.List;\r
9 \r
10 import org.simantics.databoard.binding.UnionBinding;\r
11 import org.simantics.databoard.binding.error.BindingException;\r
12 import org.simantics.databoard.binding.util.IsReferableQuery;\r
13 import org.simantics.databoard.binding.util.Result;\r
14 import org.simantics.databoard.serialization.SerializationException;\r
15 import org.simantics.databoard.serialization.Serializer;\r
16 import org.simantics.databoard.serialization.Serializer.CompositeSerializer;\r
17 import org.simantics.databoard.type.UnionType;\r
18 import org.simantics.databoard.util.binary.Endian;\r
19 \r
20 public class UnionSerializer extends CompositeSerializer {\r
21 \r
22         UnionBinding binding;\r
23         public Serializer[] componentSerializers;\r
24         int tagTypeCount;\r
25         Integer fixedSize;\r
26         int minSize;\r
27         \r
28         /**\r
29          * \r
30          * @param binding\r
31          * @param componentSerializers (optional) can be set later\r
32          */\r
33         public UnionSerializer(UnionBinding binding, Serializer[] componentSerializers)                         \r
34         {\r
35                 super( IsReferableQuery.isReferable( binding.type() ) != Result.No );\r
36                 tagTypeCount = ((UnionType) binding.type()).components.length;\r
37                 this.binding = binding;\r
38                 this.componentSerializers = componentSerializers;\r
39         }\r
40         \r
41         @Override\r
42         public void finalizeConstruction() {\r
43                 // Calculate Fixed Size\r
44                 for (Serializer s : componentSerializers)\r
45                 {\r
46                         Integer fixedSizeOfComponentSerializer = s.getConstantSize();\r
47                         if (fixedSizeOfComponentSerializer==null) {\r
48                                 fixedSize = null;\r
49                                 break;\r
50                         }\r
51                         if (fixedSize!=null && fixedSizeOfComponentSerializer!=fixedSize) {\r
52                                 fixedSize = null;\r
53                                 break;\r
54                         }\r
55                         fixedSize = fixedSizeOfComponentSerializer;\r
56                 }\r
57                 if (componentSerializers.length == 0) fixedSize = 0;\r
58                 if (fixedSize!=null) fixedSize += Endian.getUIntLength(tagTypeCount-1);\r
59                 \r
60                 if (componentSerializers.length>0) {\r
61                         minSize = Integer.MAX_VALUE;\r
62                         for (Serializer s : componentSerializers) minSize = Math.min(minSize, s.getMinSize());\r
63                         minSize += Endian.getUIntLength( tagTypeCount-1 );\r
64                 }\r
65                         \r
66         }\r
67 \r
68         @Override\r
69         public Object deserialize(DataInput in, List<Object> identities) throws IOException {\r
70                 try {\r
71                         int tag = Endian.getUInt(in, tagTypeCount-1);\r
72                         return binding.create(tag, componentSerializers[tag].deserialize(in, identities));\r
73                 } catch (BindingException e) {\r
74                         throw new IOException( e ); \r
75                 }\r
76         }\r
77         \r
78         public Object deserializeToTry(DataInput in, List<Object> identities, Object dst) throws IOException \r
79         {\r
80                 if (binding.isTagMutable()) {\r
81                         return deserialize(in, identities);\r
82                 } else {\r
83                         deserializeTo(in, identities, dst);\r
84                         return dst;                             \r
85                 }\r
86         }\r
87                 \r
88         \r
89         @Override\r
90         public void deserializeTo(DataInput in, List<Object> identities, Object obj) throws IOException {\r
91                 try {\r
92                         int tag = Endian.getUInt(in, tagTypeCount-1);\r
93                         int oldTag = binding.getTag(obj);\r
94                         Serializer cs = componentSerializers[tag];\r
95                         boolean csImmutable = binding.getComponentBinding(tag).isImmutable();\r
96                         \r
97                         if (oldTag==tag && !csImmutable) {\r
98                                 Object component = binding.getValue(obj);\r
99                                 component = componentSerializers[tag].deserializeToTry(in, identities, component);\r
100                                 binding.setValue(obj, tag, component);\r
101                         } else {\r
102                                 Object component = cs.deserialize(in, identities);\r
103                                 binding.setValue(obj, tag, component);\r
104                         }\r
105                 } catch (BindingException e) {\r
106                         throw new IOException( e ); \r
107                 }\r
108         }\r
109 \r
110         @Override\r
111         public void skip(DataInput in, List<Object> identities) throws IOException, SerializationException {\r
112                 int tag = Endian.getUInt(in, tagTypeCount-1);\r
113                 componentSerializers[tag].skip(in, identities);\r
114         }\r
115         \r
116         @Override\r
117         public void serialize(DataOutput out, TObjectIntHashMap<Object> identities, Object obj) throws IOException {\r
118                 try {\r
119                         int tag = binding.getTag(obj);\r
120                         Endian.putUInt(out, tag, tagTypeCount-1);\r
121                         componentSerializers[tag].serialize(out, identities, binding.getValue(obj));\r
122                 } catch (BindingException e) {\r
123                         throw new IOException( e ); \r
124                 }\r
125         }\r
126 \r
127         @Override\r
128         public Integer getConstantSize() {\r
129                 return fixedSize;\r
130         }\r
131 \r
132         @Override\r
133         public int getSize(Object obj, TObjectIntHashMap<Object> identities) throws IOException {\r
134                 try {\r
135                         if (fixedSize!=null) return fixedSize;\r
136                         int tag = binding.getTag(obj);\r
137                         return Endian.getUIntLength( tagTypeCount-1 ) +\r
138                                 componentSerializers[tag].getSize(binding.getValue(obj), identities);\r
139                 } catch (BindingException e) {\r
140                         throw new IOException( e ); \r
141                 }\r
142         }\r
143         \r
144         @Override\r
145         public int getMinSize() {\r
146                 return minSize;\r
147         }\r
148 \r
149         \r
150 }\r