Skip to content

Commit 4b1fdb0

Browse files
committed
Bon now supports Tuple natively.
1 parent c751665 commit 4b1fdb0

4 files changed

+131
-69
lines changed

BTDB/Bon/Bon.cs

+74-1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ public enum BonType
2828
Class, // 133 - VUint offset to VUint offset to VUint len + VUint offset to type name string + VUint offsets to strings, Bons*len
2929
Dictionary, // 29 - empty, 134 - VUint offset to VUint len + (Key Bon + Value Bon)*len
3030
ByteArray, // 30 - empty, 135 - VUint offset to VUint len + bytes
31+
Tuple, // 137 - VUint offset to VUint len + Bons*len (same as Array)
3132
}
3233

3334
public static class Helpers
@@ -60,6 +61,7 @@ public static class Helpers
6061
public const byte CodeByteArrayEmpty = 30;
6162
public const byte CodeByteArrayPtr = 135;
6263
public const byte CodeArraySplitBy32Ptr = 136;
64+
public const byte CodeTuplePtr = 137;
6365
// ReSharper restore InconsistentNaming
6466

6567
public static BonType BonTypeFromByte(byte b)
@@ -79,6 +81,7 @@ public static BonType BonTypeFromByte(byte b)
7981
CodeClassPtr => BonType.Class,
8082
CodeDictionaryEmpty or CodeDictionaryPtr => BonType.Dictionary,
8183
CodeByteArrayEmpty or CodeByteArrayPtr => BonType.ByteArray,
84+
CodeTuplePtr => BonType.Tuple,
8285
_ => BonType.Error
8386
};
8487
}
@@ -347,6 +350,7 @@ enum State
347350
ClassValue,
348351
DictionaryKey,
349352
DictionaryValue,
353+
Tuple
350354
};
351355

352356
State _state = State.Empty;
@@ -590,6 +594,37 @@ public void FinishArray()
590594
AfterBon();
591595
}
592596

597+
public void StartTuple()
598+
{
599+
BeforeBon();
600+
StackPush();
601+
_state = State.Tuple;
602+
}
603+
604+
public void FinishTuple()
605+
{
606+
if (_state != State.Tuple) ThrowWrongState();
607+
var items = _items;
608+
var bytes = _topData;
609+
var objKeys = _objKeys;
610+
StackPop();
611+
Debug.Assert(objKeys.Count == 0);
612+
ref var rootData = ref _topData;
613+
if (_stack.Count > 0)
614+
{
615+
rootData = ref _stack[0].Item2;
616+
}
617+
618+
var pos = rootData.GetCurrentPosition();
619+
rootData.WriteVUInt32(items);
620+
rootData.WriteBlock(bytes.GetSpan());
621+
_lastBonPos = (ulong)_topData.GetCurrentPosition();
622+
_topData.WriteUInt8(Helpers.CodeTuplePtr);
623+
_topData.WriteVUInt64((ulong)pos);
624+
625+
AfterBon();
626+
}
627+
593628
public void StartObject()
594629
{
595630
BeforeBon();
@@ -796,7 +831,8 @@ void AfterBon()
796831

797832
void BeforeBon()
798833
{
799-
if (_state is not (State.Empty or State.Array or State.ObjectValue or State.ClassValue or State.DictionaryKey
834+
if (_state is not (State.Empty or State.Array or State.Tuple or State.ObjectValue or State.ClassValue
835+
or State.DictionaryKey
800836
or State.DictionaryValue))
801837
{
802838
ThrowWrongState();
@@ -1112,6 +1148,28 @@ public bool TryGetArray(out ArrayBon bon)
11121148
}
11131149
}
11141150

1151+
public bool TryGetTuple(out ArrayBon bon)
1152+
{
1153+
var b = _reader.PeekUInt8();
1154+
switch (b)
1155+
{
1156+
case Helpers.CodeTuplePtr:
1157+
{
1158+
_reader.Skip1Byte();
1159+
_items--;
1160+
var ofs = _reader.ReadVUInt64();
1161+
var reader2 = _reader;
1162+
reader2.SetCurrentPositionWithoutController(ofs);
1163+
var items = reader2.ReadVUInt32();
1164+
bon = new(_reader, reader2.GetCurrentPositionWithoutController(), items, false);
1165+
return true;
1166+
}
1167+
default:
1168+
bon = new(new(), 0, 0, false);
1169+
return false;
1170+
}
1171+
}
1172+
11151173
public bool TryGetObject(out KeyedBon bon)
11161174
{
11171175
var b = _reader.PeekUInt8();
@@ -1282,6 +1340,21 @@ public void DumpToJson(Utf8JsonWriter writer)
12821340
writer.WriteEndArray();
12831341
break;
12841342
}
1343+
case BonType.Tuple:
1344+
{
1345+
writer.WriteStartArray();
1346+
TryGetTuple(out var ab);
1347+
if (ab.TryGet(0, out var bon))
1348+
{
1349+
while (!bon.Eof)
1350+
{
1351+
bon.DumpToJson(writer);
1352+
}
1353+
}
1354+
1355+
writer.WriteEndArray();
1356+
break;
1357+
}
12851358
case BonType.Object:
12861359
writer.WriteStartObject();
12871360
TryGetObject(out var o);

BTDB/Serialization/BonSerializer.cs

+25-28
Original file line numberDiff line numberDiff line change
@@ -302,12 +302,10 @@ public unsafe Serialize CreateSerializerForType(Type type)
302302
return (ref SerializerCtx ctx, ref byte value) =>
303303
{
304304
ref var builder = ref AsCtx(ref ctx).Builder;
305-
builder.StartClass("Tuple"u8);
306-
builder.WriteKey("Item1"u8);
305+
builder.StartTuple();
307306
serializer0(ref ctx, ref Unsafe.AddByteOffset(ref value, offsets.Item1));
308-
builder.WriteKey("Item2"u8);
309307
serializer1(ref ctx, ref Unsafe.AddByteOffset(ref value, offsets.Item2));
310-
builder.FinishClass();
308+
builder.FinishTuple();
311309
};
312310
}
313311

@@ -321,12 +319,10 @@ public unsafe Serialize CreateSerializerForType(Type type)
321319
return (ref SerializerCtx ctx, ref byte value) =>
322320
{
323321
ref var builder = ref AsCtx(ref ctx).Builder;
324-
builder.StartClass("Tuple"u8);
325-
builder.WriteKey("Item1"u8);
322+
builder.StartTuple();
326323
serializer0(ref ctx, ref RawData.Ref(Unsafe.As<byte, object>(ref value), offsets.Item1));
327-
builder.WriteKey("Item2"u8);
328324
serializer1(ref ctx, ref RawData.Ref(Unsafe.As<byte, object>(ref value), offsets.Item2));
329-
builder.FinishClass();
325+
builder.FinishTuple();
330326
};
331327
}
332328

@@ -531,26 +527,11 @@ public Deserialize CreateCachedDeserializerForType(Type type)
531527
case BonType.Class:
532528
{
533529
AsCtx(ref ctx).Bon.TryGetClass(out AsCtx(ref ctx).KeyedBon, out var name);
534-
if (name.SequenceEqual("Tuple"u8))
535-
{
536-
var valuesBon = AsCtx(ref ctx).KeyedBon.Values();
537-
var res = new object?[valuesBon.Items];
538-
BonDeserializerCtx subCtx = new() { Factory = AsCtx(ref ctx).Factory, Bon = ref valuesBon };
539-
for (var idx = 0u; idx < valuesBon.Items; idx++)
540-
{
541-
res[idx] = AsCtx(ref ctx).Factory.DeserializeObject(ref AsCtx(ref subCtx));
542-
}
543-
544-
return res;
545-
}
546-
else
547-
{
548-
var deserializer =
549-
((BonSerializerFactory)AsCtx(ref ctx).Factory).CreateCachedDeserializerForName(name);
550-
object? res = null;
551-
deserializer(ref ctx, ref Unsafe.As<object, byte>(ref res));
552-
return res;
553-
}
530+
var deserializer =
531+
((BonSerializerFactory)AsCtx(ref ctx).Factory).CreateCachedDeserializerForName(name);
532+
object? res = null;
533+
deserializer(ref ctx, ref Unsafe.As<object, byte>(ref res));
534+
return res;
554535
}
555536
case BonType.Array:
556537
{
@@ -566,6 +547,22 @@ public Deserialize CreateCachedDeserializerForType(Type type)
566547

567548
return res;
568549
}
550+
case BonType.Tuple:
551+
{
552+
AsCtx(ref ctx).Bon.TryGetArray(out var arrayBon);
553+
arrayBon.TryGet(0, out var itemBon);
554+
var count = arrayBon.Items;
555+
if (count == 2)
556+
{
557+
BonDeserializerCtx subCtx = new() { Factory = AsCtx(ref ctx).Factory, Bon = ref itemBon };
558+
var i0 = AsCtx(ref ctx).Factory.DeserializeObject(ref AsCtx(ref subCtx));
559+
var i1 = AsCtx(ref ctx).Factory.DeserializeObject(ref AsCtx(ref subCtx));
560+
var res = new Tuple<object?, object?>(i0, i1);
561+
return res;
562+
}
563+
564+
throw new NotSupportedException("Tuple with " + count + " items is not supported.");
565+
}
569566
case BonType.Dictionary:
570567
{
571568
AsCtx(ref ctx).Bon.TryGetDictionary(out var dictBon);

BTDBTest/SerializationTests/BonSerializerTest.SerializeDeserializeAllSupportedTypes.approved.txt

+28-35
Original file line numberDiff line numberDiff line change
@@ -16,26 +16,22 @@
1616
"Float32": 3.140000104904175,
1717
"Float64": 3.141592653589793,
1818
"NullableFloat64": 3.141592653589793,
19-
"ValueTupleIntLong": {
20-
"__type__": "Tuple",
21-
"Item1": 42,
22-
"Item2": 4242424242
23-
},
24-
"ValueTupleLongString": {
25-
"__type__": "Tuple",
26-
"Item1": 424242424242,
27-
"Item2": "B"
28-
},
29-
"ValueTupleUintUint": {
30-
"__type__": "Tuple",
31-
"Item1": 1,
32-
"Item2": 2
33-
},
34-
"TupleLongString": {
35-
"__type__": "Tuple",
36-
"Item1": 123456,
37-
"Item2": "BB"
38-
},
19+
"ValueTupleIntLong": [
20+
42,
21+
4242424242
22+
],
23+
"ValueTupleLongString": [
24+
424242424242,
25+
"B"
26+
],
27+
"ValueTupleUintUint": [
28+
1,
29+
2
30+
],
31+
"TupleLongString": [
32+
123456,
33+
"BB"
34+
],
3935
"Self": {
4036
"__type__": "BTDBTest.SerializationTests.AllSupportedTypes",
4137
"Str": null,
@@ -54,21 +50,18 @@
5450
"Float32": 0,
5551
"Float64": 0,
5652
"NullableFloat64": null,
57-
"ValueTupleIntLong": {
58-
"__type__": "Tuple",
59-
"Item1": 0,
60-
"Item2": 0
61-
},
62-
"ValueTupleLongString": {
63-
"__type__": "Tuple",
64-
"Item1": 0,
65-
"Item2": null
66-
},
67-
"ValueTupleUintUint": {
68-
"__type__": "Tuple",
69-
"Item1": 0,
70-
"Item2": 0
71-
},
53+
"ValueTupleIntLong": [
54+
0,
55+
0
56+
],
57+
"ValueTupleLongString": [
58+
0,
59+
null
60+
],
61+
"ValueTupleUintUint": [
62+
0,
63+
0
64+
],
7265
"TupleLongString": null,
7366
"Self": null,
7467
"DoubleArray": null,
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
{
2-
"__type__": "Tuple",
3-
"Item1": 42,
4-
"Item2": 424242424242
5-
}
1+
[
2+
42,
3+
424242424242
4+
]

0 commit comments

Comments
 (0)