Skip to content

Commit 46b75e5

Browse files
committed
Add Variant serdeProxy support
support e.g. deserializing int to Variant!(void, ProxiedInt) Side-effect: this allows us to easily implement serdeProxyCast, which is done here and supersedes the PR #22
1 parent 91bab37 commit 46b75e5

4 files changed

Lines changed: 116 additions & 41 deletions

File tree

source/mir/deser/package.d

Lines changed: 55 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import mir.small_array;
1616
import mir.small_string;
1717
import mir.utility: _expect;
1818
import std.traits: ForeachType, hasUDA, Unqual, isSomeChar, EnumMembers, TemplateArgsOf, getUDAs;
19+
import mir.ion.conv : toProxy;
1920

2021
private alias AliasSeq(T...) = T;
2122

@@ -380,7 +381,7 @@ template deserializeValue(string[] symbolTable)
380381
Temporal proxy;
381382
if (auto exception = impl(params, proxy))
382383
return exception;
383-
auto temporal = to!(serdeDeserializationMemberType!(T, member))(move(proxy));
384+
auto temporal = toProxy!(serdeDeserializationMemberType!(T, member))(move(proxy));
384385
static if (hasTransform)
385386
transform(temporal);
386387
__traits(getMember, value, member) = move(temporal);
@@ -442,6 +443,7 @@ template deserializeValue(string[] symbolTable)
442443
if (!isFirstOrderSerdeType!T)
443444
{with(params){
444445
import mir.algebraic: isVariant, isNullable;
446+
import mir.serde: ContainsProxied;
445447
import mir.internal.meta: Contains;
446448
import mir.ndslice.slice: Slice, SliceKind;
447449
import mir.rc.array: RCArray, RCI;
@@ -749,7 +751,6 @@ template deserializeValue(string[] symbolTable)
749751
return error.ionException;
750752
if (symbolId >= table.length)
751753
return IonErrorCode.symbolIdIsTooLargeForTheCurrentSymbolTable.ionException;
752-
import mir.conv: to;
753754
auto elemParams = params.withData(elem);
754755
serdeGetProxy!T temporal;
755756
if (auto exception = impl(elemParams, temporal))
@@ -774,7 +775,6 @@ template deserializeValue(string[] symbolTable)
774775
{
775776
if (error)
776777
return error.ionException;
777-
import mir.conv: to;
778778
auto elemParams = params.withData(elem);
779779
serdeGetProxy!T temporal;
780780
if (auto exception = impl(elemParams, temporal))
@@ -788,7 +788,7 @@ template deserializeValue(string[] symbolTable)
788788
if (auto exception = impl(params, temporal))
789789
return exception;
790790

791-
value = to!T(move(temporal));
791+
value = toProxy!T(move(temporal));
792792
}
793793
static if(__traits(hasMember, T, "serdeFinalize"))
794794
{
@@ -876,7 +876,26 @@ template deserializeValue(string[] symbolTable)
876876
}
877877

878878
alias Types = T.AllowedTypes;
879-
alias contains = Contains!Types;
879+
alias contains = ContainsProxied!Types;
880+
881+
pragma(inline, true) void setValue(T)(T new_value)
882+
{
883+
alias realContains = Contains!Types;
884+
static if (realContains!T)
885+
value = new_value;
886+
else
887+
{
888+
static foreach (Type; Types)
889+
{
890+
static if (is(serdeGetFinalProxy!Type == T))
891+
{
892+
Type ret = new_value.toProxy!Type;
893+
value = ret;
894+
return; // kind of unsafe: first one wins, but compiler will warn with multiple returns anyway
895+
}
896+
}
897+
}
898+
}
880899

881900
static if (getAlgebraicAnnotationsOfVariant!T.length)
882901
{
@@ -901,7 +920,7 @@ template deserializeValue(string[] symbolTable)
901920
if (auto exception = deserializeValue(annotatedParams, object))
902921
return exception;
903922
import core.lifetime: move;
904-
value = move(object);
923+
setValue(move(object));
905924
return null;
906925
}
907926
}
@@ -936,7 +955,7 @@ template deserializeValue(string[] symbolTable)
936955
if (auto exception = deserializeValue(annotatedParams, object))
937956
return exception;
938957
import core.lifetime: move;
939-
value = move(object);
958+
setValue(move(object));
940959
return null;
941960
}
942961
}
@@ -951,7 +970,7 @@ template deserializeValue(string[] symbolTable)
951970
// TODO: check that descriptor.type correspond underlaying type
952971
if (data.descriptor.L == 0xF)
953972
{
954-
value = IonNull(data.descriptor.type);
973+
setValue(IonNull(data.descriptor.type));
955974
return retNull;
956975
}
957976
}
@@ -961,7 +980,7 @@ template deserializeValue(string[] symbolTable)
961980
// TODO: check that descriptor.type correspond underlaying type
962981
if (data.descriptor.L == 0xF)
963982
{
964-
value = null;
983+
setValue(null);
965984
return retNull;
966985
}
967986
}
@@ -970,7 +989,7 @@ template deserializeValue(string[] symbolTable)
970989
T.AllowedTypes[1] payload;
971990
if (auto exception = deserializeValue(params, payload))
972991
return exception;
973-
value = payload;
992+
setValue(payload);
974993
return retNull;
975994
}
976995
else
@@ -980,7 +999,7 @@ template deserializeValue(string[] symbolTable)
980999
// {
9811000
// case IonTypeCode.null_:
9821001
// {
983-
// value = null;
1002+
// setValue(null);
9841003
// return retNull;
9851004
// }
9861005
// }
@@ -992,7 +1011,7 @@ template deserializeValue(string[] symbolTable)
9921011
bool boolean;
9931012
if (auto errorCode = data.get!bool(boolean))
9941013
return errorCode.ionException;
995-
value = boolean;
1014+
setValue(boolean);
9961015
return retNull;
9971016
}
9981017
}
@@ -1005,7 +1024,7 @@ template deserializeValue(string[] symbolTable)
10051024
string str;
10061025
if (auto exception = deserializeValue(params, str))
10071026
return exception;
1008-
value = str;
1027+
setValue(str);
10091028
return retNull;
10101029
}
10111030
}
@@ -1018,27 +1037,37 @@ template deserializeValue(string[] symbolTable)
10181037
Filter!(isSmallString, Types)[$ - 1] str; // pick the largest one
10191038
if (auto exception = deserializeValue(params, str))
10201039
return exception;
1021-
value = str;
1040+
setValue(str);
10221041
return retNull;
10231042
}
10241043
}
10251044

1026-
static if (contains!long)
1045+
enum containsIntegral = contains!short
1046+
|| contains!ushort
1047+
|| contains!int
1048+
|| contains!uint
1049+
|| contains!long
1050+
|| contains!ulong;
1051+
enum containsFloating = contains!float
1052+
|| contains!double
1053+
|| contains!real;
1054+
1055+
static if (containsIntegral)
10271056
{
10281057
case IonTypeCode.nInt:
10291058
case IonTypeCode.uInt:
10301059
{
10311060
long number;
10321061
if (auto exception = deserializeValue_(data, number))
10331062
return exception;
1034-
value = number;
1063+
setValue(number);
10351064
return retNull;
10361065
}
10371066
}
10381067

1039-
static if (contains!double)
1068+
static if (containsFloating)
10401069
{
1041-
static if (!contains!long)
1070+
static if (!containsIntegral)
10421071
{
10431072
case IonTypeCode.nInt:
10441073
case IonTypeCode.uInt:
@@ -1049,7 +1078,7 @@ template deserializeValue(string[] symbolTable)
10491078
double number;
10501079
if (auto exception = deserializeValue_(data, number))
10511080
return exception;
1052-
value = number;
1081+
setValue(number);
10531082
return retNull;
10541083
}
10551084
}
@@ -1061,7 +1090,7 @@ template deserializeValue(string[] symbolTable)
10611090
Timestamp timestamp;
10621091
if (auto error = data.trustedGet!IonTimestamp.get(timestamp))
10631092
return error.ionException;
1064-
value = timestamp;
1093+
setValue(timestamp);
10651094
return retNull;
10661095
}
10671096
}
@@ -1071,7 +1100,7 @@ template deserializeValue(string[] symbolTable)
10711100
case IonTypeCode.blob:
10721101
{
10731102
auto blob = data.trustedGet!Blob;
1074-
value = Blob(blob.data.dup);
1103+
setValue(Blob(blob.data.dup));
10751104
return retNull;
10761105
}
10771106
}
@@ -1081,7 +1110,7 @@ template deserializeValue(string[] symbolTable)
10811110
case IonTypeCode.clob:
10821111
{
10831112
auto clob = data.trustedGet!Clob;
1084-
value = Clob(clob.data.dup);
1113+
setValue(Clob(clob.data.dup));
10851114
return retNull;
10861115
}
10871116
}
@@ -1096,7 +1125,7 @@ template deserializeValue(string[] symbolTable)
10961125
if (auto exception = deserializeValue(params, array))
10971126
return exception;
10981127
import core.lifetime: move;
1099-
value = move(array);
1128+
setValue(move(array));
11001129
return retNull;
11011130
}
11021131
}
@@ -1164,7 +1193,7 @@ template deserializeValue(string[] symbolTable)
11641193
if (auto exception = deserializeValue(params, object))
11651194
return exception;
11661195
import core.lifetime: move;
1167-
value = move(object);
1196+
setValue(move(object));
11681197
return retNull;
11691198
}
11701199
}
@@ -1186,7 +1215,7 @@ template deserializeValue(string[] symbolTable)
11861215
if (auto exception = deserializeValue(params, object))
11871216
return exception;
11881217
import core.lifetime: move;
1189-
value = move(object);
1218+
setValue(move(object));
11901219
return retNull;
11911220
}
11921221
}
@@ -1202,7 +1231,7 @@ template deserializeValue(string[] symbolTable)
12021231
if (auto exception = deserializeValue(params, object))
12031232
return exception;
12041233
import core.lifetime: move;
1205-
value = move(object);
1234+
setValue(move(object));
12061235
return retNull;
12071236
}
12081237
}

source/mir/ion/conv.d

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -562,3 +562,35 @@ version(mir_ion_test) unittest
562562
])
563563
text.text2ion.ion2msgpack.msgpack2ion.ion2text.should == text;
564564
}
565+
566+
To toProxy(To, From)(auto ref scope return From v)
567+
{
568+
import std.traits : hasUDA, isImplicitlyConvertible;
569+
import mir.conv : to;
570+
import mir.deser : serdeProxyCast;
571+
static if (__traits(compiles, hasUDA!(To, serdeProxyCast)) && hasUDA!(To, serdeProxyCast))
572+
return cast(To)v;
573+
else static if (isImplicitlyConvertible!(From, To))
574+
{
575+
To ret = v;
576+
return ret;
577+
}
578+
else
579+
return to!To(v);
580+
}
581+
582+
To proxyTo(To, From)(auto ref scope return From v)
583+
{
584+
import std.traits : hasUDA, isImplicitlyConvertible;
585+
import mir.conv : to;
586+
import mir.deser : serdeProxyCast;
587+
static if (__traits(compiles, hasUDA!(From, serdeProxyCast)) && hasUDA!(From, serdeProxyCast))
588+
return cast(To)v;
589+
else static if (isImplicitlyConvertible!(From, To))
590+
{
591+
To ret = v;
592+
return ret;
593+
}
594+
else
595+
return to!To(v);
596+
}

source/mir/ion/examples.d

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1404,3 +1404,26 @@ unittest
14041404
assert((cast(Foo)6).serializeText == "6", Foo.b.serializeText);
14051405
assert("6".deserializeText!Foo == 6);
14061406
}
1407+
1408+
///
1409+
version(mir_ion_test)
1410+
unittest
1411+
{
1412+
import mir.deser.json;
1413+
import mir.algebraic_alias.json;
1414+
import mir.algebraic: Variant, Nullable;
1415+
1416+
@serdeProxy!int
1417+
struct Aliased
1418+
{
1419+
int x;
1420+
alias x this;
1421+
}
1422+
1423+
struct S
1424+
{
1425+
@serdeOptional Variant!(void, Aliased) data;
1426+
}
1427+
1428+
S s = `{"data":4}`.deserializeJson!S;
1429+
}

source/mir/ser/package.d

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import mir.ion.type_code;
1414
import mir.reflection;
1515
import std.meta;
1616
import std.traits;
17+
import mir.ion.conv : proxyTo;
1718

1819
public import mir.serde;
1920

@@ -644,24 +645,14 @@ private template serializeWithProxy(Proxy)
644645
static if (is(Proxy == const(char)[]) || is(Proxy == string) || is(Proxy == char[]))
645646
{
646647
import mir.format: stringBuf, print, getData;
647-
static if (__traits(compiles, serializeValue(serializer, stringBuf() << value << getData)))
648-
serializeValue(serializer, stringBuf() << value << getData);
648+
static if (__traits(compiles, serializeValue(serializer, stringBuf() << proxyTo!Proxy(value) << getData)))
649+
serializeValue(serializer, stringBuf() << proxyTo!Proxy(value) << getData);
649650
else
650-
{
651-
serializeValue(serializer, to!Proxy(value));
652-
}
651+
serializeValue(serializer, proxyTo!Proxy(value));
653652
}
654653
else
655654
{
656-
static if (isImplicitlyConvertible!(V, Proxy))
657-
{
658-
Proxy proxy = value;
659-
serializeValue(serializer, proxy);
660-
}
661-
else
662-
{
663-
serializeValue(serializer, to!Proxy(value));
664-
}
655+
serializeValue(serializer, proxyTo!Proxy(value));
665656
}
666657
}
667658
}
@@ -776,7 +767,7 @@ void serializeValue(S, V)(scope ref S serializer, auto ref V value)
776767
static if (__traits(compiles, value.serialize(serializer)) || !hasUDA!(V, serdeProxy))
777768
value.serialize(serializer);
778769
else
779-
serializeValue(serializer, to!(serdeGetProxy!V)(value));
770+
serializeValue(serializer, proxyTo!(serdeGetProxy!V)(value));
780771

781772
}
782773
else

0 commit comments

Comments
 (0)