1 /** 2 Serialization Interface 3 4 Interfaces for creating classes which may be serialized and deserialized. 5 6 Copyright: 7 Copyright © 2023-2025, Kitsunebi Games 8 Copyright © 2023-2025, Inochi2D Project 9 10 License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 11 Authors: Luna Nielsen 12 */ 13 module nulib.io.serialize; 14 import nulib.string; 15 import numem; 16 17 /** 18 Interface a class may implement to indicate it can be serialized. 19 */ 20 interface ISerializable { 21 @nogc: 22 23 /** 24 Called on the object to serialize it using the 25 given (de)serializer. 26 27 Params: 28 serde = the (de)serializer to use. 29 */ 30 void serialize(ref Serde serde); 31 } 32 33 /** 34 Gets whether the type can be serialized using an 35 elaborate serializer function. 36 */ 37 enum hasElaborateSerializer(T) = 38 is(T : ISerializable) || 39 is(typeof((ref Serde serde) { auto t = T.init; t.serialize(serde); })); 40 41 /** 42 Interface a class may implement to indicate it can be deserialized. 43 */ 44 interface IDeserializable { 45 @nogc: 46 47 /** 48 Called on the object to deserialize it using the 49 given (de)serializer. 50 51 Params: 52 serde = the (de)serializer to use. 53 */ 54 void deserialize(ref Serde serde); 55 } 56 57 /** 58 Gets whether the type can be deserialized using an 59 elaborate serializer function. 60 */ 61 enum hasElaborateDeserializer(T) = 62 is(T : IDeserializable) || 63 is(typeof((ref Serde serde) { auto t = T.init; t.deserialize(serde); })); 64 65 /** 66 A (de)serializer. 67 */ 68 abstract 69 class Serde : NuObject { 70 private: 71 @nogc: 72 SerdeContext ctx; 73 74 protected: 75 76 /** 77 Called when the serialization context is initialized. 78 */ 79 abstract SerdeContext onInit(); 80 81 /** 82 A serialization function which serializes a string. 83 84 Params: 85 value = The value to serialize. 86 */ 87 abstract void serializeString(string value); 88 89 /** 90 A serialization function which serializes a signed integer. 91 (max 64-bit) 92 93 Params: 94 value = The value to serialize, sign extended. 95 bytes = The actual amount of bytes to serialize. 96 */ 97 abstract void serializeInt(long value, ubyte bytes); 98 99 /** 100 A serialization function which serializes an unsigned 101 integer. (max 64-bit) 102 103 Params: 104 value = The value to serialize, sign extended. 105 bytes = The actual amount of bytes to serialize. 106 */ 107 abstract void serializeUInt(ulong value, ubyte bytes); 108 109 /** 110 A serialization function which serializes a floating 111 point number. (max 64-bit) 112 113 Params: 114 value = The value to serialize. 115 bytes = The actual amount of bytes to serialize. 116 */ 117 abstract void serializeFloat(double value, ubyte bytes); 118 119 /** 120 A deserialization function which deserializes a string. 121 122 Returns: 123 The deserialized value 124 */ 125 abstract nstring deserializeString(); 126 127 /** 128 A serialization function which serializes a signed integer. 129 (max 64-bit) 130 131 Params: 132 bytes = The amount of bytes to deserialize. 133 134 Returns: 135 The deserialized value 136 */ 137 abstract long deserializeInt(ubyte bytes); 138 139 /** 140 A serialization function which serializes an unsigned 141 integer. (max 64-bit) 142 143 Params: 144 bytes = The amount of bytes to deserialize. 145 146 Returns: 147 The deserialized value 148 */ 149 abstract ulong deserializeUInt(ubyte bytes); 150 151 /** 152 A serialization function which serializes a floating 153 point number. (max 64-bit) 154 155 Params: 156 bytes = The amount of bytes to deserialize. 157 158 Returns: 159 The deserialized value 160 */ 161 abstract double deserializeFloat(ubyte bytes); 162 163 /** 164 Begins a complex serialization context. 165 */ 166 abstract SerdeContext beginComplexContext(); 167 168 /** 169 Ends a complex serde context. 170 */ 171 abstract void endComplexContext(SerdeContext ctx); 172 173 public: 174 175 // Destructor 176 ~this() { nogc_delete(ctx); } 177 178 /** 179 Constructs a Serde object. 180 */ 181 this() { 182 ctx = this.onInit(); 183 } 184 185 /** 186 The name of the format that the (de)serializer 187 supports. 188 */ 189 abstract @property string format(); 190 191 /** 192 The public serialization interface. 193 */ 194 void serialize(T)(auto ref T item) { 195 static if (is(T : string)) { 196 serializeString(item); 197 } else static if (__traits(isFloating, T)) { 198 serializeFloat(cast(double)item, T.sizeof); 199 } else static if (__traits(isIntegral, T) && __traits(isUnsigned, T)) { 200 serializeUInt(cast(ulong)item, T.sizeof); 201 } else static if (__traits(isIntegral, T) && !__traits(isUnsigned, T)) { 202 serializeInt(cast(ulong)item, T.sizeof); 203 } else static if (hasElaborateSerializer!T) { 204 Serde self = this; 205 item.serialize(self); 206 } static assert(0, "Can't serialize given type "~T.stringof~"."); 207 } 208 209 /** 210 The public deserialization interface. 211 */ 212 void deserialize(T)(auto ref T item) { 213 static if (is(T : string)) { 214 serializeString(item); 215 } else static if (__traits(isFloating, T)) { 216 serializeFloat(cast(double)item, T.sizeof); 217 } else static if (__traits(isIntegral, T) && __traits(isUnsigned, T)) { 218 serializeUInt(cast(ulong)item, T.sizeof); 219 } else static if (__traits(isIntegral, T) && !__traits(isUnsigned, T)) { 220 serializeInt(cast(ulong)item, T.sizeof); 221 } else static if (hasElaborateDeserializer!T) { 222 Serde self = this; 223 item.deserialize(self); 224 } static assert(0, "Can't deserialize given type "~T.stringof~"."); 225 } 226 } 227 228 /** 229 A context used during (de)serialization to traverse complex 230 nested serialization trees. 231 */ 232 abstract 233 class SerdeContext : NuObject { 234 private: 235 Serde owner_; 236 237 public: 238 @nogc: 239 240 /** 241 Constructor for a context. 242 */ 243 this(Serde owner) { this.owner_ = owner; } 244 245 /** 246 The owner object which created the context. 247 */ 248 final 249 @property Serde owner() { return owner_; } 250 251 /** 252 Begins an object within the context. 253 */ 254 abstract SerdeContext beginObject(); 255 256 /** 257 Ends an object within the context. 258 */ 259 abstract void endObject(SerdeContext object); 260 261 /** 262 Begins a data range within the context. 263 */ 264 abstract SerdeContext beginRange(); 265 266 /** 267 Ends a data range within the context. 268 */ 269 abstract void endRange(SerdeContext object); 270 }