#pragma once #include "./cbor-walker.h" struct StorageDummy { template void operator()(const char *, V &) {} }; struct StorageExample { template void operator()(const char */*key*/, V &v) { value(v); } private: void value(int64_t &v) {}; void value(uint64_t &v) {}; void value(int32_t &v) {}; void value(uint32_t &v) {}; void value(int16_t &v) {}; void value(uint16_t &v) {}; void value(int8_t &v) {}; void value(uint8_t &v) {}; void value(float &v) {}; void value(double &v) {}; void value(bool &v) {}; template void value(std::vector &array) { for (auto &item : array) { value(item); } } template void value(V &v) { v.state(*this); } }; namespace _impl { template struct VoidFallback { using T = MaybeVoid; }; template struct VoidFallback { using T = Fallback; }; } template struct StorageCborWriter { StorageCborWriter(const signalsmith::cbor::CborWriter &writer, std::vector *buffer=nullptr) : cbor(writer) { if (buffer) buffer->resize(0); if (compact) { cbor.addTag(0xCB68ADED); // turns into "2store..." when base64-encoded cbor.openArray(); } else { cbor.openMap(); } } StorageCborWriter(std::vector &cborBuffer) : StorageCborWriter(signalsmith::cbor::CborWriter(cborBuffer), &cborBuffer) {} ~StorageCborWriter() { cbor.close(); } template void operator()(const char *key, V &value) { if (!compact) cbor.addUtf8(key); writeValue(value); } protected: signalsmith::cbor::CborWriter cbor; #define STORAGE_BASIC_INT(V) \ void writeValue(V &value) { \ cbor.addInt(value); \ } STORAGE_BASIC_INT(int64_t) STORAGE_BASIC_INT(uint64_t) STORAGE_BASIC_INT(int32_t) STORAGE_BASIC_INT(uint32_t) STORAGE_BASIC_INT(int16_t) STORAGE_BASIC_INT(uint16_t) STORAGE_BASIC_INT(int8_t) STORAGE_BASIC_INT(uint8_t) #undef STORAGE_BASIC_INT void writeValue(float &value) { cbor.addFloat(value); } void writeValue(double &value) { cbor.addFloat(value); } void writeValue(bool &value) { cbor.addBool(value); } void writeValue(const char *cStr) { cbor.addUtf8(cStr); } template void writeValue(std::vector &array) { cbor.openArray(array.size()); for (auto &item : array) { writeValue(item); } } #define STORAGE_TYPED_ARRAY(T) \ void writeValue(std::vector &array) { \ cbor.addTypedArray(array.data(), array.size()); \ } STORAGE_TYPED_ARRAY(uint8_t) STORAGE_TYPED_ARRAY(int8_t) STORAGE_TYPED_ARRAY(uint16_t) STORAGE_TYPED_ARRAY(int16_t) STORAGE_TYPED_ARRAY(uint32_t) STORAGE_TYPED_ARRAY(int32_t) STORAGE_TYPED_ARRAY(uint64_t) STORAGE_TYPED_ARRAY(int64_t) STORAGE_TYPED_ARRAY(float) STORAGE_TYPED_ARRAY(double) #undef STORAGE_TYPED_ARRAY using SubStorage = typename _impl::VoidFallback::T; template void writeValue(Obj &obj) { cbor.openMap(); obj.state(*(SubStorage *)this); cbor.close(); } }; template struct StorageCborReader { using Cbor = signalsmith::cbor::TaggedCborWalker; StorageCborReader(Cbor c) : cbor(c) { if (compact) { if (cbor.isArray()) cbor = cbor.enter(); } else { if (cbor.isMap()) cbor = cbor.enter(); } } StorageCborReader(const std::vector &v) : StorageCborReader(Cbor(v)) {} template void operator()(const char *key, V &v) { if (filterKeyBytes != nullptr) { if (!keyMatch(key, filterKeyBytes, filterKeyLength)) return; } else if (!compact) { if (!cbor.isUtf8()) return; // We expect a string key if (!keyMatch(key, (const char *)cbor.bytes(), cbor.length())) { return; // key doesn't match } cbor++; } readValue(v); } template void readValue(Obj &obj) { if (compact) { // No keys, no filters return obj.state(*(SubClass *)this); } if (!cbor.isMap()) return; cbor = cbor.forEachPair([&](Cbor key, Cbor value){ if (!key.isUtf8()) return; const char *fkb = filterKeyBytes; size_t fkl = filterKeyLength; // Temporarily set key, and scan the object for that property filterKeyBytes = (const char *)key.bytes(); filterKeyLength = key.length(); cbor = value; obj.state(*(SubClass *)this); filterKeyBytes = fkb; filterKeyLength = fkl; }); } #define STORAGE_BASIC_TYPE(V) \ void readValue(V &v) { \ v = V(cbor++); \ } STORAGE_BASIC_TYPE(int64_t) STORAGE_BASIC_TYPE(uint64_t) STORAGE_BASIC_TYPE(int32_t) STORAGE_BASIC_TYPE(uint32_t) STORAGE_BASIC_TYPE(int16_t) STORAGE_BASIC_TYPE(uint16_t) STORAGE_BASIC_TYPE(int8_t) STORAGE_BASIC_TYPE(uint8_t) STORAGE_BASIC_TYPE(float) STORAGE_BASIC_TYPE(double) STORAGE_BASIC_TYPE(bool) #undef STORAGE_BASIC_TYPE void readValue(std::string &v) { v = (cbor++).utf8(); } template void readValue(std::vector &array) { if (!cbor.isArray()) return; size_t length = 0; cbor = cbor.forEach([&](Cbor item, size_t index){ length = index + 1; if (array.size() < length) array.resize(length); cbor = item; readValue(array[index]); }); array.resize(length); } private: protected: Cbor cbor; const char *filterKeyBytes = nullptr; size_t filterKeyLength = 0; static bool keyMatch(const char *key, const char *filterKeyBytes, size_t filterKeyLength) { for (size_t i = 0; i < filterKeyLength; ++i) { if (key[i] != filterKeyBytes[i]) return false; } return key[filterKeyLength] == 0; } using SubClass = typename _impl::VoidFallback::T; };