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 }