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