1 /** 2 Copyright: Copyright (c) 2017-2018 Andrey Penechko. 3 License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). 4 Authors: Andrey Penechko. 5 */ 6 module voxelman.serialization.datasaver; 7 8 import std.traits : TemplateOf; 9 import std.array : empty; 10 import voxelman.container.buffer; 11 import voxelman.serialization; 12 import voxelman.utils.mapping; 13 14 struct PluginDataSaver 15 { 16 StringMap* stringMap; 17 ubyte[16] delegate(uint) getKey; 18 private Buffer!ubyte buffer; 19 private size_t prevDataLength; 20 21 Buffer!ubyte* beginWrite() { 22 prevDataLength = buffer.data.length; 23 return &buffer; 24 } 25 26 IoStorageType storageType() { return IoStorageType.database; } 27 28 void endWrite(ref IoKey key) { 29 // write empty entries, they will be deleted in storage worker 30 uint entrySize = cast(uint)(buffer.data.length - prevDataLength); 31 buffer.put(*cast(ubyte[4]*)&entrySize); 32 buffer.put(getKey(stringMap.get(key))); 33 } 34 35 void writeEntryEncoded(T)(ref IoKey key, T data) { 36 beginWrite(); 37 encodeCbor(buffer, data); 38 endWrite(key); 39 } 40 41 void writeMapping(T)(ref IoKey key, T mapping) 42 if (__traits(isSame, TemplateOf!T, Mapping)) 43 { 44 auto sink = beginWrite(); 45 encodeCborArrayHeader(sink, mapping.infoArray.length); 46 foreach(const ref info; mapping.infoArray) 47 { 48 encodeCborString(sink, info.name); 49 } 50 endWrite(key); 51 } 52 53 void reset() @nogc { 54 buffer.clear(); 55 } 56 57 int opApply(scope int delegate(ubyte[16] key, ubyte[] data) dg) 58 { 59 ubyte[] data = buffer.data; 60 while(!data.empty) 61 { 62 ubyte[16] key = data[$-16..$]; 63 uint entrySize = *cast(uint*)(data[$-4-16..$-16].ptr); 64 ubyte[] entry = data[$-4-16-entrySize..$-4-16]; 65 auto result = dg(key, entry); 66 67 data = data[0..$-4-16-entrySize]; 68 69 if (result) return result; 70 } 71 return 0; 72 } 73 } 74 75 unittest 76 { 77 ubyte[16] keyProducer(uint key) { 78 return (ubyte[16]).init; 79 } 80 StringMap stringMap; 81 auto saver = PluginDataSaver(&stringMap, &keyProducer); 82 //StringMap stringMap; 83 //saver.stringMap = &stringMap; 84 85 auto dbKey1 = IoKey("Key1"); 86 saver.writeEntryEncoded(dbKey1, 1); 87 88 auto dbKey2 = IoKey("Key2"); 89 auto sink = saver.beginWrite(); 90 encodeCbor(sink, 2); 91 saver.endWrite(dbKey2); 92 93 // iteration 94 foreach(ubyte[16] key, ubyte[] data; saver) { 95 // 96 } 97 saver.reset(); 98 }