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 orange.serialization.Serializable;
8 
9 import orange.core.Attribute;
10 import orange.serialization.archives.Archive;
11 import orange.serialization.Events;
12 import orange.serialization.Serializer;
13 import orange.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     enum 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 = 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 struct NonSerializedField (string name)
142 {
143     enum field = name;
144 }
145 
146 /*
147  * Converts a tuple of aliases to an array of strings containing the names of the given
148  * aliases.
149  *
150  * Examples:
151  * ---
152  * int a;
153  * int b;
154  *
155  * enum names = toArray!(a, b);
156  *
157  * static assert(names == ["a", "b"]);
158  * ---
159  *
160  * Returns: an array containing the names of the given aliases
161  */
162 template toArray (Args ...)
163 {
164     static string[] toArray ()
165     {
166         string[] args;
167 
168         foreach (i, _ ; typeof(Args))
169             args ~= Args[i].stringof;
170 
171         return args;
172     }
173 }
174 
175 package:
176 
177 enum nonSerializedField = "__nonSerialized";
178 enum serializedField = "__serialized";
179 enum internalFields = [nonSerializedField[], onDeserializedField, onDeserializingField, onSerializedField, onSerializingField];