From bf8215a5e85fdc51980f0fa9eb722298a2d5536d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6nke=20Ludwig?= Date: Wed, 7 Feb 2024 11:14:06 +0100 Subject: [PATCH 1/2] Fix deserialization of string based enum types. Closes #2345. This is using and extending the unit tests by @madmax-inc in #2345 and replicates the manual value-to-enum conversion with an added `NoDuplicates` to fix handling of enums with duplicate values. Fixes #2209. --- data/vibe/data/serialization.d | 53 ++++++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/data/vibe/data/serialization.d b/data/vibe/data/serialization.d index 876696b4c4..b81830d1df 100644 --- a/data/vibe/data/serialization.d +++ b/data/vibe/data/serialization.d @@ -135,7 +135,7 @@ import vibe.internal.meta.traits; import vibe.internal.meta.uda; import std.array : Appender, appender; -import std.conv : to; +import std.conv : ConvException, to; import std.exception : enforce; import std.range.primitives : ElementType, isInputRange; import std.traits; @@ -718,7 +718,13 @@ private template deserializeValueImpl(Serializer, alias Policy) { static if (hasPolicyAttributeL!(ByNameAttribute, Policy, ATTRIBUTES)) { return ser.deserializeValue!(string, ATTRIBUTES).to!T(); } else { - return cast(T)ser.deserializeValue!(OriginalType!T); + auto value = ser.deserializeValue!(OriginalType!T); + switch (value) { + default: + throw new ConvException("Unexpected enum value " ~ value.to!string); + static foreach (enumvalue; NoDuplicates!(EnumMembers!T)) + case enumvalue: return enumvalue; + } } } else static if (Serializer.isSupportedValueType!T) { return ser.readValue!(Traits, T)(); @@ -2212,3 +2218,46 @@ unittest { // issue #2110 - single-element tuples assert(serialize!TestSerializer(s) == expected); assert(deserialize!(TestSerializer, S)(expected) == s); } + +unittest { + import std.conv : ConvException; + import std.exception : assertThrown, assertNotThrown; + + enum Testable : string { + foo = "foo", + bar = "bar", + baz = "bar" + } + + Testable deserializeString(string value) { + return deserialize!(TestSerializer, Testable)("V(Aya)(" ~ value ~ ")"); + } + + foreach (string val; ["foo", "bar"]) + assert(deserializeString(val) == val.to!Testable); + + assertThrown!ConvException(deserializeString("foobar")); +} + +unittest { + import std.conv : ConvException; + import std.exception : assertThrown, assertNotThrown; + + enum Foo { + foobar + }; + + struct Testable { + @byName + Foo bar; + } + + void deserializeString(string value) { + auto d = "D(" ~ Testable.mangleof ~ ")"; + auto de = "DE(" ~ Foo.mangleof ~ ",bar)"; + deserialize!(TestSerializer, Testable)(d ~ "{" ~ de ~ "(V(Aya)(" ~ value ~ "))" ~ de ~ "}" ~ d); + } + + assertNotThrown(deserializeString("foobar")); + assertThrown!ConvException(deserializeString("baz")); +} From 3227f04b49710acd47e4b10bcbef71250634dcc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6nke=20Ludwig?= Date: Wed, 7 Feb 2024 12:17:07 +0100 Subject: [PATCH 2/2] Fix MongoDB forward compatibility issue caused by deserializing to an enum. --- mongodb/vibe/db/mongo/collection.d | 2 +- mongodb/vibe/db/mongo/connection.d | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/mongodb/vibe/db/mongo/collection.d b/mongodb/vibe/db/mongo/collection.d index 3db4358589..16dab68164 100644 --- a/mongodb/vibe/db/mongo/collection.d +++ b/mongodb/vibe/db/mongo/collection.d @@ -1477,7 +1477,7 @@ struct MaxWireVersion MaxWireVersion until(WireVersion v) @safe { return MaxWireVersion(v); } /// Unsets nullable fields not matching the server version as defined per UDAs. -void enforceWireVersionConstraints(T)(ref T field, WireVersion serverVersion, +void enforceWireVersionConstraints(T)(ref T field, int serverVersion, string file = __FILE__, size_t line = __LINE__) @safe { import std.traits : getUDAs; diff --git a/mongodb/vibe/db/mongo/connection.d b/mongodb/vibe/db/mongo/connection.d index 5cc2969662..1adac1560c 100644 --- a/mongodb/vibe/db/mongo/connection.d +++ b/mongodb/vibe/db/mongo/connection.d @@ -1120,7 +1120,7 @@ struct ServerDescription Nullable!BsonDate lastWriteDate; Nullable!BsonObjectID opTime; ServerType type = ServerType.unknown; - WireVersion minWireVersion, maxWireVersion; + int minWireVersion, maxWireVersion; string me; string[] hosts, passives, arbiters; string[string] tags; @@ -1153,7 +1153,8 @@ enum WireVersion : int v50 = 13, v51 = 14, v52 = 15, - v53 = 16 + v53 = 16, + v60 = 17 } private string getHostArchitecture()