| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524 |
- /**
- * Element binary serialization for Implexus storage layer.
- *
- * Provides serialization and deserialization of Invercargill.Element
- * values to/from binary format for persistent storage.
- */
- namespace Implexus.Storage {
- /**
- * Type codes for binary element serialization.
- */
- internal enum ElementTypeCode {
- NULL = 0x00,
- BOOL = 0x01,
- INT64 = 0x02,
- UINT64 = 0x03,
- DOUBLE = 0x04,
- STRING = 0x05,
- BINARY = 0x06,
- ARRAY = 0x07,
- DICTIONARY = 0x08;
- /**
- * Determines the type code from an Element's GLib.Type.
- */
- public static ElementTypeCode from_type(GLib.Type type) {
- if (type == typeof(bool)) {
- return BOOL;
- } else if (type == typeof(int64)) {
- return INT64;
- } else if (type == typeof(uint64)) {
- return UINT64;
- } else if (type == typeof(double)) {
- return DOUBLE;
- } else if (type == typeof(string)) {
- return STRING;
- } else if (type == typeof(Invercargill.BinaryData)) {
- return BINARY;
- } else if (type == typeof(Invercargill.Enumerable<Invercargill.Element>)) {
- return ARRAY;
- } else if (type == typeof(Invercargill.Properties)) {
- return DICTIONARY;
- } else {
- return NULL;
- }
- }
- }
- /**
- * Writes Element values to binary format.
- */
- public class ElementWriter : Object {
- private Invercargill.ByteComposition _buffer;
- /**
- * Creates a new ElementWriter.
- */
- public ElementWriter() {
- _buffer = new Invercargill.ByteComposition();
- }
- /**
- * Writes an element to the buffer.
- *
- * @param element The element to write
- */
- public void write_element(Invercargill.Element element) throws StorageError {
- // Check for null element
- if (element.is_null()) {
- write_null();
- return;
- }
- // Check the element's type and serialize accordingly
- var type = element.type();
- if (type == typeof(bool)) {
- _buffer.append_uint8(ElementTypeCode.BOOL);
- try {
- write_bool(element.as<bool?>());
- } catch (Invercargill.ElementError e) {
- throw new StorageError.CORRUPT_DATA("Failed to get bool value: %s".printf(e.message));
- }
- } else if (type == typeof(int64)) {
- _buffer.append_uint8(ElementTypeCode.INT64);
- try {
- int64? val = element.as<int64?>();
- write_int64(val == null ? 0 : (!) val);
- } catch (Invercargill.ElementError e) {
- throw new StorageError.CORRUPT_DATA("Failed to get int64 value: %s".printf(e.message));
- }
- } else if (type == typeof(uint64)) {
- _buffer.append_uint8(ElementTypeCode.UINT64);
- try {
- uint64? val = element.as<uint64?>();
- write_uint64(val == null ? 0 : (!) val);
- } catch (Invercargill.ElementError e) {
- throw new StorageError.CORRUPT_DATA("Failed to get uint64 value: %s".printf(e.message));
- }
- } else if (type == typeof(double)) {
- _buffer.append_uint8(ElementTypeCode.DOUBLE);
- try {
- double? val = element.as<double?>();
- write_double(val == null ? 0.0 : (!) val);
- } catch (Invercargill.ElementError e) {
- throw new StorageError.CORRUPT_DATA("Failed to get double value: %s".printf(e.message));
- }
- } else if (type == typeof(string)) {
- _buffer.append_uint8(ElementTypeCode.STRING);
- try {
- write_string(element.as<string>());
- } catch (Invercargill.ElementError e) {
- throw new StorageError.CORRUPT_DATA("Failed to get string value: %s".printf(e.message));
- }
- } else if (type == typeof(Invercargill.BinaryData)) {
- _buffer.append_uint8(ElementTypeCode.BINARY);
- try {
- write_binary(element.as<Invercargill.BinaryData>());
- } catch (Invercargill.ElementError e) {
- throw new StorageError.CORRUPT_DATA("Failed to get binary value: %s".printf(e.message));
- }
- } else if (type == typeof(Invercargill.Enumerable<Invercargill.Element>)) {
- _buffer.append_uint8(ElementTypeCode.ARRAY);
- try {
- write_array(element.as<Invercargill.Enumerable<Invercargill.Element>>());
- } catch (Invercargill.ElementError e) {
- throw new StorageError.CORRUPT_DATA("Failed to get array value: %s".printf(e.message));
- }
- } else if (type == typeof(Invercargill.Properties)) {
- _buffer.append_uint8(ElementTypeCode.DICTIONARY);
- try {
- write_dictionary(element.as<Invercargill.Properties>());
- } catch (Invercargill.ElementError e) {
- throw new StorageError.CORRUPT_DATA("Failed to get dictionary value: %s".printf(e.message));
- }
- } else {
- // Unknown type - serialize as null
- write_null();
- }
- }
- /**
- * Writes a null value.
- */
- public void write_null() {
- _buffer.append_uint8(ElementTypeCode.NULL);
- }
- /**
- * Writes a boolean value.
- */
- public void write_bool(bool value) {
- _buffer.append_uint8(value ? (uint8) 1 : (uint8) 0);
- }
- /**
- * Writes an int64 value (big-endian).
- */
- public void write_int64(int64 value) {
- _buffer.append_uint8((uint8) ((value >> 56) & 0xFF));
- _buffer.append_uint8((uint8) ((value >> 48) & 0xFF));
- _buffer.append_uint8((uint8) ((value >> 40) & 0xFF));
- _buffer.append_uint8((uint8) ((value >> 32) & 0xFF));
- _buffer.append_uint8((uint8) ((value >> 24) & 0xFF));
- _buffer.append_uint8((uint8) ((value >> 16) & 0xFF));
- _buffer.append_uint8((uint8) ((value >> 8) & 0xFF));
- _buffer.append_uint8((uint8) (value & 0xFF));
- }
- /**
- * Writes a uint64 value (big-endian).
- */
- public void write_uint64(uint64 value) {
- _buffer.append_uint8((uint8) ((value >> 56) & 0xFF));
- _buffer.append_uint8((uint8) ((value >> 48) & 0xFF));
- _buffer.append_uint8((uint8) ((value >> 40) & 0xFF));
- _buffer.append_uint8((uint8) ((value >> 32) & 0xFF));
- _buffer.append_uint8((uint8) ((value >> 24) & 0xFF));
- _buffer.append_uint8((uint8) ((value >> 16) & 0xFF));
- _buffer.append_uint8((uint8) ((value >> 8) & 0xFF));
- _buffer.append_uint8((uint8) (value & 0xFF));
- }
- /**
- * Writes a double value.
- */
- public void write_double(double value) {
- int64 bits = (int64) *(uint64*) &value;
- write_int64(bits);
- }
- /**
- * Writes a length value (int64).
- */
- public void write_length(int64 length) {
- write_int64(length);
- }
- /**
- * Writes a string value.
- */
- public void write_string(string value) {
- int64 len = value.length;
- write_length(len);
- _buffer.append_string(value);
- }
- /**
- * Writes binary data.
- */
- public void write_binary(Invercargill.BinaryData value) {
- var bytes = value.to_bytes();
- int64 len = (int64) bytes.length;
- write_length(len);
- _buffer.append_bytes(bytes);
- }
- /**
- * Writes an array of elements.
- */
- public void write_array(Invercargill.Enumerable<Invercargill.Element> collection) {
- uint count = collection.count();
- write_length((int64) count);
- foreach (var item in collection) {
- try {
- write_element(item);
- } catch (StorageError e) {
- // Skip invalid elements - write null
- write_null();
- }
- }
- }
- /**
- * Writes a dictionary of elements.
- */
- public void write_dictionary(Invercargill.Properties props) {
- uint count = props.count();
- write_length((int64) count);
- foreach (var kvp in props) {
- write_string(kvp.key);
- try {
- write_element(kvp.value);
- } catch (StorageError e) {
- // Write null for invalid elements
- write_null();
- }
- }
- }
- /**
- * Gets the written data as BinaryData.
- *
- * @return The binary data
- */
- public Invercargill.BinaryData to_binary_data() {
- return _buffer;
- }
- /**
- * Clears the buffer for reuse.
- */
- public void clear() {
- _buffer.clear();
- }
- }
- /**
- * Reads Element values from binary format.
- */
- public class ElementReader : Object {
- private Invercargill.BinaryData _data;
- private Invercargill.ReadOnlyAddressable<uint8> _buffer;
- private uint _position;
- private uint _size;
- /**
- * Creates a new ElementReader with the given data.
- *
- * @param data The binary data to read
- */
- public ElementReader(Invercargill.BinaryData data) {
- _data = data;
- _buffer = data.to_byte_buffer();
- _position = 0;
- _size = data.count();
- }
- /**
- * Current position in the data.
- */
- public uint position {
- get { return _position; }
- }
- /**
- * Size of the data.
- */
- public uint size {
- get { return _size; }
- }
- /**
- * Whether there is more data to read.
- */
- public bool has_more {
- get { return _position < _size; }
- }
- /**
- * Reads a single byte.
- */
- private uint8 read_byte() throws StorageError {
- if (_position >= _size) {
- throw new StorageError.CORRUPT_DATA("Unexpected end of data");
- }
- try {
- var byte_val = _buffer.get(_position);
- _position++;
- return byte_val;
- } catch (Invercargill.IndexError e) {
- throw new StorageError.CORRUPT_DATA("Failed to read byte: %s".printf(e.message));
- }
- }
- /**
- * Reads bytes from the data.
- *
- * @param length Number of bytes to read
- * @return The bytes read
- */
- private uint8[] read_bytes(uint length) throws StorageError {
- if (_position + length > _size) {
- throw new StorageError.CORRUPT_DATA("Unexpected end of data");
- }
- var bytes = new uint8[length];
- var slice = _data.slice(_position, _position + length);
- var slice_bytes = slice.to_bytes();
- Memory.copy(bytes, slice_bytes.get_data(), length);
- _position += length;
- return bytes;
- }
- /**
- * Reads an element from the data.
- *
- * @return The element read
- */
- public Invercargill.Element read_element() throws StorageError {
- if (_position >= _size) {
- throw new StorageError.CORRUPT_DATA("Unexpected end of data");
- }
- var type_code = (ElementTypeCode) read_byte();
- switch (type_code) {
- case ElementTypeCode.NULL:
- return new Invercargill.NullElement();
- case ElementTypeCode.BOOL:
- return new Invercargill.NativeElement<bool?>(read_bool());
- case ElementTypeCode.INT64:
- return new Invercargill.NativeElement<int64?>(read_int64());
- case ElementTypeCode.UINT64:
- return new Invercargill.NativeElement<uint64?>(read_uint64());
- case ElementTypeCode.DOUBLE:
- return new Invercargill.NativeElement<double?>(read_double());
- case ElementTypeCode.STRING:
- return new Invercargill.NativeElement<string>(read_string());
- case ElementTypeCode.BINARY:
- return new Invercargill.NativeElement<Invercargill.BinaryData>(read_binary());
- case ElementTypeCode.ARRAY:
- return read_array();
- case ElementTypeCode.DICTIONARY:
- return read_dictionary();
- default:
- throw new StorageError.CORRUPT_DATA("Unknown type code: %d".printf((int) type_code));
- }
- }
- /**
- * Reads a boolean value.
- */
- public bool read_bool() throws StorageError {
- return read_byte() != 0;
- }
- /**
- * Reads an int64 value (big-endian).
- */
- public int64 read_int64() throws StorageError {
- if (_position + 8 > _size) {
- throw new StorageError.CORRUPT_DATA("Unexpected end of data reading int64");
- }
- try {
- int64 result = (int64) (
- ((int64) _buffer.get(_position) << 56) |
- ((int64) _buffer.get(_position + 1) << 48) |
- ((int64) _buffer.get(_position + 2) << 40) |
- ((int64) _buffer.get(_position + 3) << 32) |
- ((int64) _buffer.get(_position + 4) << 24) |
- ((int64) _buffer.get(_position + 5) << 16) |
- ((int64) _buffer.get(_position + 6) << 8) |
- ((int64) _buffer.get(_position + 7))
- );
- _position += 8;
- return result;
- } catch (Invercargill.IndexError e) {
- throw new StorageError.CORRUPT_DATA("Failed to read int64: %s".printf(e.message));
- }
- }
- /**
- * Reads a uint64 value (big-endian).
- */
- public uint64 read_uint64() throws StorageError {
- if (_position + 8 > _size) {
- throw new StorageError.CORRUPT_DATA("Unexpected end of data reading uint64");
- }
- try {
- uint64 result = (uint64) (
- ((uint64) _buffer.get(_position) << 56) |
- ((uint64) _buffer.get(_position + 1) << 48) |
- ((uint64) _buffer.get(_position + 2) << 40) |
- ((uint64) _buffer.get(_position + 3) << 32) |
- ((uint64) _buffer.get(_position + 4) << 24) |
- ((uint64) _buffer.get(_position + 5) << 16) |
- ((uint64) _buffer.get(_position + 6) << 8) |
- ((uint64) _buffer.get(_position + 7))
- );
- _position += 8;
- return result;
- } catch (Invercargill.IndexError e) {
- throw new StorageError.CORRUPT_DATA("Failed to read uint64: %s".printf(e.message));
- }
- }
- /**
- * Reads a double value.
- */
- public double read_double() throws StorageError {
- int64 bits = read_int64();
- return *(double*) &bits;
- }
- /**
- * Reads a length value.
- */
- public int64 read_length() throws StorageError {
- return read_int64();
- }
- /**
- * Reads a string value.
- */
- public string read_string() throws StorageError {
- int64 len = read_length();
- if (len < 0) {
- throw new StorageError.CORRUPT_DATA("Negative string length");
- }
- var bytes = read_bytes((uint) len);
- // Create a properly null-terminated string from the bytes
- // We need to copy the data and add a null terminator
- var str_builder = new StringBuilder.sized((size_t)(len + 1));
- for (int64 i = 0; i < len; i++) {
- str_builder.append_c((char) bytes[i]);
- }
- return str_builder.str;
- }
- /**
- * Reads binary data.
- */
- public Invercargill.BinaryData read_binary() throws StorageError {
- int64 len = read_length();
- if (len < 0) {
- throw new StorageError.CORRUPT_DATA("Negative binary length");
- }
- var bytes = read_bytes((uint) len);
- return new Invercargill.DataStructures.ByteBuffer.from_byte_array(bytes);
- }
- /**
- * Reads an array of elements.
- */
- public Invercargill.NativeElement<Invercargill.Enumerable<Invercargill.Element>> read_array() throws StorageError {
- int64 count = read_length();
- if (count < 0) {
- throw new StorageError.CORRUPT_DATA("Negative array count");
- }
- var array = new Invercargill.DataStructures.Vector<Invercargill.Element>();
- for (int64 i = 0; i < count; i++) {
- var element = read_element();
- array.add(element);
- }
- return new Invercargill.NativeElement<Invercargill.Enumerable<Invercargill.Element>>(array);
- }
- /**
- * Reads a dictionary of elements.
- */
- public Invercargill.NativeElement<Invercargill.Properties> read_dictionary() throws StorageError {
- int64 count = read_length();
- if (count < 0) {
- throw new StorageError.CORRUPT_DATA("Negative dictionary count");
- }
- var props = new Invercargill.DataStructures.PropertyDictionary();
- for (int64 i = 0; i < count; i++) {
- string key = read_string();
- var value = read_element();
- try {
- props.set(key, value);
- } catch (Invercargill.IndexError e) {
- throw new StorageError.CORRUPT_DATA("Failed to set dictionary key: %s".printf(e.message));
- }
- }
- return new Invercargill.NativeElement<Invercargill.Properties>(props);
- }
- }
- }
|