1 /**
2  * Copyright: Copyright (c) 2010-2011 Jacob Carlborg.
3  * Authors: Jacob Carlborg
4  * Version: Initial created: Jan 26, 2010
5  * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
6  */
7 module mambo.serialization.Serializable;
8 
9 import mambo.core._;
10 import mambo.serialization.archives.Archive;
11 import mambo.serialization.Events;
12 import mambo.serialization.Serializer;
13 import mambo.util.Ctfe;
14 
15 /**
16  * This interface represents a type that this is serializable. To implement this interface
17  * the user needs to implement two methods, one for serialization and one for
18  * deserialization. These methods are used to perform custom (de)serialization and will
19  * be called if available. It's up to these methods to call the serializer to perform
20  * the (de)serialization. If these methods are available the automatic (de)serialization
21  * process $(I will not) be performed.
22  *
23  * These methods can also be used without actually implementing this interface, i.e. they
24  * also work for structs.
25  *
26  * Examples:
27  * ---
28  * class Foo : Serializable
29  * {
30  * 	int a;
31  *
32  * 	void toData (Serializer serializer, Serializer.Data key)
33  * 	{
34  * 		serializer.serialize(a, "b");
35  * 	}
36  *
37  *  void fromData (Serializer serializer, Serializer.Data key)
38  *  {
39  *  	a = serializer.deserialize!(int)("b");
40  *  }
41  * }
42  * ---
43  *
44  * See_Also: isSerializable
45  */
46 interface Serializable
47 {
48 	/**
49 	 * Called by the given serializer when performing custom serialization.
50 	 *
51 	 * Params:
52 	 *     serializer = the serializer that performs the serialization
53 	 *     key = the key of the receiver
54 	 */
55 	void toData (Serializer serializer, Serializer.Data key);
56 
57 	/**
58 	 * Called by the given serializer when performing custom deserialization.
59 	 *
60 	 * Params:
61 	 *     serializer = the serializer that performs the deserialization
62 	 *     key = the key of the receiver
63 	 */
64 	void fromData (Serializer serializer, Serializer.Data key);
65 }
66 
67 /**
68  * This interface represents a type that this is serializable. To implement this interface
69  * Evaluates to $(D_KEYWORD true) if the given type is serializable. A type is considered
70  * serializable when it implements to two methods in the Serializable interface.
71  * Note that the type does not have to implement the actual interface, i.e. it also works
72  * for structs.
73  *
74  * Examples:
75  * ---
76  * struct Foo
77  * {
78  * 	int a;
79  *
80  * 	void toData (Serializer serializer, Serializer.Data key)
81  * 	{
82  * 		serializer.serialize(a, "b");
83  * 	}
84  *
85  *  void fromData (Serializer serializer, Serializer.Data key)
86  *  {
87  *  	a = serializer.deserialize!(int)("b");
88  *  }
89  * }
90  *
91  * static assert(isSerializable!(Foo));
92  * ---
93  *
94  * See_Also: Serializable
95  */
96 template isSerializable (T)
97 {
98 	const isSerializable = is(T : Serializable) || (
99 		is(typeof(T.toData(Serializer.init, Serializer.Data.init))) &&
100 		is(typeof(T.fromData(Serializer.init, Serializer.Data.init))));
101 }
102 
103 /**
104  * This template is used to indicate that one or several fields should not be
105  * (de)serialized. If no fields or "this" is specified, it indicates that the whole
106  * class/struct should not be (de)serialized.
107  *
108  * This template is used as a mixin.
109  *
110  * Examples:
111  * ---
112  * class Foo
113  * {
114  * 	int a;
115  * 	int b;
116  *
117  * 	mixin NonSerialized!(b); // "b" will not be (de)serialized
118  * }
119  *
120  * struct Bar
121  * {
122  * 	int a;
123  * 	int b;
124  *
125  * 	mixin NonSerialized; // "Bar" will not be (de)serialized
126  * }
127  * ---
128  */
129 template NonSerialized (Fields ...)
130 {
131 	static if (Fields.length == 0)
132 		static enum __nonSerialized = ["this"[]];
133 
134 	else
135 		static enum __nonSerialized = mambo.serialization.Serializable.toArray!(Fields)();
136 }
137 
138 /// Indicates that the declaration this attribute is attached to should not be (de)serialized.
139 @attribute struct nonSerialized { }
140 
141 /**
142  *
143  * Authors: doob
144  */
145 struct NonSerializedField (string name)
146 {
147 	const field = name;
148 }
149 
150 /**
151  * Converts a tuple of aliases to an array of strings containing the names of the given
152  * aliases.
153  *
154  * Examples:
155  * ---
156  * int a;
157  * int b;
158  *
159  * const names = toArray!(a, b);
160  *
161  * static assert(names == ["a", "b"]);
162  * ---
163  *
164  * Returns: an array containing the names of the given aliases
165  */
166 template toArray (Args ...)
167 {
168 	static string[] toArray ()
169 	{
170 		string[] args;
171 
172 		foreach (i, _ ; typeof(Args))
173 			args ~= Args[i].stringof;
174 
175 		return args;
176 	}
177 }
178 
179 package:
180 
181 enum nonSerializedField = "__nonSerialized";
182 enum serializedField = "__serialized";
183 enum internalFields = [nonSerializedField[], onDeserializedField, onDeserializingField, onSerializedField, onSerializingField];