--- /dev/null
+package org.simantics.databoard.serialization.impl;\r
+\r
+import gnu.trove.map.hash.TObjectIntHashMap;\r
+\r
+import java.io.DataInput;\r
+import java.io.DataOutput;\r
+import java.io.IOException;\r
+import java.util.List;\r
+\r
+import org.simantics.databoard.binding.OptionalBinding;\r
+import org.simantics.databoard.binding.error.BindingException;\r
+import org.simantics.databoard.binding.util.IsReferableQuery;\r
+import org.simantics.databoard.binding.util.Result;\r
+import org.simantics.databoard.serialization.SerializationException;\r
+import org.simantics.databoard.serialization.Serializer;\r
+import org.simantics.databoard.serialization.Serializer.CompositeSerializer;\r
+\r
+public class OptionalSerializer extends CompositeSerializer {\r
+\r
+ OptionalBinding binding;\r
+ public Serializer componentSerializer; \r
+ boolean componentImmutable; \r
+ Integer fixedSize;\r
+ \r
+ /**\r
+ * Create optional serializer\r
+ * \r
+ * @param binding\r
+ * @param componentSerializer (optional), can be set after\r
+ */\r
+ public OptionalSerializer(OptionalBinding binding, Serializer componentSerializer) {\r
+ super( IsReferableQuery.isReferable( binding.type() ) != Result.No );\r
+ this.componentSerializer = componentSerializer;\r
+ this.binding = binding;\r
+ this.componentImmutable = binding.getComponentBinding().isImmutable(); \r
+ }\r
+ \r
+ @Override\r
+ public void finalizeConstruction() {\r
+ Integer fixedSizeOfComponent = componentSerializer.getConstantSize();\r
+ if (fixedSizeOfComponent!=null && fixedSizeOfComponent==0) {\r
+ fixedSize = fixedSizeOfComponent + 1;\r
+ }\r
+ }\r
+\r
+ @Override\r
+ public Object deserialize(DataInput in, List<Object> identities) throws IOException {\r
+ try {\r
+ byte x = in.readByte();\r
+ if (x == 0) return binding.createNoValue();\r
+ else if (x == 1) {\r
+ Object componentValue = componentSerializer.deserialize(in, identities);\r
+ return binding.createValue(componentValue);\r
+ }\r
+ else throw new SerializationException("Unexpected marker for option "+x+" 0 or 1 expected.");\r
+ } catch (BindingException e) {\r
+ throw new IOException( e ); \r
+ }\r
+ }\r
+ \r
+ @Override\r
+ public void deserializeTo(DataInput in, List<Object> identities,\r
+ Object obj) throws IOException {\r
+ try {\r
+ byte x = in.readByte();\r
+ if (x == 0) {\r
+ if (binding.hasValue(obj)) binding.setNoValue(obj);\r
+ } else if (x == 1) {\r
+ if (componentImmutable) {\r
+ Object component = componentSerializer.deserialize(in, identities);\r
+ binding.setValue(obj, component);\r
+ } else {\r
+ Object component = binding.hasValue(obj) ? binding.getValue(obj) : binding.componentBinding.createDefault();\r
+ component = componentSerializer.deserializeToTry(in, identities, component);\r
+ binding.setValue(obj, component);\r
+ }\r
+ \r
+ }\r
+ else throw new SerializationException("Unexpected marker for option "+x+" 0 or 1 expected.");\r
+ } catch (BindingException e) {\r
+ throw new IOException( e ); \r
+ }\r
+ }\r
+\r
+ @Override\r
+ public void skip(DataInput in, List<Object> identities) throws IOException, SerializationException {\r
+ int x = in.readByte();\r
+ if (x==1) componentSerializer.skip(in, identities);\r
+ }\r
+ \r
+ @Override\r
+ public void serialize(DataOutput out, TObjectIntHashMap<Object> identities, Object obj) throws IOException {\r
+ try {\r
+ if (!binding.hasValue(obj)) {\r
+ out.write((byte)0);\r
+ } else {\r
+ out.write((byte)1);\r
+ Object componentValue = binding.getValue(obj);\r
+ componentSerializer.serialize(out, identities, componentValue);\r
+ }\r
+ } catch (BindingException e) {\r
+ throw new IOException( e ); \r
+ }\r
+ \r
+ }\r
+\r
+ @Override\r
+ public Integer getConstantSize() {\r
+ return fixedSize;\r
+ }\r
+\r
+ @Override\r
+ public int getSize(Object obj, TObjectIntHashMap<Object> identities) throws IOException {\r
+ try {\r
+ if (fixedSize!=null) return fixedSize;\r
+ if (!binding.hasValue(obj)) return 1;\r
+ Object componentValue = binding.getValue(obj);\r
+ return 1 + componentSerializer.getSize(componentValue, identities);\r
+ } catch (BindingException e) {\r
+ throw new IOException( e ); \r
+ } \r
+ }\r
+ \r
+ @Override\r
+ public int getMinSize() {\r
+ return 1;\r
+ }\r
+ \r
+} \r