1 /++ 2 $(H4 High level YAML serialization API) 3 4 Macros: 5 IONREF = $(REF_ALTTEXT $(TT $2), $2, mir, ion, $1)$(NBSP) 6 +/ 7 module mir.ser.yaml; 8 9 import mir.serde: SerdeTarget; 10 import mir.algebraic_alias.yaml: YamlAlgebraic; 11 12 /++ 13 YAML Serialization Params 14 +/ 15 struct YamlSerializationParams 16 { 17 import mir.algebraic_alias.yaml: YamlScalarStyle, YamlCollectionStyle; 18 19 /// Default style for scalar nodes. If style is $(D YamlScalarStyle.none), the _style is chosen automatically. 20 YamlScalarStyle defaultScalarStyle; 21 /// Default style for collection nodes. If style is $(D YamlCollectionStyle.none), the _style is chosen automatically. 22 YamlCollectionStyle defaultCollectionStyle; 23 /// Always explicitly write document start? Default is no explicit start. 24 bool explicitStart; 25 /// Always explicitly write document end? Default is no explicit end. 26 bool explicitEnd; 27 /// Write scalars in canonical form? 28 bool canonical; 29 /// Indentation width 30 ubyte indent = 2; 31 /// Preferred text width. 32 uint textWidth = 80; 33 /// YAML version string. Default value is null. 34 string yamlVersion; 35 } 36 37 /++ 38 Ion serialization function. 39 40 Params: 41 value = value to serializa 42 params = (optional) serialization param 43 serdeTarget = (optional) serialization target ID 44 Returns: 45 UTF-8 YAML text 46 +/ 47 @safe 48 string serializeYaml(V)(auto scope ref const V value, YamlSerializationParams params = YamlSerializationParams.init, int serdeTarget = SerdeTarget.yaml) 49 { 50 static if (is(V == YamlAlgebraic)) 51 { 52 alias node = value; 53 } 54 else 55 static if (is(typeof(const YamlAlgebraic(value)))) 56 { 57 scope node = const YamlAlgebraic(value); 58 } 59 else 60 static if (is(typeof(cast(const YamlAlgebraic) value))) 61 { 62 scope node = cast(const YamlAlgebraic) value; 63 } 64 else 65 { 66 import mir.ion.conv: serde; 67 auto node = serde!YamlAlgebraic(value, serdeTarget); 68 } 69 70 return serializeYamlValues((()@trusted=>(&node)[0 .. 1])(), params); 71 } 72 73 /// 74 @safe pure 75 unittest 76 { 77 import mir.test: should; 78 79 static struct S 80 { 81 string foo; 82 uint bar; 83 } 84 85 S("str", 4).serializeYaml.should == 86 `{foo: str, bar: 4} 87 `; 88 } 89 90 /// Tags (annotations) support 91 @safe pure 92 unittest 93 { 94 import mir.test: should; 95 import mir.algebraic: Variant; 96 import mir.serde: serdeAlgebraicAnnotation; 97 98 import mir.test: should; 99 import mir.algebraic: Variant; 100 import mir.serde: serdeAlgebraicAnnotation, serdeAnnotation, serdeOptional; 101 102 @serdeAlgebraicAnnotation("!S") 103 static struct S 104 { 105 string foo; 106 uint bar; 107 } 108 109 @serdeAlgebraicAnnotation("rgb") 110 static struct RGB 111 { 112 @serdeAnnotation @serdeOptional 113 string name; 114 115 ubyte r, g, b; 116 } 117 118 alias V = Variant!(S, RGB); 119 120 S("str", 4).serializeYaml.should == "{foo: str, bar: 4}\n"; 121 V("str", 4).serializeYaml.should == "!S {foo: str, bar: 4}\n"; 122 123 // Multiple Ion annotations represented in a single tag using `::`. 124 V(RGB("dark_blue", 23, 25, 55)).serializeYaml.should == 125 `!<rgb::dark_blue> {r: 23, g: 25, b: 55} 126 `; 127 } 128 129 /// YAML-specific serialization 130 @safe pure 131 unittest 132 { 133 import mir.algebraic_alias.yaml: YamlAlgebraic, YamlCollectionStyle; 134 import mir.test: should; 135 136 auto value = YamlAlgebraic(["foo".YamlAlgebraic, 123.9.YamlAlgebraic, "bar".YamlAlgebraic]); 137 138 value.serializeYaml.should == "[foo, 123.9, bar]\n"; 139 140 value.collectionStyle = YamlCollectionStyle.block; 141 value.serializeYaml.should == "- foo\n- 123.9\n- bar\n"; 142 } 143 144 /// User API for YAML-specific serialization 145 @safe pure 146 version(none) 147 unittest 148 { 149 import mir.algebraic_alias.yaml: YamlAlgebraic; 150 import mir.test: should; 151 152 static struct MyYamlStruct 153 { 154 int b; 155 156 // has to be scope const 157 auto opCast(T : YamlAlgebraic)() scope const @safe pure 158 { 159 return b.YamlAlgebraic; 160 } 161 } 162 163 MyYamlStruct(40).serializeYaml.should == "40\n"; 164 } 165 166 /++ 167 Params: 168 nodes = Algebraic nodes (documents) 169 params = (optional) serialization param 170 Returns: 171 UTF-8 YAML text 172 See_Also: 173 $(IONREF, conv, serde). 174 +/ 175 @safe pure 176 string serializeYamlValues(scope const YamlAlgebraic[] nodes, YamlSerializationParams params = YamlSerializationParams.init) 177 { 178 import mir.yaml.internal.dumper; 179 import std.array: appender; 180 181 auto app = appender!string; 182 auto dumper = dumper(params); 183 foreach (ref node; nodes) 184 dumper.dump(app, node); 185 return app.data; 186 }