Overview
DLHN ( Pronounced the same as "Dullahan" ) is a language and platform neutral binary serialization format that is inspired by JSON, CSV, MessagePack, and Protocol Buffers. It is designed for blazing fast serialization and deserialization with the smallest possible data size without the need for schema file. However, we are also considering supporting schema file in the future.
Data Structures
DLHN has a header and a body part, which can be separated from each other. It also supports Stream.
Header
Header only.
Header |
---|
Body
Body only. The most efficient format. However, the deserializer must know the header information in advance.
Body |
---|
Header + Body
Header followed by body. Unlike the body-only case, this format does not require the deserializer to know the header information in advance.
Header | Body |
---|
Header (Stream)
Stream version with headers only.
Header | Header | Header | Header.. |
---|
Body (Stream)
Stream version with bodies only.
Body | Body | Body | Body.. |
---|
Header + Body (Stream)
Stream version with a header and bodies. All bodies must have the same type as the first header.
Header | Body | Body | Body | Body.. |
---|
(Header + Body) (Stream)
Stream version with headers and bodies. Similar to Header + Body (Stream) but can store different types of data in each pair.
Header | Body | Header | Body | Header | Body | .. |
---|
Types
Unit
Represents an Unit.
Optional<T>
Represents some that contains a T-type value or none that does not contain a value.
Boolean
Represents a boolean.
UInt8
Represents an 8-bit unsigned integer.
UInt16
Represents a 16-bit unsigned integer.
UInt32
Represents a 32-bit unsigned integer.
UInt64
Represents a 64-bit unsigned integer.
Int8
Represents an 8-bit signed integer.
Int16
Represents a 16-bit signed integer.
Int32
Represents a 32-bit signed integer.
Int64
Represents a 64-bit signed integer.
Float32
Represents an IEEE 754 single precision floating point number.
Float64
Represents an IEEE 754 double precision floating point number.
BigUInt
Represents an arbitrary precision unsigned integer.
BigInt
Represents an arbitrary precision signed integer.
BigDecimal
Represents an arbitrary precision signed decimal number.
String
Represents an UTF-8 string.
Binary
Represents a byte array.
Array<T>
Represents a sequence of values of the same type T.
Tuple<(T1, ..)>
Represents a collection of values of different types.
Map<T>
Represents a collection of key value pairs of string key type and same value type.
Enum { Field1(T1), Field..(T..), }
Represents a custom defined type which may be one of a few different variants.
Date
Represents a proleptic Gregorian calendar date.
DateTime
Represents a TimeZone independent moment in nanoseconds starting from 1970-01-01T00:00Z.
Header
Unit
Unit code |
---|
0x00 |
Optional<T>
Optional code | <T> |
---|---|
0x01 | serialize_header(T) |
Optional<Boolean>
Optional code | Boolean code |
---|---|
0x01 | 0x02 |
Boolean
Boolean code |
---|
0x02 |
UInt8
UInt8 code |
---|
0x03 |
UInt16
UInt16 code |
---|
0x04 |
UInt32
UInt32 code |
---|
0x05 |
UInt64
UInt64 code |
---|
0x06 |
Int8
Int8 code |
---|
0x08 |
Int16
Int16 code |
---|
0x09 |
Int32
Int32 code |
---|
0x0a |
Int64
Int64 code |
---|
0x0b |
Float32
Float32 code |
---|
0x0d |
Float64
Float64 code |
---|
0x0e |
BigUInt
BigUInt code |
---|
0x0f |
BigInt
BigInt code |
---|
0x10 |
BigDecimal
BigDecimal code |
---|
0x11 |
String
String code |
---|
0x12 |
Binary
Binary code |
---|
0x13 |
Array<T>
Array code | <T> |
---|---|
0x14 | serialize_header(T) |
Array<Boolean>
Array code | Boolean code |
---|---|
0x14 | 0x02 |
Tuple<(T1, ..)>
Tuple code | Number of fields in Tuple : UInt16 | <T1> | <..> |
---|---|---|---|
0x15 | Number of fields in Tuple | serialize_header(T1) | serialize_header(..) |
Tuple<(Boolean, UInt8, String)>
Tuple code | Number of fields in Tuple : UInt16 | Boolean code | UInt8 code | String code |
---|---|---|---|---|
0x15 | 0x03 | 0x02 | 0x03 | 0x12 |
Map<T>
Map code | <T> |
---|---|
0x17 | serialize_header(T) |
Map<Boolean>
Map code | Boolean code |
---|---|
0x17 | 0x03 |
Enum { Field1(T1), Field..(T..), }
Enum code | Number of fields in Enum : UInt16 | <T1> | <T..> |
---|---|---|---|
0x18 | Number of fields in Enum | serialize_header(T1) | serialize_header(T..) |
Date
Date code |
---|
0x19 |
DateTime
DateTime code |
---|
0x1a |
Body
Unit
0 byte
A value of type Unit. Not a single byte is written during serialization, and not a single byte is read during deserialization. If you want to make it Nullable, use the Optional type.
Unit |
---|
Optional<T>
1 ~ N bytes
Optional can store a single value of type T inside, and has a state of None or Some(value: T).
None |
---|
0x00 |
Some | value: T |
---|---|
0x01 | serialize_body(value) |
None: Optional<Boolean>
None |
---|
0x00 |
Some(true): Optional<Boolean>
Some | value: Boolean |
---|---|
0x01 | 0x01 |
Boolean
1 byte
Stores a true or false value.
value: Boolean |
---|
serialize_body(value: Boolean) |
false
Boolean value |
---|
0x00 |
true
Boolean value |
---|
0x01 |
UInt8
1 byte
An 8-bit little-endian unsigned integer. (Note: PrefixVarint is not used)
value: UInt8 |
---|
serialize_body(value: UInt8) |
0
value: UInt8 |
---|
0x00 |
1
value: UInt8 |
---|
0x01 |
255
value: UInt8 |
---|
0xff |
UInt16
1 ~ 3 bytes
16bit unsigned integer. Encode with PrefixVarint.
value: UInt16 |
---|
serialize_body(value: UInt16) |
0
value: UInt16 |
---|
0x00 |
1
value: UInt16 |
---|
0x01 |
127
value: UInt16 |
---|
0x7f |
128
value: UInt16 |
---|
0x8002 |
16383
value: UInt16 |
---|
0xbfff |
16384
value: UInt16 |
---|
0xc00040 |
65535
value: UInt16 |
---|
0xc0ffff |
UInt32
1 ~ 5 bytes
32bit unsigned integer. Encode with PrefixVarint.
value: UInt32 |
---|
serialize_body(value: UInt32) |
0
value: UInt32 |
---|
0x00 |
1
value: UInt32 |
---|
0x01 |
127
value: UInt32 |
---|
0x7f |
128
value: UInt32 |
---|
0x8002 |
16383
value: UInt32 |
---|
0xbfff |
16384
value: UInt32 |
---|
0xc00002 |
2097151
value: UInt32 |
---|
0xdfffff |
2097152
value: UInt32 |
---|
0xe0000002 |
268435455
value: UInt32 |
---|
0xefffffff |
268435456
value: UInt32 |
---|
0xf000000010 |
4294967295
value: UInt32 |
---|
0xf0ffffffff |
UInt64
1 ~ 9 bytes
64bit unsigned integer. Encode with PrefixVarint.
value: UInt64 |
---|
serialize_body(value: UInt64) |
0
value: UInt64 |
---|
0x00 |
1
value: UInt64 |
---|
0x01 |
127
value: UInt64 |
---|
0x7f |
128
value: UInt64 |
---|
0x8002 |
16383
value: UInt64 |
---|
0xbfff |
16384
value: UInt64 |
---|
0xc00002 |
2097151
value: UInt64 |
---|
0xdfffff |
2097152
value: UInt64 |
---|
0xe0000002 |
268435455
value: UInt64 |
---|
0xefffffff |
268435456
value: UInt64 |
---|
0xf000000002 |
34359738367
value: UInt64 |
---|
0xf7ffffffff |
34359738368
value: UInt64 |
---|
0xf80000000002 |
4398046511103
value: UInt64 |
---|
0xfbffffffffff |
4398046511104
value: UInt64 |
---|
0xfc000000000002 |
562949953421311
value: UInt64 |
---|
0xfdffffffffffff |
562949953421312
value: UInt64 |
---|
0xfe00000000000002 |
72057594037927935
value: UInt64 |
---|
0xfeffffffffffffff |
72057594037927936
value: UInt64 |
---|
0xff0000000000000001 |
18446744073709551615
value: UInt64 |
---|
0xffffffffffffffffff |
Int8
1 byte
An 8-bit little-endian integer. (Note: ZigZag encoding and PrefixVarint are not used)
value: Int8 |
---|
serialize_body(value: Int8) |
-128
value: Int8 |
---|
0x80 |
-1
value: Int8 |
---|
0xff |
0
value: Int8 |
---|
0x00 |
1
value: Int8 |
---|
0x01 |
127
value: Int8 |
---|
0x7f |
Int16
1 ~ 3 bytes
16bit integer. Encode with ZigZag encoding and PrefixVarint.
value: Int16 |
---|
serialize_body(value: Int16) |
-32768
value: Int16 |
---|
0xc0ffff |
-8193
value: Int16 |
---|
0xc00140 |
-8192
value: Int16 |
---|
0xbfff |
-65
value: Int16 |
---|
0x8102 |
-64
value: Int16 |
---|
0x7f |
-1
value: Int16 |
---|
0x01 |
0
value: Int16 |
---|
0x00 |
1
value: Int16 |
---|
0x02 |
63
value: Int16 |
---|
0x7e |
64
value: Int16 |
---|
0x8002 |
8191
value: Int16 |
---|
0xbeff |
8192
value: Int16 |
---|
0xc00040 |
32767
value: Int16 |
---|
0xc0feff |
Int32
1 ~ 5 bytes
32bit integer. Encode with ZigZag encoding and PrefixVarint.
value: Int32 |
---|
serialize_body(value: Int32) |
-2147483648
value: Int32 |
---|
0xf0ffffffff |
-134217729
value: Int32 |
---|
0xf001000010 |
-134217728
value: Int32 |
---|
0xefffffff |
-1048577
value: Int32 |
---|
0xe1000002 |
-1048576
value: Int32 |
---|
0xdfffff |
-8193
value: Int32 |
---|
0xc10002 |
-8192
value: Int32 |
---|
0xbfff |
-65
value: Int32 |
---|
0x8102 |
-64
value: Int32 |
---|
0x7f |
-1
value: Int32 |
---|
0x01 |
0
value: Int32 |
---|
0x00 |
1
value: Int32 |
---|
0x02 |
63
value: Int32 |
---|
0x7e |
64
value: Int32 |
---|
0x8002 |
8191
value: Int32 |
---|
0xbeff |
8192
value: Int32 |
---|
0xc00002 |
1048575
value: Int32 |
---|
0xdeffff |
1048576
value: Int32 |
---|
0xe0000002 |
134217727
value: Int32 |
---|
0xeeffffff |
134217728
value: Int32 |
---|
0xf000000010 |
2147483647
value: Int32 |
---|
0xf0feffffff |
Int64
1 ~ 9 bytes
64bit integer. Encode with ZigZag encoding and PrefixVarint.
value: Int64 |
---|
serialize_body(value: Int64) |
-9223372036854775808
value: Int64 |
---|
0xffffffffffffffffff |
-36028797018963969
value: Int64 |
---|
0xff0100000000000001 |
-36028797018963968
value: Int64 |
---|
0xfeffffffffffffff |
-281474976710657
value: Int64 |
---|
0xfe01000000000002 |
-281474976710656
value: Int64 |
---|
0xfdffffffffffff |
-2199023255553
value: Int64 |
---|
0xfd000000000002 |
-2199023255552
value: Int64 |
---|
0xfbffffffffff |
-17179869185
value: Int64 |
---|
0xf90000000002 |
-17179869184
value: Int64 |
---|
0xf7ffffffff |
-134217729
value: Int64 |
---|
0xf100000002 |
-134217728
value: Int64 |
---|
0xefffffff |
-1048577
value: Int64 |
---|
0xe1000002 |
-1048576
value: Int64 |
---|
0xdfffff |
-8193
value: Int64 |
---|
0xc10002 |
-8192
value: Int64 |
---|
0xbfff |
-65
value: Int64 |
---|
0x8102 |
-64
value: Int64 |
---|
0x7f |
-1
value: Int64 |
---|
0x01 |
0
value: Int64 |
---|
0x00 |
1
value: Int64 |
---|
0x02 |
63
value: Int64 |
---|
0x7e |
64
value: Int64 |
---|
0x8002 |
8191
value: Int64 |
---|
0xbeff |
8192
value: Int64 |
---|
0xc00002 |
1048575
value: Int64 |
---|
0xdeffff |
1048576
value: Int64 |
---|
0xe0000002 |
134217727
value: Int64 |
---|
0xeeffffff |
134217728
value: Int64 |
---|
0xf000000002 |
17179869183
value: Int64 |
---|
0xf6ffffffff |
17179869184
value: Int64 |
---|
0xf80000000002 |
2199023255551
value: Int64 |
---|
0xfaffffffffff |
2199023255552
value: Int64 |
---|
0xfc000000000002 |
281474976710655
value: Int64 |
---|
0xfcffffffffffff |
281474976710656
value: Int64 |
---|
0xfe00000000000002 |
36028797018963967
value: Int64 |
---|
0xfefeffffffffffff |
36028797018963968
value: Int64 |
---|
0xff0000000000000001 |
9223372036854775807
value: Int64 |
---|
0xfffeffffffffffffff |
Float32
4 bytes
32bit float. Stores IEEE 754 single precision floating point number format in little endian.
value: Float32 |
---|
serialize_body(value: Float32) |
-Infinity
value: Float32 |
---|
0x000080ff |
-1.1
value: Float32 |
---|
0xcdcc8cbf |
0
value: Float32 |
---|
0x00000000 |
1.1
value: Float32 |
---|
0xcdcc8c3f |
Infinity
value: Float32 |
---|
0x0000807f |
NaN
value: Float32 |
---|
0x0000c07f |
Float64
8 bytes
64bit float. Stores IEEE 754 double precision floating point number format in little endian.
value: Float64 |
---|
serialize_body(value: Float64) |
-Infinity
value: Float64 |
---|
0x000000000000f0ff |
-1.1
value: Float64 |
---|
0x9a9999999999f1bf |
0
value: Float64 |
---|
0x0000000000000000 |
1.1
value: Float64 |
---|
0x9a9999999999f13f |
Infinity
value: Float64 |
---|
0x000000000000f07f |
NaN
value: Float64 |
---|
0x000000000000f87f |
BigUInt
1 ~ N bytes
Unsigned BigInt. The first byte is a BigUInt byte number ( UInt64 ) , followed by a little-endian unsigned BigInt. If the value of BigUInt is 0, the byte number part will be filled with 0 and the BigUInt part will not store anything.
Bytes of serialized BigUint value: UInt64 | value: BigUInt |
---|---|
serialize_body(Bytes of serialized BigUint value: UInt64) | serialize_body(value: BigUInt) |
0
Bytes of serialized BigUint value: UInt64 |
---|
0x00 |
1234567890
Bytes of serialized BigUint value: UInt64 | value: BigUInt |
---|---|
0x04 | 0xd2029649 |
BigInt
1 ~ N bytes
BigInt. The first byte is a BigInt byte number ( UInt64 ) , followed by a little-endian BigInt. If the value of BigInt is 0, the byte number part will be filled with 0 and the BigInt part will not store anything.
Bytes of serialized BigInt value: UInt64 | value: BigInt |
---|---|
serialize_body(Bytes of serialized BigInt value: UInt64) | serialize_body(value: BigInt) |
0
Bytes of serialized BigInt value: UInt64 |
---|
0x00 |
1234567890
Bytes of serialized BigInt value: UInt64 | value: BigInt |
---|---|
0x04 | 0xd2029649 |
-1234567890
Bytes of serialized BigInt value: UInt64 | value: BigInt |
---|---|
0x04 | 0x2efd69b6 |
BigDecimal
1 ~ N bytes
BigDecimal. Stores an arbitrary precision integer unscaled value ( BigInt ) and a scale ( Int64 ).
unscaled value: BigInt | scale: Int64 |
---|---|
serialize_body(unscaled value: BigInt) | serialize_body(scale: Int64) |
0
unscaled value: BigInt |
---|
0x00 |
1.23
unscaled value: BigInt | scale: Int64 |
---|---|
0x017b | 0x04 |
-1.23
unscaled value: BigInt | scale: Int64 |
---|---|
0x0185 | 0x04 |
String
1 ~ N bytes
UTF-8 String. Stores a byte number of a string value ( UInt64 ) and the string value. If the string is empty, the string part will not store anything.
Bytes of serialized String value: UInt64 | value: String |
---|---|
serialize_body(Bytes of serialized String value: UInt64) | serialize_body(value: String) |
""
Bytes of serialized String value: UInt64 |
---|
0x00 |
"Test"
Bytes of serialized String value: UInt64 | value: String |
---|---|
0x04 | 0x54657374 |
Binary
1 ~ N bytes
Binary. Stores a byte number of a byte sequence ( UInt64 ) and the byte sequence. When the byte sequence is empty, nothing is stored in the byte sequence section.
Bytes of serialized Binary value: UInt64 | value: Binary |
---|---|
serialize_body(Bytes of serialized Binary value: UInt64) | serialize_body(value: Binary) |
[]
Bytes of serialized Binary value: UInt64 |
---|
0x00 |
[1, 2, 3]
Bytes of serialized Binary value: UInt64 | value: Binary |
---|---|
0x03 | 0x010203 |
Array<T>
1 ~ N bytes
An array of type T. Stores a number of elements ( UInt64 ) and the encoded values of all T types in order.
Number of values in Array: UInt64 | Array[0] value: T | Array[..] value: T |
---|---|---|
serialize_body(Number of values in Array: UInt64) | serialize_body(Array[0] value: T) | serialize_body(Array[..] value: T).. |
[]: Array<UInt8>
Number of values in Array: UInt64 |
---|
0x00 |
[1, 2, 3]: Array<UInt8>
Number of values in Array: UInt64 | Array[0] value: UInt8 | Array[1] value: UInt8 | Array[2] value: UInt8 |
---|---|---|---|
0x03 | 0x01 | 0x02 | 0x03 |
Tuple<(T1, ..)>
N bytes
Tuple. Stores the encoded values in the order of their definitions.
value: T1 | value: T.. |
---|---|
serialize_body(value: T1) | serialize_body(value: T).. |
(123, "Test"): (UInt8, String)
value: UInt8 | value: String |
---|---|
0x7b | 0x0454657374 |
Map<T>
1 ~ N bytes
Map. Stores a number of elements ( UInt64 ), keys and values. The keys can only store String and all the values must be the same type. Encodes all the elements in order of key and value.
Number of elements in Map: UInt64 | key: String | value: T | key: String.. | value: T.. |
---|---|---|---|---|
serialize_body(Number of elements in Map: UInt64) | serialize_body(key: String) | serialize_body(value: T) | serialize_body(key: String).. | serialize_body(value: T).. |
Map { "field1": true, "field2", false }: Map<Boolean>
Number of elements in Map: UInt64 | key: String | value: Boolean | key: String | value: Boolean |
---|---|---|---|---|
0x02 | 0x066669656c6432 | 0x00 | 0x066669656c6431 | 0x01 |
Enum { Field1(T1), Field..(T..) }
1 ~ N bytes
Enum. Stores a field number ( UInt64 ) that starts from 0. Then, encodes and stores the values in the field.
Field number: UInt64 | Field value: T.. |
---|---|
serialize_body(Field number: UInt64) | serialize_body(Field value: T..) |
Enum::B(123): Enum { A(Boolean), B(UInt8), C(Boolean, String) }
Field number: UInt64 | Field value: UInt8 |
---|---|
0x01 | 0x7b |
Date
2 ~ N bytes
Date. Stores a year ( Int32 ) which represents 2000 as a value 0, followed by an ordinal ( Int16 ) which represents January 1 as a value 0.
Year value: Int32 | Ordinal value: UInt16 |
---|---|
serialize_body(Year value: Int32) | serialize_body(Ordinal value: UInt16) |
2000-01-01
Year value: Int32 | Ordinal value: UInt16 |
---|---|
0x00 | 0x00 |
2020-08-04
Year value: Int32 | Ordinal value: UInt16 |
---|---|
0x28 | 0x9803 |
DateTime
2 ~ N bytes
DateTime. Stores seconds ( Int64 ) and nanoseconds ( UInt32 ) that represent the time passed since 1970-01-01 00:00:00 UTC.
Seconds value: Int64 | Nano seconds value: UInt32 |
---|---|
serialize_body(Seconds value: Int64) | serialize_body(Nano seconds value: UInt32) |
1970-01-01 00:00:00.000000000
Seconds value: Int64 | Nano seconds value: UInt32 |
---|---|
0x00 | 0x00 |
2020-08-04 12:34:56.123456789
Seconds value: Int64 | Nano seconds value: UInt32 |
---|---|
0xf07c55ca17 | 0xe5d1bc75 |