Skip to content

Commit

Permalink
Bon now supports Tuple natively.
Browse files Browse the repository at this point in the history
  • Loading branch information
Bobris committed Mar 18, 2024
1 parent c751665 commit 4b1fdb0
Show file tree
Hide file tree
Showing 4 changed files with 131 additions and 69 deletions.
75 changes: 74 additions & 1 deletion BTDB/Bon/Bon.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public enum BonType
Class, // 133 - VUint offset to VUint offset to VUint len + VUint offset to type name string + VUint offsets to strings, Bons*len
Dictionary, // 29 - empty, 134 - VUint offset to VUint len + (Key Bon + Value Bon)*len
ByteArray, // 30 - empty, 135 - VUint offset to VUint len + bytes
Tuple, // 137 - VUint offset to VUint len + Bons*len (same as Array)
}

public static class Helpers
Expand Down Expand Up @@ -60,6 +61,7 @@ public static class Helpers
public const byte CodeByteArrayEmpty = 30;
public const byte CodeByteArrayPtr = 135;
public const byte CodeArraySplitBy32Ptr = 136;
public const byte CodeTuplePtr = 137;
// ReSharper restore InconsistentNaming

public static BonType BonTypeFromByte(byte b)
Expand All @@ -79,6 +81,7 @@ public static BonType BonTypeFromByte(byte b)
CodeClassPtr => BonType.Class,
CodeDictionaryEmpty or CodeDictionaryPtr => BonType.Dictionary,
CodeByteArrayEmpty or CodeByteArrayPtr => BonType.ByteArray,
CodeTuplePtr => BonType.Tuple,
_ => BonType.Error
};
}
Expand Down Expand Up @@ -347,6 +350,7 @@ enum State
ClassValue,
DictionaryKey,
DictionaryValue,
Tuple
};

State _state = State.Empty;
Expand Down Expand Up @@ -590,6 +594,37 @@ public void FinishArray()
AfterBon();
}

public void StartTuple()
{
BeforeBon();
StackPush();
_state = State.Tuple;
}

public void FinishTuple()
{
if (_state != State.Tuple) ThrowWrongState();
var items = _items;
var bytes = _topData;
var objKeys = _objKeys;
StackPop();
Debug.Assert(objKeys.Count == 0);
ref var rootData = ref _topData;
if (_stack.Count > 0)
{
rootData = ref _stack[0].Item2;
}

var pos = rootData.GetCurrentPosition();
rootData.WriteVUInt32(items);
rootData.WriteBlock(bytes.GetSpan());
_lastBonPos = (ulong)_topData.GetCurrentPosition();
_topData.WriteUInt8(Helpers.CodeTuplePtr);
_topData.WriteVUInt64((ulong)pos);

AfterBon();
}

public void StartObject()
{
BeforeBon();
Expand Down Expand Up @@ -796,7 +831,8 @@ void AfterBon()

void BeforeBon()
{
if (_state is not (State.Empty or State.Array or State.ObjectValue or State.ClassValue or State.DictionaryKey
if (_state is not (State.Empty or State.Array or State.Tuple or State.ObjectValue or State.ClassValue
or State.DictionaryKey
or State.DictionaryValue))
{
ThrowWrongState();
Expand Down Expand Up @@ -1112,6 +1148,28 @@ public bool TryGetArray(out ArrayBon bon)
}
}

public bool TryGetTuple(out ArrayBon bon)
{
var b = _reader.PeekUInt8();
switch (b)
{
case Helpers.CodeTuplePtr:
{
_reader.Skip1Byte();
_items--;
var ofs = _reader.ReadVUInt64();
var reader2 = _reader;
reader2.SetCurrentPositionWithoutController(ofs);
var items = reader2.ReadVUInt32();
bon = new(_reader, reader2.GetCurrentPositionWithoutController(), items, false);
return true;
}
default:
bon = new(new(), 0, 0, false);
return false;
}
}

public bool TryGetObject(out KeyedBon bon)
{
var b = _reader.PeekUInt8();
Expand Down Expand Up @@ -1282,6 +1340,21 @@ public void DumpToJson(Utf8JsonWriter writer)
writer.WriteEndArray();
break;
}
case BonType.Tuple:
{
writer.WriteStartArray();
TryGetTuple(out var ab);
if (ab.TryGet(0, out var bon))
{
while (!bon.Eof)
{
bon.DumpToJson(writer);
}
}

writer.WriteEndArray();
break;
}
case BonType.Object:
writer.WriteStartObject();
TryGetObject(out var o);
Expand Down
53 changes: 25 additions & 28 deletions BTDB/Serialization/BonSerializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -302,12 +302,10 @@ public unsafe Serialize CreateSerializerForType(Type type)
return (ref SerializerCtx ctx, ref byte value) =>
{
ref var builder = ref AsCtx(ref ctx).Builder;
builder.StartClass("Tuple"u8);
builder.WriteKey("Item1"u8);
builder.StartTuple();
serializer0(ref ctx, ref Unsafe.AddByteOffset(ref value, offsets.Item1));
builder.WriteKey("Item2"u8);
serializer1(ref ctx, ref Unsafe.AddByteOffset(ref value, offsets.Item2));
builder.FinishClass();
builder.FinishTuple();
};
}

Expand All @@ -321,12 +319,10 @@ public unsafe Serialize CreateSerializerForType(Type type)
return (ref SerializerCtx ctx, ref byte value) =>
{
ref var builder = ref AsCtx(ref ctx).Builder;
builder.StartClass("Tuple"u8);
builder.WriteKey("Item1"u8);
builder.StartTuple();
serializer0(ref ctx, ref RawData.Ref(Unsafe.As<byte, object>(ref value), offsets.Item1));
builder.WriteKey("Item2"u8);
serializer1(ref ctx, ref RawData.Ref(Unsafe.As<byte, object>(ref value), offsets.Item2));
builder.FinishClass();
builder.FinishTuple();
};
}

Expand Down Expand Up @@ -531,26 +527,11 @@ public Deserialize CreateCachedDeserializerForType(Type type)
case BonType.Class:
{
AsCtx(ref ctx).Bon.TryGetClass(out AsCtx(ref ctx).KeyedBon, out var name);
if (name.SequenceEqual("Tuple"u8))
{
var valuesBon = AsCtx(ref ctx).KeyedBon.Values();
var res = new object?[valuesBon.Items];
BonDeserializerCtx subCtx = new() { Factory = AsCtx(ref ctx).Factory, Bon = ref valuesBon };
for (var idx = 0u; idx < valuesBon.Items; idx++)
{
res[idx] = AsCtx(ref ctx).Factory.DeserializeObject(ref AsCtx(ref subCtx));
}

return res;
}
else
{
var deserializer =
((BonSerializerFactory)AsCtx(ref ctx).Factory).CreateCachedDeserializerForName(name);
object? res = null;
deserializer(ref ctx, ref Unsafe.As<object, byte>(ref res));
return res;
}
var deserializer =
((BonSerializerFactory)AsCtx(ref ctx).Factory).CreateCachedDeserializerForName(name);
object? res = null;
deserializer(ref ctx, ref Unsafe.As<object, byte>(ref res));
return res;
}
case BonType.Array:
{
Expand All @@ -566,6 +547,22 @@ public Deserialize CreateCachedDeserializerForType(Type type)

return res;
}
case BonType.Tuple:
{
AsCtx(ref ctx).Bon.TryGetArray(out var arrayBon);
arrayBon.TryGet(0, out var itemBon);
var count = arrayBon.Items;
if (count == 2)
{
BonDeserializerCtx subCtx = new() { Factory = AsCtx(ref ctx).Factory, Bon = ref itemBon };
var i0 = AsCtx(ref ctx).Factory.DeserializeObject(ref AsCtx(ref subCtx));
var i1 = AsCtx(ref ctx).Factory.DeserializeObject(ref AsCtx(ref subCtx));
var res = new Tuple<object?, object?>(i0, i1);
return res;
}

throw new NotSupportedException("Tuple with " + count + " items is not supported.");
}
case BonType.Dictionary:
{
AsCtx(ref ctx).Bon.TryGetDictionary(out var dictBon);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,26 +16,22 @@
"Float32": 3.140000104904175,
"Float64": 3.141592653589793,
"NullableFloat64": 3.141592653589793,
"ValueTupleIntLong": {
"__type__": "Tuple",
"Item1": 42,
"Item2": 4242424242
},
"ValueTupleLongString": {
"__type__": "Tuple",
"Item1": 424242424242,
"Item2": "B"
},
"ValueTupleUintUint": {
"__type__": "Tuple",
"Item1": 1,
"Item2": 2
},
"TupleLongString": {
"__type__": "Tuple",
"Item1": 123456,
"Item2": "BB"
},
"ValueTupleIntLong": [
42,
4242424242
],
"ValueTupleLongString": [
424242424242,
"B"
],
"ValueTupleUintUint": [
1,
2
],
"TupleLongString": [
123456,
"BB"
],
"Self": {
"__type__": "BTDBTest.SerializationTests.AllSupportedTypes",
"Str": null,
Expand All @@ -54,21 +50,18 @@
"Float32": 0,
"Float64": 0,
"NullableFloat64": null,
"ValueTupleIntLong": {
"__type__": "Tuple",
"Item1": 0,
"Item2": 0
},
"ValueTupleLongString": {
"__type__": "Tuple",
"Item1": 0,
"Item2": null
},
"ValueTupleUintUint": {
"__type__": "Tuple",
"Item1": 0,
"Item2": 0
},
"ValueTupleIntLong": [
0,
0
],
"ValueTupleLongString": [
0,
null
],
"ValueTupleUintUint": [
0,
0
],
"TupleLongString": null,
"Self": null,
"DoubleArray": null,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
{
"__type__": "Tuple",
"Item1": 42,
"Item2": 424242424242
}
[
42,
424242424242
]

0 comments on commit 4b1fdb0

Please sign in to comment.