1 /// Contains an archive for SDLang. 2 module jaster.serialise.sdlang; 3 4 private 5 { 6 import std.algorithm, std.format, std.exception, std.traits, std.utf; 7 import sdlang; 8 import jaster.serialise.archive; 9 } 10 11 /// An `Archive` for SDLang. 12 class ArchiveSDL : Archive 13 { 14 private 15 { 16 ArchiveObject _root; 17 } 18 19 public 20 { 21 void loadFromTag(Tag tag) 22 { 23 this._root = this.tagToObject(tag); 24 } 25 } 26 27 public override 28 { 29 const(ubyte[]) saveToMemory() 30 { 31 return cast(const(ubyte[]))this.objectToTag(this.root).toSDLDocument(); 32 } 33 34 void loadFromMemory(const ubyte[] data) 35 { 36 auto text = cast(string)data.idup; 37 validate(text); 38 39 auto tag = parseSource(text); 40 this._root = this.tagToObject(tag); 41 } 42 43 @property 44 ArchiveObject root() 45 { 46 if(this._root is null) 47 this._root = new ArchiveObject(); 48 49 return this._root; 50 } 51 } 52 53 // ########### 54 // # UTILITY # 55 // ########### 56 private 57 { 58 ArchiveObject tagToObject(Tag tag) 59 { 60 auto object = new ArchiveObject(tag.getFullName().toString); 61 62 foreach(value; tag.values) 63 object.addValues(this.sdlToArchive(value)); 64 65 foreach(attrib; tag.attributes) 66 object.setAttribute(attrib.name, this.sdlToArchive(attrib.value)[0]); 67 68 foreach(child; tag.all.tags) 69 object.addChild(this.tagToObject(child)); 70 71 return object; 72 } 73 74 ArchiveValue[] sdlToArchive(Value value) 75 { 76 ArchiveValue[] data; 77 78 static foreach(type; Value.AllowedTypes) 79 { 80 if(value.type == typeid(type)) 81 { 82 static if( 83 (isNumeric!type && !is(type == real)) 84 || is(type == ubyte[]) 85 || is(type == bool) 86 || is(type == typeof(null)) 87 || is(type == string)) 88 data ~= ArchiveValue(value.get!type); 89 else static if(is(type == Value[])) 90 { 91 foreach(v; value.get!(Value[])) 92 data ~= sdlToArchive(v); 93 } 94 else enforce(false, "Unsupported type: " ~ type.stringof); 95 } 96 } 97 98 return data; 99 } 100 101 Tag objectToTag(ArchiveObject object) 102 { 103 Tag tag = new Tag(); 104 tag.name = object.name; 105 106 foreach(value; object.values) 107 tag.add(this.archiveToSdl(value)); 108 109 foreach(attrib; object.attributes) 110 { 111 auto values = this.archiveToSdl(attrib.value); 112 113 enforce(values.length == 1, "Attributes cannot be arrays."); 114 tag.add(new Attribute(attrib.name, values[0])); 115 } 116 117 foreach(child; object.children) 118 tag.add(this.objectToTag(child)); 119 120 return tag; 121 } 122 123 Value[] archiveToSdl(ArchiveValue value) 124 { 125 Value[] data; 126 127 static foreach(type; ArchiveValue.AllowedTypes) 128 { 129 if(value.type == typeid(type)) 130 { 131 static if(isNumeric!type && !isFloatingPoint!type) 132 data ~= Value(value.coerce!long); 133 else static if(isNumeric!type && isFloatingPoint!type) 134 data ~= Value(value.coerce!double); 135 else static if(is(type == ubyte[]) || is(type == bool) || is(type == typeof(null)) || is(type == string)) 136 data ~= Value(value.get!type); 137 else static if(is(type == ArchiveValue[])) 138 { 139 foreach(v; value.get!(ArchiveValue[])) 140 data ~= archiveToSdl(v); 141 } 142 else static assert(false, "Unsupported type: " ~ type.stringof); 143 } 144 } 145 146 return data; 147 } 148 } 149 }