(De)Serializing interfaces

Rikki Cattermole via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Sun Aug 23 04:40:49 PDT 2015


On Sunday, 23 August 2015 at 10:37:11 UTC, Rikki Cattermole wrote:
> On 8/23/2015 10:17 PM, nims wrote:
>> On Sunday, 23 August 2015 at 08:38:14 UTC, Rikki Cattermole 
>> wrote:
>>> What I was thinking was having a serialize method take an 
>>> output range
>>> which you will just pass in a value.
>> I'm not really sure what you mean. Replacing the operator by a 
>> range
>> function or serializing everything automatically?
>
> Oh not quite. Humm, how to explain this.
>
> import std.traits : isBasicType, isArray;
>
> interface Serializable {
> 	void serialize(OutputRange!ubyte);
> 	void deserialize(InputRange!ubyte);
>
> 	final void putValue(T)(OutputRange!ubyte output, ref T value) {
> 		static if (isArray!T) {
> 			putValue(output, value.length);
> 			foreach(v; value)
> 				putValue(v);
> 		} else static if (isBasicType!T) {
> 			// convert to ubytes ext. ext. and call put on output.
> 		} else if (Serializable sv = cast(Serializable)value) {
> 			sv.serialize(output);
> 		} else {
> 			static assert(0, "I don't know how to handle this");
> 		}
> 	}
>
> 	final T getValue(T)(InputRange!ubyte input) {
> 		ubyte[T.sizeof] ret;
> 		foreach(i; 0 .. T.sizeof)
> 			ret[i] = input.moveFront;
> 		return to!T(ret);
> 	}
> }
>
> class ... : Serializable {
> 	int x, y;
> 	float z;
>
> 	void serialize(OutputRange!ubyte output) {
> 		output.putValue(x);
> 		output.putValue(y);
> 		output.putValue(z);
>     	}
>
> 	void deserialize(InputRange!ubyte input) {
> 		x = input.getValue!int;
> 		y = input.getValue!int;
> 		z = input.getValue!float;
> 	}
> }
>
>>> A hash? Yeah, TypeInfo_Class should. It will take a pointer.
>>> https://github.com/D-Programming-Language/druntime/blob/master/src/object.d#L261
>>>
>>>
>>> size_t hash = typeid(avalue).getHash(&avalue);
>>>
>>> But keep in mind avalue must be an rvalue.
>> Sounds good! How do I then create an instance having the same 
>> type?
>
> The hash value won't help you much really. It's meant for 
> comparing instances.
>
>>> My suggestion would be evaluate the type "down" aka get
>>> immutable(char) from immutable(char)[] aka string. So don't 
>>> try to
>>> serialize the string straight. Grab the length put that to 
>>> the output
>>> range, then try to serialize each of the values of the array
>>> individually as another function call to itself.
>>>
>>> Same sort of deal with other classes, check that they have the
>>> interface and if so, call it's serialize method with yourself.
>>>
>>> A little confusing I must admit.
>> I'm sorry I didn't get that. Would you have a piece of code for
>> illustration?
>
> Take a look at the top code snippet.
> You will probably want a couple of free functions be the 
> function you call to serialize and deserialize. That way it can 
> control embedding e.g. the class name as the first set of 
> values. Which is trivial to use with the help of e.g. 
> Object.factory or with the help of TypeInfo.init.
>
> On that note I'll see about getting you a snippet of code that 
> may interest you here.
> If you can please come on[0] to make it slightly easier for me.
>
> [0] https://gitter.im/rikkimax/chatWithMe

Short summary of code snippets:

~~~~~~~~~~~~~~~~~~~
module dnetdev.webserver.common.classfinder;

Interface findAndCreateClass(Interface)(string name) if 
(is(Interface == class) || is(Interface == interface)) {
     import std.experimental.allocator;
     auto alloc = theAllocator();

     auto classinfo = TypeInfo_Class.find(name);
     if (classinfo is null)
         return null;

     size_t issize = classinfo.init.length;
     void[] dataallocated = alloc.allocate(issize);

     Object obj;
     dataallocated[] = cast(void[])classinfo.init[];
     if (dataallocated is null)
         return null;

     obj = cast(Object)dataallocated.ptr;

     if (obj !is null) {
         if (classinfo.defaultConstructor !is null)
             (cast(void 
function(Object))classinfo.defaultConstructor)(obj);

         if (Interface obj2 = cast(Interface)obj) {
             return obj2;
         } else {
             alloc.dispose(obj);
             return null;
         }
     } else {
         alloc.dispose(dataallocated);
         return null;
     }
}
~~~~~~~~~~~~~~~~~~~

~~~~~~~~~~~~~~~~~~~
void main() {
     int x;
     foo!x(x);
}

void foo(alias T)(typeof(T) v) {
     pragma(msg, T.stringof);
}
~~~~~~~~~~~~~~~~~~~~

~~~~~~~~~~~~~~~~~~~~
import std.stdio;

interface Foo {
     final void func(this T)(/* output */) {
         writeln(T.stringof);
         foreach(v; __traits(allMembers, T))
             writeln(v);
     }
}

class Bar : Foo {
     int x;
}

void main() {
     Bar b = new Bar;
     b.func();
}
~~~~~~~~~~~~~~~~~~~~~


More information about the Digitalmars-d-learn mailing list