diff --git a/pvDataApp/factory/FieldCreateFactory.cpp b/pvDataApp/factory/FieldCreateFactory.cpp index 5152067..99fcadd 100644 --- a/pvDataApp/factory/FieldCreateFactory.cpp +++ b/pvDataApp/factory/FieldCreateFactory.cpp @@ -13,6 +13,7 @@ #include #include #include +#include using std::tr1::static_pointer_cast; @@ -61,6 +62,53 @@ void Scalar::toString(StringBuilder buffer,int indentLevel) const{ Field::toString(buffer,indentLevel); } +void Scalar::serialize(ByteBuffer *buffer, SerializableControl *control) const { + control->ensureBuffer(1); + buffer->putByte((int8)(epics::pvData::scalar << 4 | getScalarType())); + SerializeHelper::serializeString(getFieldName(), buffer, control); +} + +void Scalar::deserialize(ByteBuffer *buffer, DeserializableControl *control) { +} + + + +static void serializeStructureField(const Structure* structure, ByteBuffer* buffer, SerializableControl* control) +{ + SerializeHelper::serializeString(structure->getFieldName(), buffer, control); + FieldConstPtrArray fields = structure->getFields(); + SerializeHelper::writeSize(structure->getNumberFields(), buffer, control); + for (int i = 0; i < structure->getNumberFields(); i++) + { + control->cachedSerialize(fields[i], buffer); + } +} + +static StructureConstPtr deserializeStructureField(const FieldCreate* fieldCreate, ByteBuffer* buffer, DeserializableControl* control) +{ + const String structureFieldName = SerializeHelper::deserializeString(buffer, control); + const int32 size = SerializeHelper::readSize(buffer, control); + FieldConstPtrArray fields = NULL; + if (size > 0) + { + fields = new FieldConstPtr[size]; + for(int i = 0; i < size; i++) + { + try { + fields[i] = control->cachedDeserialize(buffer); + } catch (...) { + delete[] fields; + throw; + } + } + } + + StructureConstPtr structure = fieldCreate->createStructure(structureFieldName, size, fields); + return structure; +} + + + ScalarArray::ScalarArray(String fieldName,ScalarType elementType) : Field(fieldName,scalarArray),elementType(elementType){} @@ -73,6 +121,15 @@ void ScalarArray::toString(StringBuilder buffer,int indentLevel) const{ Field::toString(buffer,indentLevel); } +void ScalarArray::serialize(ByteBuffer *buffer, SerializableControl *control) const { + control->ensureBuffer(1); + buffer->putByte((int8)(epics::pvData::scalarArray << 4 | getElementType())); + SerializeHelper::serializeString(getFieldName(), buffer, control); +} + +void ScalarArray::deserialize(ByteBuffer *buffer, DeserializableControl *control) { +} + StructureArray::StructureArray(String fieldName,StructureConstPtr structure) : Field(fieldName,structureArray),pstructure(structure) { @@ -89,6 +146,17 @@ void StructureArray::toString(StringBuilder buffer,int indentLevel) const { pstructure->toString(buffer,indentLevel + 1); } +void StructureArray::serialize(ByteBuffer *buffer, SerializableControl *control) const { + control->ensureBuffer(1); + buffer->putByte((int8)(epics::pvData::structureArray << 4)); + SerializeHelper::serializeString(getFieldName(), buffer, control); + // we also need to serialize structure field... + serializeStructureField(getStructure().get(), buffer, control); +} + +void StructureArray::deserialize(ByteBuffer *buffer, DeserializableControl *control) { +} + Structure::Structure (String fieldName, int numberFields, FieldConstPtrArray infields) @@ -186,6 +254,14 @@ void Structure::toString(StringBuilder buffer,int indentLevel) const{ } } +void Structure::serialize(ByteBuffer *buffer, SerializableControl *control) const { + control->ensureBuffer(1); + buffer->putByte((int8)(epics::pvData::structure << 4)); + serializeStructureField(this, buffer, control); +} + +void Structure::deserialize(ByteBuffer *buffer, DeserializableControl *control) { +} ScalarConstPtr FieldCreate::createScalar(String fieldName, ScalarType scalarType) const @@ -243,6 +319,45 @@ FieldConstPtr FieldCreate::create(String fieldName, THROW_EXCEPTION2(std::logic_error, message); } +FieldConstPtr FieldCreate::deserialize(ByteBuffer* buffer, DeserializableControl* control) const +{ + control->ensureData(1); + const int8 typeCode = buffer->getByte(); + + // high nibble means scalar/array/structure + const Type type = (Type)(typeCode >> 4); + switch (type) + { + case scalar: + { + const ScalarType scalar = (ScalarType)(typeCode & 0x0F); + const String scalarFieldName = SerializeHelper::deserializeString(buffer, control); + return static_cast(createScalar(scalarFieldName,scalar)); + } + case scalarArray: + { + const ScalarType element = (ScalarType)(typeCode & 0x0F); + const String arrayFieldName = SerializeHelper::deserializeString(buffer, control); + return static_cast(createScalarArray(arrayFieldName,element)); + } + case structure: + { + return static_cast(deserializeStructureField(this, buffer, control)); + } + case structureArray: + { + const String structureArrayFieldName = SerializeHelper::deserializeString(buffer, control); + const StructureConstPtr arrayElement = deserializeStructureField(this, buffer, control); + return static_cast(createStructureArray(structureArrayFieldName, arrayElement)); + } + default: + { + // TODO log + return FieldConstPtr(); + } + } +} + static FieldCreate* fieldCreate = 0; FieldCreate::FieldCreate() diff --git a/pvDataApp/misc/serialize.h b/pvDataApp/misc/serialize.h index a0d5fc9..0c3cc82 100644 --- a/pvDataApp/misc/serialize.h +++ b/pvDataApp/misc/serialize.h @@ -7,6 +7,7 @@ #ifndef SERIALIZE_H #define SERIALIZE_H #include +#include namespace epics { namespace pvData { class SerializableControl; @@ -15,6 +16,7 @@ namespace epics { namespace pvData { class BitSetSerializable; class SerializableArray; class BitSet; + class Field; class SerializableControl { public: @@ -22,6 +24,7 @@ namespace epics { namespace pvData { virtual void flushSerializeBuffer() =0; virtual void ensureBuffer(int size) =0; virtual void alignBuffer(int alignment) =0; + virtual void cachedSerialize(std::tr1::shared_ptr const & field, ByteBuffer* buffer) = 0; }; class DeserializableControl { @@ -29,6 +32,7 @@ namespace epics { namespace pvData { virtual ~DeserializableControl(){} virtual void ensureData(int size) =0; virtual void alignData(int alignment) =0; + virtual std::tr1::shared_ptr cachedDeserialize(ByteBuffer* buffer) = 0; }; class Serializable { diff --git a/pvDataApp/pv/pvIntrospect.h b/pvDataApp/pv/pvIntrospect.h index 369b562..006f4dd 100644 --- a/pvDataApp/pv/pvIntrospect.h +++ b/pvDataApp/pv/pvIntrospect.h @@ -13,6 +13,9 @@ #include #include #include +#include +#include + namespace epics { namespace pvData { class Field; @@ -170,7 +173,9 @@ namespace ScalarTypeFunc { /** * This class implements introspection object for field. */ -class Field : public std::tr1::enable_shared_from_this { +class Field : + virtual public Serializable, + public std::tr1::enable_shared_from_this { public: POINTER_DEFINITIONS(Field); /** @@ -254,6 +259,10 @@ public: * @param indentLevel The number of blanks at the beginning of new lines. */ virtual void toString(StringBuilder buf,int indentLevel) const; + + virtual void serialize(ByteBuffer *buffer, SerializableControl *flusher) const; + virtual void deserialize(ByteBuffer *buffer, DeserializableControl *flusher); + protected: Scalar(String fieldName,ScalarType scalarType); private: @@ -287,6 +296,10 @@ public: * @param indentLevel The number of blanks at the beginning of new lines. */ virtual void toString(StringBuilder buf,int indentLevel) const; + + virtual void serialize(ByteBuffer *buffer, SerializableControl *flusher) const; + virtual void deserialize(ByteBuffer *buffer, DeserializableControl *flusher); + protected: /** * Destructor. @@ -319,6 +332,10 @@ public: * @param indentLevel The number of blanks at the beginning of new lines. */ virtual void toString(StringBuilder buf,int indentLevel=0) const; + + virtual void serialize(ByteBuffer *buffer, SerializableControl *flusher) const; + virtual void deserialize(ByteBuffer *buffer, DeserializableControl *flusher); + protected: /** * Constructor. @@ -398,6 +415,10 @@ public: * @param indentLevel The number of blanks at the beginning of new lines. */ virtual void toString(StringBuilder buf,int indentLevel) const; + + virtual void serialize(ByteBuffer *buffer, SerializableControl *flusher) const; + virtual void deserialize(ByteBuffer *buffer, DeserializableControl *flusher); + protected: Structure(String fieldName, int numberFields,FieldConstPtrArray fields); private: @@ -450,6 +471,15 @@ public: */ StructureArrayConstPtr createStructureArray(String fieldName, StructureConstPtr structure) const; + + /** + * Deserialize {@code Field} instance from given byte buffer. + * @param buffer Buffer containing serialized {@code Field} instance. + * @param control Deserialization control instance. + * @return a deserialized {@code Field} instance. + */ + FieldConstPtr deserialize(ByteBuffer* buffer, DeserializableControl* control) const; + private: FieldCreate(); friend FieldCreate * getFieldCreate(); diff --git a/testApp/misc/testSerialization.cpp b/testApp/misc/testSerialization.cpp index d4309d2..d8515db 100644 --- a/testApp/misc/testSerialization.cpp +++ b/testApp/misc/testSerialization.cpp @@ -55,6 +55,11 @@ public: virtual void alignBuffer(int alignment) { buffer->align(alignment); } + + virtual void cachedSerialize(std::tr1::shared_ptr const & field, ByteBuffer* buffer) + { + field->serialize(buffer, this); + } SerializableControlImpl() { } @@ -73,6 +78,11 @@ public: buffer->align(alignment); } + virtual std::tr1::shared_ptr cachedDeserialize(ByteBuffer* buffer) + { + return getFieldCreate()->deserialize(buffer, this); + } + DeserializableControlImpl() { }