<<
path:
root/public/blog.git/html/modules/osor_serialization/example.jai
blob: 0c442e9ec1300f7fcd9bdaf8c6e1e0d75fc33268
[raw]
[clear marker]
4#import,dir "../osor_serialization";
10 set_my_print_format();
13 more_types_and_to_a_file();
14 how_about_compile_time();
22 print_example_name("A simple example");
24 Test :: struct { a : int; }
27 // Set up some simple data that we want to transform to an array of bytes
30 original_test.a = 123;
31 print("Original: %\n", original_test);
34 // This transform the data to an array of bytes that we can recover later.
36 // It allocates a single time with a single call to alloc() so you could use a
37 // different allocator by changing context.allocator.
39 serialized_test := serialize(*original_test);
42 // Changing the original data here after serializing to
43 // prove that the data isn't just pointing to the original variable
45 original_test.a = 456;
48 // Now we take the array of bytes that we just generate it and transform
49 // it back to a "Test".
51 // This obviously doesn't make much sense in a contrived example like this, but
52 // you could take any data, serialize it to an array of bytes and store it to a file.
54 // Then you read back that file, load the contents and recover the original struct!
56 deserialized_test := deserialize(serialized_test, Test);
57 print("Deserialized: %\n", deserialized_test.*);
58 assert(deserialized_test.a == 123);
63more_types_and_to_a_file :: ()
65 print_example_name("More types, and to a file!");
69 Internal_Variant_Type :: struct { a := 123; }
70 A_Variant :: #type,distinct Internal_Variant_Type;
74 b : [3]string = .["hey", "these", "count"];
80 c := "testoooooaaaaaaaaaaooooT";
81 variant := A_Variant.{};
82 internal : []Internal;
83 d : [2]float32 = .[-1.0, 1.0];
84 table : Table(u32, string);
88 // Here we create a "Test" with a bunch of types, so you can see
89 // that things with dynamic sizes such as strings and arrays of things work
92 // Then we write that to a file
95 internal : [2]Test.Internal;
96 defer array_reset(*internal[0].c);
97 defer array_reset(*internal[1].c);
98 internal[0].a = .[1, 2, 3, 123, 0xFF_FF];
99 internal[0].b[2] = "sailor??? what???";
100 internal[1].a = .[3, 3, 2, 1];
101 internal[1].b[1] = "At this point I don't know what to write here";
102 array_add(*internal[1].c, 123.123);
103 array_add(*internal[1].c, 666.777);
104 array_add(*internal[1].c, 888.777);
107 defer deinit(*test.table);
108 test.b = .[75, 75, 75, 75, 75, 75, 75, 75, 76];
109 test.c = "yo what's up?";
110 test.internal.count = internal.count;
111 test.internal.data = internal.data;
113 table_set(*test.table, 12, "a value on the table");
114 table_set(*test.table, 123, "another value on the table");
115 serialized_data := serialize(*test);
117 success := write_entire_file("./serialized_data.bin", cast(string)serialized_data);
122 // This takes the serialized data in the array of bytes generated above
123 // and deserializes it into what would be a copy of "test" that we set
127 serialized_data := cast([]u8)read_entire_file("./serialized_data.bin");
128 test := deserialize(serialized_data, Test);
129 print("%\n", test.*);
130 for test.table print("%, %\n", it_index, it);
136how_about_compile_time :: ()
138 print_example_name("Serializing at compile-time and deserializing at runtime");
143 c : Table(string, int);
147 // Note how the data to be deserialized to be writable!
149 // Here we're making it a constant first, and then initializing
150 // a variable that copies from the constant array. You can do it
151 // in one step by doing data := #run -> []u8 { ... } but I'm making
152 // it explicit here for clarity.
154 SERIALIZED_DATA_AT_COMPILE_TIME :: #run -> []u8
157 test.a = .[1,2,3,4,5];
158 test.b = "how about dem stringz";
159 table_set(*test.c, "how many croissants do we have?", 60345);
160 return serialize(*test);
162 serialized_data_at_compile_time := SERIALIZED_DATA_AT_COMPILE_TIME;
164 test := deserialize(serialized_data_at_compile_time, Test);
165 print("%\n", test.*);
166 for test.c print("%, %\n", it_index, it);
173 print_example_name("Serializing a type with a replacement");
178 Original_Type :: struct
183 // If you have a type that you want to be serialized as a different set of data
184 // you can do it by providing a Replacement_Type type to convert to. As well as the
185 // functions to transform to and from this type, which need to be called
186 // serialization_replacement and deserialization_replacement.
188 // One example that I've used this for is for hashed-strings/string-ids on dev builds.
189 // Where instead of serializing only the hash, you serialize both the hash and the string
190 // that hashes to it. So when you deserialize the data later, you can see the original string
191 // on debug builds and keep track of it.
193 // See: needs_serialization_replacement()
195 Replacement_Type :: struct
197 data_compressed : u8;
198 time_of_compression : Apollo_Time;
200 serialization_replacement :: (original : *Original_Type) -> Replacement_Type
203 // Note how this procedure gets called twice during serialization. This is because
204 // the code goes throught the members twice. Once to see how much dynamic memory will
205 // be required in total, then another time to do the copy after it has done the allocation.
207 print("Transforming the original data to the replacement type\n");
208 replacement : Replacement_Type;
209 replacement.data_compressed = cast(u8)floor(original.data * 255.0 + 0.5);
210 replacement.time_of_compression = current_time_consensus();
213 deserialization_replacement :: (replacement : *Replacement_Type) -> Original_Type
216 // And this will get called once during deserialization, so you could run any code in here, such
217 // as putting stuff in your own global data structures, or god knows.
219 print("Deserializing data that was compressed on %\n", to_calendar(replacement.time_of_compression));
220 original : Original_Type;
221 original.data = replacement.data_compressed / 255.00;
227 original_test : Test;
228 original_test.og.data = 0.123;
229 data := serialize(*original_test);
231 deserialized_test := deserialize(data, Test);
232 print("%\n", deserialized_test.*);
241print_example_name :: (name : string) #expand
243 for 0..(8 + name.count)-1 print("#");
244 print("\n### % ###\n", name);
245 for 0..(8 + name.count)-1 print("#");
247 `defer print("\n\n\n");
252set_my_print_format :: (c : *Context = null)
254 if c == null then c = *context;
258 using c.print_style.default_format_struct;
259 draw_type_name = true;
260 use_long_form_if_more_than_this_many_members = -1;
261 separator_between_name_and_value = " = ";
262 short_form_separator_between_fields = ", ";
263 long_form_separator_between_fields = "; ";
266 indentation_width = 4;
267 use_newlines_if_long_form = true;
272 using c.print_style.default_format_array;
276 printing_stopped_early_string = "...";
277 draw_separator_after_last_element = false;
278 stop_printing_after_this_many_elements = 16;
283 using c.print_style.default_format_float;
284 zero_removal = .ONE_ZERO_AFTER_DECIMAL;