New Upstream Release - mir-core

Ready changes

Summary

Merged new upstream version: 1.5.5 (was: 1.3.15).

Resulting package

Built on 2023-05-01T09:53 (took 11m12s)

The resulting binary packages can be installed (if you have the apt repository enabled) by running one of:

apt install -t fresh-releases libmir-core-devapt install -t fresh-releases libmir-core1-dbgsymapt install -t fresh-releases libmir-core1

Lintian Result

Diff

diff --git a/debian/changelog b/debian/changelog
index bb16b98..7bea90e 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,11 @@
+mir-core (1.5.5-1) UNRELEASED; urgency=low
+
+  * New upstream release.
+  * Drop patch 01_fix-gdc-build.patch, present upstream.
+  * New upstream release.
+
+ -- Debian Janitor <janitor@jelmer.uk>  Mon, 01 May 2023 09:43:22 -0000
+
 mir-core (1.1.111-2) unstable; urgency=medium
 
   * Add fix-gdc-build.patch: Fix build with GDC (Closes: #1018796)
diff --git a/debian/patches/01_fix-gdc-build.patch b/debian/patches/01_fix-gdc-build.patch
deleted file mode 100644
index d8ed8fa..0000000
--- a/debian/patches/01_fix-gdc-build.patch
+++ /dev/null
@@ -1,43 +0,0 @@
-From 2d4aa33510403023d75eecd81c9ba0eaaf996f00 Mon Sep 17 00:00:00 2001
-From: Matthias Klumpp <matthias@tenstral.net>
-Date: Fri, 2 Sep 2022 18:28:53 +0200
-Subject: [PATCH] meson: Allow building with gdc
-
----
- meson.build | 16 ++++++++++++----
- 1 file changed, 12 insertions(+), 4 deletions(-)
-
-diff --git a/meson.build b/meson.build
-index facbfaa..8030ecc 100644
---- a/meson.build
-+++ b/meson.build
-@@ -6,6 +6,8 @@ subprojects = []
- 
- has_cpp_headers = false
- 
-+dc = meson.get_compiler('d')
-+
- sources_list = [
-     'mir/algebraic',
-     'mir/bitmanip',
-@@ -36,10 +38,16 @@ foreach s : sources_list
-     sources += 'source/' + s + '.d'
- endforeach
- 
--add_project_arguments([
--    '-preview=dip1008',
--    '-lowmem',
--], language: 'd')
-+if dc.get_id() == 'gcc'
-+    add_project_arguments([
-+        '-fpreview=dip1008',
-+    ], language: 'd')
-+else
-+    add_project_arguments([
-+        '-preview=dip1008',
-+        '-lowmem',
-+    ], language: 'd')
-+endif
- 
- required_deps = []
- 
diff --git a/debian/patches/series b/debian/patches/series
index dc1c406..e69de29 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -1 +0,0 @@
-01_fix-gdc-build.patch
diff --git a/dub.sdl b/dub.sdl
index 7bed9ba..27f2f7d 100644
--- a/dub.sdl
+++ b/dub.sdl
@@ -8,11 +8,22 @@ license "Apache-2.0"
 buildType "unittest" {
     buildOptions "unittests" "debugMode" "debugInfo"
     versions "mir_core_test"
+}
+
+buildType "unittest-verbose" {
+    buildOptions "unittests" "debugMode" "debugInfo"
+    versions "mir_core_test"
     dflags "-checkaction=context" "-allinst"
 }
 
 buildType "unittest-dip1008" {
     buildOptions "unittests" "debugMode" "debugInfo"
     versions "mir_core_test"
-    dflags "-lowmem" "-preview=dip1008" "-checkaction=context" "-allinst"
+    dflags "-lowmem" "-preview=dip1008"
+}
+
+buildType "unittest-dip1000" {
+    buildOptions "unittests" "debugMode" "debugInfo"
+    versions "mir_core_test"
+    dflags "-lowmem" "-preview=dip1000"
 }
diff --git a/meson.build b/meson.build
index facbfaa..8030ecc 100644
--- a/meson.build
+++ b/meson.build
@@ -6,6 +6,8 @@ subprojects = []
 
 has_cpp_headers = false
 
+dc = meson.get_compiler('d')
+
 sources_list = [
     'mir/algebraic',
     'mir/bitmanip',
@@ -36,10 +38,16 @@ foreach s : sources_list
     sources += 'source/' + s + '.d'
 endforeach
 
-add_project_arguments([
-    '-preview=dip1008',
-    '-lowmem',
-], language: 'd')
+if dc.get_id() == 'gcc'
+    add_project_arguments([
+        '-fpreview=dip1008',
+    ], language: 'd')
+else
+    add_project_arguments([
+        '-preview=dip1008',
+        '-lowmem',
+    ], language: 'd')
+endif
 
 required_deps = []
 
diff --git a/source/mir/algebraic.d b/source/mir/algebraic.d
index b63ab3e..a0d9c9a 100644
--- a/source/mir/algebraic.d
+++ b/source/mir/algebraic.d
@@ -57,7 +57,6 @@ $(T2plain `void`, It is usefull to indicate a possible return type of the visito
 $(T2plain `typeof(null)`, It is usefull for nullable types. Also, it is used to indicate that a visitor can't match the current value of the algebraic. Can't be accesed by reference. )
 $(T2 This, Dummy structure that is used to construct self-referencing algebraic types. Example: `Variant!(int, double, string, This*[2])`)
 $(T2plain $(LREF SetAlias)`!setId`, Dummy structure that is used to construct cyclic-referencing lists of algebraic types. )
-$(T2 TaggedType, Dummy type used to associate tags with type. )
 $(T2 Err, Wrapper to denote an error value type. )
 $(T2 reflectErr, Attribute that denotes that the type is an error value type. )
 )
@@ -66,7 +65,6 @@ $(BOOKTABLE $(H3 $(LREF Algebraic) Traits),
 $(TR $(TH Name) $(TH Description))
 $(T2 isVariant, Checks if the type is instance of $(LREF Algebraic).)
 $(T2 isNullable, Checks if the type is instance of $(LREF Algebraic) with a self $(LREF TypeSet) that contains `typeof(null)`. )
-$(T2 isTaggedVariant, Checks if the type is instance of tagged $(LREF Algebraic).)
 $(T2 isTypeSet, Checks if the types are the same as $(LREF TypeSet) of them. )
 $(T2 ValueTypeOfNullable, Gets type of $(LI $(LREF .Algebraic.get.2)) method. )
 $(T2 SomeVariant, Gets subtype of algebraic without types for which $(LREF isErr) is true.)
@@ -78,8 +76,7 @@ $(T2 isResultVariant, Checks if T is a Variant with at least one allowed type th
 
 
 $(H3 Type Set)
-$(UL 
-$(LI $(LREF TaggedTypeSet) is supported. Example:`TargetTypeSet!(["integer", "floating"], int, double)`).
+$(UL
 $(LI Type set is unordered. Example:`TypeSet!(int, double)` and `TypeSet!(double, int)` are the same. )
 $(LI Duplicats are ignored. Example: `TypeSet!(float, int, float)` and `TypeSet!(int, float)` are the same. )
 $(LI Types are automatically unqualified if this operation can be performed implicitly. Example: `TypeSet!(const int) and `TypeSet!int` are the same. )
@@ -89,7 +86,7 @@ $(LI Empty `TypeSet!()` is allowed.)
 )
 
 $(H3 Visitors)
-$(UL 
+$(UL
 $(LI Visitors are allowed to return values of different types If there are more then one return type then the an $(LREF Algebraic) type is returned. )
 $(LI Visitors are allowed to accept additional arguments. The arguments can be passed to the visitor handler. )
 $(LI Multiple visitors can be passes to the visitor handler. )
@@ -100,7 +97,7 @@ $(LI If the visitors arguments has known types, then such visitors should be pas
 )
 
 $(H3 Implementation Features)
-$(UL 
+$(UL
 $(LI BetterC support. Runtime `TypeInfo` is not used.)
 $(LI Copy-constructors and postblit constructors are supported. )
 $(LI `toHash`, `opCmp`. `opEquals`, and `toString` support. )
@@ -126,6 +123,23 @@ module mir.algebraic;
 import mir.internal.meta;
 import mir.functional: naryFun;
 
+/++
+The attribute is used to define a permanent member field in an anlgebraic type.
+Should applied to a field of the union passed to $(LREF TaggedVariant).
++/
+enum algMeta;
+/++
+The attribute is used in pair with $(LREF algMeta) to exclude the field
+from compression in `toHash`, `opEquals`, and `opCmp` methods.
++/
+enum algTransp;
+/++
+The attribute is used in pair with $(LREF algMeta) to use the field
+as an error infomration. Usually it is a position marker in a file.
+The type should have `scope const` `toString` method.
++/
+enum algVerbose;
+
 private static immutable variantExceptionMsg = "mir.algebraic: the algebraic stores other type then requested.";
 private static immutable variantNullExceptionMsg = "mir.algebraic: the algebraic is empty and doesn't store any value.";
 private static immutable variantMemberExceptionMsg = "mir.algebraic: the algebraic stores a type that isn't compatible with the user provided visitor and arguments.";
@@ -179,7 +193,7 @@ static if (__VERSION__ >= 2_100)
     ///
     @safe pure version(mir_core_test) unittest
     {
-        struct CustomVariant
+        static struct CustomVariant
         {
             Variant!(int, string) data;
             alias data this;
@@ -190,15 +204,15 @@ static if (__VERSION__ >= 2_100)
                 return this;
             }
         }
-        
+
         static assert(isLikeVariant!(Variant!(int, string)));
         static assert(isLikeVariant!(const Variant!(int[], string)));
         static assert(isLikeVariant!(Nullable!(int, string)));
         static assert(!isLikeVariant!int);
-        
+
         static assert(!isVariant!CustomVariant);
         static assert(isLikeVariant!CustomVariant);
-        
+
         CustomVariant customVariant = 5;
         assert(customVariant.match!(
             (string s) => false,
@@ -212,14 +226,22 @@ Checks if the type is instance of tagged $(LREF Algebraic).
 
 Tagged algebraics can be defined with $(LREF TaggedVariant).
 +/
-enum bool isTaggedVariant(T) = isVariant!T && is(T.Kind == enum);
+enum bool isTaggedVariant(T) = is(immutable T == immutable Algebraic!U, U) && is(U == union);
 
 ///
 @safe pure version(mir_core_test) unittest
 {
+    static union MyUnion
+    {
+        int integer;
+        immutable(char)[] string;
+    }
+
+    alias MyAlgebraic = Algebraic!MyUnion;
+    static assert(isTaggedVariant!MyAlgebraic);
+
     static assert(!isTaggedVariant!int);
     static assert(!isTaggedVariant!(Variant!(int, string)));
-    static assert(isTaggedVariant!(TaggedVariant!(["integer", "string"], int, string)));
 }
 
 /++
@@ -279,41 +301,22 @@ Dummy type for $(LREF Variant) and $(LREF Nullable) self-referencing.
 +/
 struct This
 {
-@safe pure nothrow @nogc const:
+@safe pure nothrow @nogc scope const:
     int opCmp(typeof(this)) { return 0; }
     string toString() { return typeof(this).stringof; }
 }
 
-/++
-Dummy type used to associate tags with a type.
-+/
-struct TaggedType(T, string name)
-    if (name.length)
+private template TagInfo(T, string name, udas...)
+    if (udas.length <= 3)
 {
-    private enum tag = name;
-    private alias Type = T;
-    static if (!is(T == void) && !is(T == typeof(null)))
-        private T payload;
-@safe pure nothrow @nogc const:
-    int opCmp(ref typeof(this)) { return 0; }
-    string toString() { return typeof(this).stringof; }
+    import std.meta: staticIndexOf;
+    alias Type = T;
+    enum tag = name;
+    enum meta = staticIndexOf!(algMeta, udas) >= 0;
+    enum transparent = staticIndexOf!(algTransp, udas) >= 0;
+    enum verbose = staticIndexOf!(algVerbose, udas) >= 0;
 }
 
-/++
-Checks if `T` is $(LREF TaggedType) instance.
-+/
-enum isTaggedType(T) = is(T == TaggedType!(I, name), I, string name);
-
-/++
-Gets $(LREF TaggedType) underlying type.
-+/
-alias getTaggedTypeUnderlying(T : TaggedType!(I, name), I, string name) = I;
-
-/++
-Gets $(LREF TaggedType) tag name.
-+/
-enum getTaggedTypeName(T : TaggedType!(I, name), I, string name) = name;
-
 // example from std.variant
 /++
 $(H4 Self-Referential Types)
@@ -322,7 +325,7 @@ $(LUCKY self-referential data structures), i.e. structures that embed references
 values of their own type within.
 This is achieved with $(LREF Variant) by using $(LREF This) as a placeholder whenever a
 reference to the type being defined is needed. The $(LREF Variant) instantiation
-will perform 
+will perform
 $(LINK2 https://en.wikipedia.org/wiki/Name_resolution_(programming_languages)#Alpha_renaming_to_make_name_resolution_trivial,
 alpha renaming) on its constituent types, replacing $(LREF This)
 with the self-referenced type. The structure of the type involving $(LREF This) may
@@ -330,7 +333,7 @@ be arbitrarily complex.
 +/
 @safe pure version(mir_core_test) unittest
 {
-    import mir.functional: Tuple = RefTuple;
+    import mir.functional: Tuple;
 
     // A tree is either a leaf or a branch of two others
     alias Tree(Leaf) = Variant!(Leaf, Tuple!(This*, This*));
@@ -357,19 +360,6 @@ be arbitrarily complex.
     assert(obj.get!Map["customer"] == "John");
 }
 
-version(mir_core_test) unittest
-{
-   static struct Foo
-   {
-      ~this() @system
-      {
-      }
-   }
-   alias TFoo = TaggedType!(Foo, "foo");
-   TFoo foo;
-}
-
-
 /++
 Type set resolution template used to construct $(LREF Algebraic) .
 +/
@@ -382,13 +372,6 @@ template TypeSet(T...)
         static if (is(NoDuplicates!T == T))
             static if (staticIsSorted!(TypeCmp, T))
             {
-                static if (anySatisfy!(isTaggedType, T))
-                {
-                    import std.meta: Filter, templateNot;
-                    static assert(Filter!(templateNot!isTaggedType, T).length == 0,
-                        "Either all or none types must be tagged. Types that doesn't have tags: " ~
-                        Filter!(templateNot!isTaggedType, T).stringof);
-                }
                 alias TypeSet = T;
             }
             else
@@ -402,7 +385,7 @@ template TypeSet(T...)
 // IonNull goes first as well
 private template isIonNull(T)
 {
-    static if (is(T == TaggedType!(U, name), U, string name))
+    static if (is(T == TagInfo!(U, name), U, string name))
         enum isIonNull = .isIonNull!U;
     else
         enum isIonNull = T.stringof == "IonNull";
@@ -411,12 +394,12 @@ private template isIonNull(T)
 private template TypeCmp(A, B)
 {
     enum bool TypeCmp = is(A == B) ? false:
-    is(A == typeof(null)) || is(A == TaggedType!(typeof(null), aname), string aname) ? true:
-    is(B == typeof(null)) || is(B == TaggedType!(typeof(null), bname), string bname) ? false:
+    is(A == typeof(null)) ? true:
+    is(B == typeof(null)) ? false:
     isIonNull!A ? true:
     isIonNull!B ? false:
-    is(A == void) || is(A == TaggedType!(void, vaname), string vaname) ? true:
-    is(B == void) || is(A == TaggedType!(void, vbname), string vbname) ? false:
+    is(A == void) || is(A == TagInfo!(void, vaname), string vaname) ? true:
+    is(B == void) || is(A == TagInfo!(void, vbname), string vbname) ? false:
     A.sizeof < B.sizeof ? true:
     A.sizeof > B.sizeof ? false:
     A.mangleof < B.mangleof;
@@ -440,14 +423,9 @@ private template applyTags(string[] tagNames, T...)
     static if (tagNames.length == 0)
         alias applyTags = AliasSeq!();
     else
-        alias applyTags =  AliasSeq!(TaggedType!(T[0], tagNames[0]), .applyTags!(tagNames[1 .. $], T[1 .. $]));
+        alias applyTags =  AliasSeq!(TagInfo!(T[0], tagNames[0]), .applyTags!(tagNames[1 .. $], T[1 .. $]));
 }
 
-/++
-Type set for tagged $(LREF Variants) self-referencing.
-+/
-alias TaggedTypeSet(string[] tagNames, T...) = TypeSet!(applyTags!(tagNames, T));
-
 /++
 Checks if the type list is $(LREF TypeSet).
 +/
@@ -464,7 +442,7 @@ enum bool isTypeSet(T...) = is(T == TypeSet!T);
 /++
 Variant Type (aka Algebraic Type).
 
-The impllementation is defined as
+The implementation is defined as
 ----
 alias Variant(T...) = Algebraic!(TypeSet!T);
 ----
@@ -474,7 +452,7 @@ Compatible with BetterC mode.
 alias Variant(T...) = Algebraic!(TypeSet!T);
 
 ///
-@safe pure @nogc 
+@safe pure @nogc
 version(mir_core_test) unittest
 {
     Variant!(int, double, string) v = 5;
@@ -487,8 +465,8 @@ version(mir_core_test) unittest
 
 /// Single argument Variant
 // and Type with copy constructor
-@safe pure nothrow @nogc 
-version(mir_core_test) unittest 
+@safe pure nothrow @nogc
+version(mir_core_test) unittest
 {
     static struct S
     {
@@ -508,7 +486,7 @@ version(mir_core_test) unittest
 }
 
 /// Empty type set
-@safe pure nothrow @nogc version(mir_core_test) unittest 
+@safe pure nothrow @nogc version(mir_core_test) unittest
 {
     Variant!() a;
     auto b = a;
@@ -519,13 +497,13 @@ version(mir_core_test) unittest
 }
 
 /// Small types
-@safe pure nothrow @nogc version(mir_core_test) unittest 
+@safe pure nothrow @nogc version(mir_core_test) unittest
 {
     static struct S { ubyte d; }
     static assert(Nullable!(byte, char, S).sizeof == 2);
 }
 
-@safe pure nothrow @nogc version(mir_core_test) unittest 
+@safe pure nothrow @nogc version(mir_core_test) unittest
 {
     static struct S { ubyte[3] d; }
     static assert(Nullable!(ushort, wchar, S).sizeof == 6);
@@ -560,7 +538,6 @@ Compatible with BetterC mode.
 
 Template has two declarations:
 ----
-alias TaggedVariant(string[] tags, T...) = Variant!(applyTags!(tags, T));
 // and
 template TaggedVariant(T)
     if (is(T == union))
@@ -571,104 +548,161 @@ template TaggedVariant(T)
 
 See_also: $(LREF Variant), $(LREF isTaggedVariant).
 +/
-alias TaggedVariant(string[] tags, T...) = Variant!(applyTags!(tags, T));
-
-/// ditto
+deprecated ("Use Algebraic!Union instead")
 template TaggedVariant(T)
     if (is(T == union))
 {
-    import std.meta: staticMap;
-    enum names = __traits(allMembers, T);
-    alias TypeOf(string member) = typeof(__traits(getMember, T, member));
-    alias Types = staticMap!(TypeOf, names);
-    alias TaggedVariant = .TaggedVariant!([names], Types);
+    alias TaggedVariant = Algebraic!T;
 }
 
-/// Json Value
-@safe pure 
+/// Json Value with styles
+@safe pure
 version(mir_core_test) unittest
 {
-    static union JsonUnion
+    enum Style { block, flow }
+
+    static struct SomeMetadata {
+        int a;
+        @safe pure nothrow @nogc scope
+        int opCmp(scope const SomeMetadata rhs) const { return a - rhs.a; }
+    }
+
+    static struct ParsePosition
     {
+        string file, line, column;
+
+        void toString()(scope ref W w) scope const
+        {
+            w.put(file);
+            if (line) {
+                w.put("("); w.put(line);
+                if (column) { w.put(","); w.put(column); }
+                w.put(")");
+            }
+        }
+    }
+
+    static union Json_
+    {
+        typeof(null) null_;
+        bool boolean;
         long integer;
         double floating;
-        bool boolean;
-        typeof(null) null_;
+        // Not, that `string` is't builtin type but an alias in `object.d`
+        // So we can use `string` as a name of the string field
         immutable(char)[] string;
         This[] array;
-        This[immutable(char)[]] object;
+        // commented out to test `opCmp` primitive
+        // This[immutable(char)[]] object;
+
+    @algMeta:
+        bool active;
+        SomeMetadata metadata;
+    @algTransp:
+        Style style;
+        @algVerbose ParsePosition position;
     }
 
-    alias JsonValue = TaggedVariant!JsonUnion;
+    alias JsonAlgebraic = Algebraic!Json_;
 
     // typeof(null) has priority
-    static assert(JsonValue.Kind.init == JsonValue.Kind.null_);
-    static assert(JsonValue.Kind.null_ == 0);
-    
+    static assert(JsonAlgebraic.Kind.init == JsonAlgebraic.Kind.null_);
+    static assert(JsonAlgebraic.Kind.null_ == 0);
+
     // Kind and AllowedTypes has the same order
-    static assert (is(JsonValue.AllowedTypes[JsonValue.Kind.array] == JsonValue[]));
-    static assert (is(JsonValue.AllowedTypes[JsonValue.Kind.boolean] == bool));
-    static assert (is(JsonValue.AllowedTypes[JsonValue.Kind.floating] == double));
-    static assert (is(JsonValue.AllowedTypes[JsonValue.Kind.integer] == long));
-    static assert (is(JsonValue.AllowedTypes[JsonValue.Kind.null_] == typeof(null)));
-    static assert (is(JsonValue.AllowedTypes[JsonValue.Kind.object] == JsonValue[string]));
+    static assert (is(JsonAlgebraic.AllowedTypes[JsonAlgebraic.Kind.array] == JsonAlgebraic[]));
+    static assert (is(JsonAlgebraic.AllowedTypes[JsonAlgebraic.Kind.boolean] == bool));
+    static assert (is(JsonAlgebraic.AllowedTypes[JsonAlgebraic.Kind.floating] == double));
+    static assert (is(JsonAlgebraic.AllowedTypes[JsonAlgebraic.Kind.integer] == long));
+    static assert (is(JsonAlgebraic.AllowedTypes[JsonAlgebraic.Kind.null_] == typeof(null)));
+    // static assert (is(JsonAlgebraic.AllowedTypes[JsonAlgebraic.Kind.object] == JsonAlgebraic[string]));
 
-    JsonValue v;
-    assert(v.kind == JsonValue.Kind.null_);
+    JsonAlgebraic v;
+    assert(v.kind == JsonAlgebraic.Kind.null_);
 
     v = 1;
-    assert(v.kind == JsonValue.Kind.integer);
+    assert(v.kind == JsonAlgebraic.Kind.integer);
     assert(v == 1);
-    v = JsonValue(1);
+    v = JsonAlgebraic(1);
     assert(v == 1);
     v = v.get!(long, double);
 
     v = "Tagged!";
-    assert(v.get       !string                  == "Tagged!");
-    assert(v.trustedGet!string                  == "Tagged!");
+    // member-based access. Simple!
+    assert(v.string == "Tagged!");
+    // type-based access
+    assert(v.get!string == "Tagged!");
+    assert(v.trustedGet!string == "Tagged!");
 
-    assert(v.kind == JsonValue.Kind.string);
+    assert(v.kind == JsonAlgebraic.Kind.string);
 
     assert(v.get!"string" == "Tagged!"); // string-based get
     assert(v.trustedGet!"string" == "Tagged!"); // string-based trustedGet
 
-    assert(v.get!(JsonValue.Kind.string) == "Tagged!"); // Kind-based get
-    assert(v.trustedGet!(JsonValue.Kind.string) == "Tagged!"); // Kind-based trustedGet
+    assert(v.get!(JsonAlgebraic.Kind.string) == "Tagged!"); // Kind-based get
+    assert(v.trustedGet!(JsonAlgebraic.Kind.string) == "Tagged!"); // Kind-based trustedGet
 
-    v = [JsonValue("str"), JsonValue(4.3)];
-
-    assert(v.kind == JsonValue.Kind.array);
-    assert(v.trustedGet!(JsonValue[])[1].kind == JsonValue.Kind.floating);
+    // checks
+    assert(v._is!string); // type based
+    assert(v._is!"string"); // string based
+    assert(v._is!(JsonAlgebraic.Kind.string)); //
 
     v = null;
-    assert(v.kind == JsonValue.Kind.null_);
+    assert(v.kind == JsonAlgebraic.Kind.null_);
+
+    v = [JsonAlgebraic("str"), JsonAlgebraic(4.3)];
+
+    assert(v.kind == JsonAlgebraic.Kind.array);
+    assert(v.trustedGet!(JsonAlgebraic[])[1].kind == JsonAlgebraic.Kind.floating);
+
+    JsonAlgebraic w = v;
+    w.style = Style.flow;
+    assert(v.style != w.style);
+    assert(v == w);
+    assert(v <= w);
+    assert(v >= w);
+    assert(v.toHash == w.toHash);
+    w.active = true;
+    assert(v != w);
+    assert(v.toHash != w.toHash);
+    assert(v.get!"array" == w.get!"array");
+    assert(v < w);
+
+    // test equality with self-referencing allowed type
+    auto arr = [JsonAlgebraic("str"), JsonAlgebraic(120)];
+    v = arr;
+    assert(v == arr);
+    assert(v == [JsonAlgebraic("str"), JsonAlgebraic(120)]);
 }
 
 /// Wrapped algebraic with propogated primitives
-@safe pure 
+@safe pure
 version(mir_core_test) unittest
 {
     static struct Response
     {
-        alias Union = TaggedVariant!(
-            ["double_", "string", "array", "table"],
-            double,
-            string,
-            Response[],
-            Response[string],
-        );
+        private union Response_
+        {
+            double float_;
+            immutable(char)[] string;
+            Response[] array;
+            Response[immutable(char)[]] table;
+        }
+
+        alias ResponseAlgebraic = Algebraic!Response_;
+
+        ResponseAlgebraic data;
+        alias Tag = ResponseAlgebraic.Kind;
 
-        Union data;
-        alias Tag = Union.Kind;
         // propogates opEquals, opAssign, and other primitives
         alias data this;
 
-        static foreach (T; Union.AllowedTypes)
+        static foreach (T; ResponseAlgebraic.AllowedTypes)
             this(T v) @safe pure nothrow @nogc { data = v; }
     }
 
     Response v = 3.0;
-    assert(v.kind == Response.Tag.double_);
+    assert(v.kind == Response.Tag.float_);
     v = "str";
     assert(v == "str");
 }
@@ -676,13 +710,13 @@ version(mir_core_test) unittest
 /++
 Nullable $(LREF Variant) Type (aka Algebraic Type).
 
-The impllementation is defined as
+The implementation is defined as
 ----
 alias Nullable(T...) = Variant!(typeof(null), T);
 ----
 
 In additional to common algebraic API the following members can be accesssed:
-$(UL 
+$(UL
 $(LI $(LREF .Algebraic.isNull))
 $(LI $(LREF .Algebraic.nullify))
 $(LI $(LREF .Algebraic.get.2))
@@ -706,7 +740,7 @@ Single type `Nullable`
 version(mir_core_test) unittest
 {
     static assert(is(Nullable!int == Variant!(typeof(null), int)));
-    
+
     Nullable!int a = 5;
     assert(a.get!int == 5);
 
@@ -724,7 +758,7 @@ version(mir_core_test) unittest
 }
 
 /// Empty nullable type set support
-@safe pure nothrow @nogc version(mir_core_test) unittest 
+@safe pure nothrow @nogc version(mir_core_test) unittest
 {
     Nullable!() a;
     auto b = a;
@@ -734,22 +768,35 @@ version(mir_core_test) unittest
     static assert(typeof(a).sizeof == 1);
 }
 
+private bool contains(scope const char[][] names, scope const char[] member)
+@safe pure nothrow @nogc
+{
+    foreach (name; names)
+        if (name == member)
+            return true;
+    return false;
+}
+
 /++
 Algebraic implementation.
 For more portable code, it is higly recommeded to don't use this template directly.
 Instead, please use of $(LREF Variant) and $(LREF Nullable), which sort types.
 +/
-struct Algebraic(_Types...)
+struct Algebraic(T__...)
 {
+    import mir.internal.meta: getUDAs;
     import core.lifetime: moveEmplace;
     import mir.conv: emplaceRef;
     import mir.reflection: isPublic, hasField, isProperty;
-    import std.meta: Filter, AliasSeq, ApplyRight, anySatisfy, allSatisfy, staticMap, templateOr, templateNot;
+    import std.meta: Filter, AliasSeq, ApplyRight, anySatisfy, allSatisfy, staticMap, templateOr, templateNot, templateAnd;
     import std.traits:
         hasElaborateAssign,
         hasElaborateCopyConstructor,
         hasElaborateDestructor,
         hasMember,
+        hasUDA,
+        isAggregateType,
+        isAssociativeArray,
         isDynamicArray,
         isEqualityComparable,
         isOrderingComparable,
@@ -757,25 +804,60 @@ struct Algebraic(_Types...)
         Unqual
         ;
 
-    private enum bool _variant_test_ = is(_Types == AliasSeq!(typeof(null), double));
-
-    static if (anySatisfy!(isTaggedType, _Types))
+    static if (T__.length == 1 && is(T__[0] == union))
     {
-        private alias _UntaggedThisTypeSetList = staticMap!(getTaggedTypeUnderlying, _Types);
+        private alias UMTypeInfoOf__(immutable(char)[] member) = TagInfo!(
+            typeof(__traits(getMember, T__[0], member)),
+            member,
+            getUDAs!(T__[0], member, algMeta),
+            getUDAs!(T__[0], member, algTransp),
+            getUDAs!(T__[0], member, algVerbose),
+        );
+
+        private alias UMGetType__(alias TI) = TI.Type;
+        private enum bool UMGetMeta(alias TI) = TI.meta;
+
+        private alias AllInfo__ = staticMap!(UMTypeInfoOf__, __traits(allMembers, T__[0]));
+        private alias TypesInfo__ = Filter!(templateNot!UMGetMeta, AllInfo__);
+        private alias MetaInfo__ = Filter!(UMGetMeta, AllInfo__);
+        alias Types__ = staticMap!(UMGetType__, TypesInfo__);
+
+        /++
+        +/
+        static immutable char[][] metaFieldNames__ = () {
+            immutable(char)[][] ret;
+            foreach (T; MetaInfo__)
+                ret ~= T.tag;
+            return ret;
+        } ();
+
+        /++
+        +/
+        static immutable char[][] typeFieldNames__ = () {
+            immutable(char)[][] ret;
+            foreach (T; TypesInfo__)
+                ret ~= T.tag;
+            return ret;
+        } ();
     }
     else
     {
-        private alias _UntaggedThisTypeSetList = _Types;
+        alias Types__ = T__;
+        private alias MetaInfo__ = T__[0 .. 0];
+        enum immutable(char[][]) metaFieldNames__ = null;
+        enum immutable(char[][]) typeFieldNames__ = null;
     }
 
+    private enum bool variant_test__ = is(Types__ == AliasSeq!(typeof(null), double));
+
     /++
     Allowed types list
     See_also: $(LREF TypeSet)
     +/
-    alias AllowedTypes = AliasSeq!(ReplaceTypeUnless!(isVariant, This, Algebraic!_Types, _UntaggedThisTypeSetList));
+    alias AllowedTypes = AliasSeq!(ReplaceTypeUnless!(.isVariant, .This, Algebraic!T__, Types__));
 
     version(mir_core_test)
-    static if (_variant_test_)
+    static if (variant_test__)
     ///
     unittest
     {
@@ -797,9 +879,12 @@ struct Algebraic(_Types...)
             V*)));
     }
 
+    static foreach (i, T; MetaInfo__)
+        mixin ("MetaInfo__["  ~ i.stringof ~ "].Type " ~ T.tag ~";");
+
     private alias _Payload = Replace!(void, _Void!(), Replace!(typeof(null), _Null!(), AllowedTypes));
 
-    private static union _Storage_
+    private static union Storage__
     {
         _Payload payload;
 
@@ -812,27 +897,27 @@ struct Algebraic(_Types...)
             ubyte[Largest!_Payload.sizeof] bytes;
     }
 
-    private _Storage_ _storage_;
+    private Storage__ storage__;
 
     static if (AllowedTypes.length > 1)
     {
-        static if ((_Storage_.alignof & 1) && _Payload.length <= ubyte.max)
-            private alias _ID_ = ubyte;
+        static if ((Storage__.alignof & 1) && _Payload.length <= ubyte.max)
+            private alias ID__ = ubyte;
         else
-        static if ((_Storage_.alignof & 2) && _Payload.length <= ushort.max)
-            private alias _ID_ = ushort;
+        static if ((Storage__.alignof & 2) && _Payload.length <= ushort.max)
+            private alias ID__ = ushort;
         else
-        static if (_Storage_.alignof & 3)
-            private alias _ID_ = uint;
-        else
-            private alias _ID_ = ulong;
-    
-        _ID_ _identifier_;
+        // static if (Storage__.alignof & 3)
+            private alias ID__ = uint;
+        // else
+        //     private alias ID__ = ulong;
+
+        ID__ identifier__;
     }
     else
     {
-        alias _ID_ = uint;
-        enum _ID_ _identifier_ = 0;
+        private alias ID__ = uint;
+        enum ID__ identifier__ = 0;
     }
 
     version (D_Ddoc)
@@ -851,12 +936,12 @@ struct Algebraic(_Types...)
         enum Kind { _not_me_but_tags_name_list_ }
     }
 
-    static if (anySatisfy!(isTaggedType, _Types))
+    static if (typeFieldNames__.length)
     {
         version (D_Ddoc){}
         else
         {
-            mixin(enumKindText([staticMap!(getTaggedTypeName, _Types)]));
+            mixin(enumKindText(typeFieldNames__));
 
         }
     }
@@ -865,7 +950,7 @@ struct Algebraic(_Types...)
         version (D_Ddoc){}
         else
         {
-            alias Kind = _ID_;
+            alias Kind = ID__;
         }
     }
 
@@ -877,38 +962,38 @@ struct Algebraic(_Types...)
     +/
     Kind kind() const @safe pure nothrow @nogc @property
     {
-        assert(_identifier_ <= Kind.max);
-        return cast(Kind) _identifier_;
+        assert(identifier__ <= Kind.max);
+        return cast(Kind) identifier__;
     }
 
     static if (anySatisfy!(hasElaborateDestructor, _Payload))
     ~this() @trusted
     {
-        S: switch (_identifier_)
+        S: switch (identifier__)
         {
             static foreach (i, T; AllowedTypes)
             static if (hasElaborateDestructor!T)
             {
                 case i:
-                    (*cast(Unqual!(_Payload[i])*)&_storage_.payload[i]).__xdtor;
+                    (*cast(Unqual!(_Payload[i])*)&storage__.payload[i]).__xdtor;
                     break S;
             }
             default:
         }
         version(mir_secure_memory)
-            _storage_.bytes = 0xCC;
+            storage__.bytes = 0xCC;
     }
 
     // static if (anySatisfy!(hasOpPostMove, _Payload))
     // void opPostMove(const ref typeof(this) old)
     // {
-    //     S: switch (_identifier_)
+    //     S: switch (identifier__)
     //     {
     //         static foreach (i, T; AllowedTypes)
     //         static if (hasOpPostMove!T)
     //         {
     //             case i:
-    //                 this._storage_.payload[i].opPostMove(old._storage_.payload[i]);
+    //                 this.storage__.payload[i].opPostMove(old.storage__.payload[i]);
     //                 return;
     //         }
     //         default: return;
@@ -926,7 +1011,7 @@ struct Algebraic(_Types...)
         {
             auto length()() const @property
             {
-                switch (_identifier_)
+                switch (identifier__)
                 {
                     static foreach (i, T; AllowedTypes)
                     {
@@ -939,7 +1024,7 @@ struct Algebraic(_Types...)
 
             auto length()(size_t length) @property
             {
-                switch (_identifier_)
+                switch (identifier__)
                 {
                     static foreach (i, T; AllowedTypes)
                     {
@@ -973,7 +1058,7 @@ struct Algebraic(_Types...)
             auto opIndex()(size_t[2] index)
             {
                 auto ret = this;
-                S: switch (_identifier_)
+                S: switch (identifier__)
                 {
                     static foreach (i, T; AllowedTypes)
                     {
@@ -995,14 +1080,18 @@ struct Algebraic(_Types...)
 
     /// Construct an algebraic type from its subset.
     this(RhsTypes...)(Algebraic!RhsTypes rhs)
-        if (allSatisfy!(Contains!AllowedTypes, Algebraic!RhsTypes.AllowedTypes))
+        if (!(hasElaborateCopyConstructor!(Algebraic!T__) && is(Algebraic!RhsTypes == typeof(this)))  && allSatisfy!(Contains!AllowedTypes, Algebraic!RhsTypes.AllowedTypes))
     {
         import core.lifetime: move;
-        static if (is(RhsTypes == _Types))
+        static if (is(RhsTypes == Types__))
             this = move(rhs);
         else
         {
-            switch (rhs._identifier_)
+            static foreach (member; metaFieldNames__)
+                static if (Algebraic!RhsTypes.metaFieldNames__.contains(member))
+                    __traits(getMember, this, member) = move(__traits(getMember, rhs, member));
+
+            switch (rhs.identifier__)
             {
                 static foreach (i, T; Algebraic!RhsTypes.AllowedTypes)
                 {
@@ -1020,7 +1109,7 @@ struct Algebraic(_Types...)
     }
 
     version(mir_core_test)
-    static if (_variant_test_)
+    static if (variant_test__)
     ///
     unittest
     {
@@ -1052,21 +1141,24 @@ struct Algebraic(_Types...)
         private static union _StorageI(uint i)
         {
             _Payload[i] payload;
-            ubyte[_Storage_.bytes.length] bytes;
+            ubyte[Storage__.bytes.length] bytes;
         }
 
         static if (allSatisfy!(hasInoutConstruction, CC_AllowedTypes))
         this(return ref scope inout Algebraic rhs) inout
         {
-            static if (AllowedTypes.length > 1) this._identifier_ = rhs._identifier_;
+            static foreach (member; metaFieldNames__)
+                __traits(getMember, this, member) = __traits(getMember, rhs, member);
+
+            static if (AllowedTypes.length > 1) this.identifier__ = rhs.identifier__;
             static foreach (int i, T; AllowedTypes)
             static if (!is(T == typeof(null)) && !is(T == void))
             {
-                if (_identifier_ == i)
+                if (identifier__ == i)
                 {
                     static if (__VERSION__ < 2094)
                     {
-                        _storage_.bytes = () inout @trusted {
+                        storage__.bytes = () inout @trusted {
                             auto ret =  inout _StorageI!i(rhs.trustedGet!T);
                             return ret.bytes;
                         } ();
@@ -1074,8 +1166,8 @@ struct Algebraic(_Types...)
                     }
                     else
                     {
-                        _storage_ = () inout {
-                            mixin(`inout _Storage_ ret = { _member_` ~ i.stringof ~ ` : rhs.trustedGet!T };`);
+                        storage__ = () inout @trusted {
+                            mixin(`inout Storage__ ret = { _member_` ~ i.stringof ~ ` : rhs.trustedGet!T };`);
                             return ret;
                         } ();
                         return;
@@ -1088,14 +1180,17 @@ struct Algebraic(_Types...)
             static if (allSatisfy!(hasMutableConstruction, CC_AllowedTypes))
             this(return ref scope Algebraic rhs)
             {
-                static if (AllowedTypes.length > 1) this._identifier_ = rhs._identifier_;
+                static foreach (member; metaFieldNames__)
+                    __traits(getMember, this, member) = __traits(getMember, rhs, member);
+
+                static if (AllowedTypes.length > 1) this.identifier__ = rhs.identifier__;
                 static foreach (int i, T; AllowedTypes)
                 static if (!is(T == typeof(null)) && !is(T == void))
                 {
-                    if (_identifier_ == i)
+                    if (identifier__ == i)
                     {
-                        _storage_ = () {
-                            mixin(`_Storage_ ret = { _member_` ~ i.stringof ~ ` : rhs.trustedGet!T };`);
+                        storage__ = () {
+                            mixin(`Storage__ ret = { _member_` ~ i.stringof ~ ` : rhs.trustedGet!T };`);
                             return ret;
                         } ();
                         return;
@@ -1106,14 +1201,17 @@ struct Algebraic(_Types...)
             static if (allSatisfy!(hasConstConstruction, CC_AllowedTypes))
             this(return ref scope const Algebraic rhs) const
             {
-                static if (AllowedTypes.length > 1) this._identifier_ = rhs._identifier_;
+                static foreach (member; metaFieldNames__)
+                    __traits(getMember, this, member) = __traits(getMember, rhs, member);
+
+                static if (AllowedTypes.length > 1) this.identifier__ = rhs.identifier__;
                 static foreach (int i, T; AllowedTypes)
                 static if (!is(T == typeof(null)) && !is(T == void))
                 {
-                    if (_identifier_ == i)
+                    if (identifier__ == i)
                     {
-                        _storage_ = () const {
-                            mixin(`const _Storage_ ret = { _member_` ~ i.stringof ~ ` : rhs.trustedGet!T };`);
+                        storage__ = () const {
+                            mixin(`const Storage__ ret = { _member_` ~ i.stringof ~ ` : rhs.trustedGet!T };`);
                             return ret;
                         } ();
                         return;
@@ -1124,14 +1222,17 @@ struct Algebraic(_Types...)
             static if (allSatisfy!(hasImmutableConstruction, CC_AllowedTypes))
             this(return ref scope immutable Algebraic rhs) immutable
             {
-                static if (AllowedTypes.length > 1) this._identifier_ = rhs._identifier_;
+                static foreach (member; metaFieldNames__)
+                    __traits(getMember, this, member) = __traits(getMember, rhs, member);
+
+                static if (AllowedTypes.length > 1) this.identifier__ = rhs.identifier__;
                 static foreach (int i, T; AllowedTypes)
                 static if (!is(T == typeof(null)) && !is(T == void))
                 {
-                    if (_identifier_ == i)
+                    if (identifier__ == i)
                     {
-                        _storage_ = () immutable {
-                            mixin(`immutable _Storage_ ret = { _member_` ~ i.stringof ~ ` : rhs.trustedGet!T };`);
+                        storage__ = () immutable {
+                            mixin(`immutable Storage__ ret = { _member_` ~ i.stringof ~ ` : rhs.trustedGet!T };`);
                             return ret;
                         } ();
                         return;
@@ -1142,14 +1243,17 @@ struct Algebraic(_Types...)
             static if (allSatisfy!(hasSemiImmutableConstruction, CC_AllowedTypes))
             this(return ref scope const Algebraic rhs) immutable
             {
-                static if (AllowedTypes.length > 1) this._identifier_ = rhs._identifier_;
+                static foreach (member; metaFieldNames__)
+                    __traits(getMember, this, member) = __traits(getMember, rhs, member);
+
+                static if (AllowedTypes.length > 1) this.identifier__ = rhs.identifier__;
                 static foreach (int i, T; AllowedTypes)
                 static if (!is(T == typeof(null)) && !is(T == void))
                 {
-                    if (_identifier_ == i)
+                    if (identifier__ == i)
                     {
-                        _storage_ = () const {
-                            mixin(`immutable _Storage_ ret = { _member_` ~ i.stringof ~ ` : rhs.trustedGet!T };`);
+                        storage__ = () const {
+                            mixin(`immutable Storage__ ret = { _member_` ~ i.stringof ~ ` : rhs.trustedGet!T };`);
                             return ret;
                         } ();
                         return;
@@ -1160,14 +1264,17 @@ struct Algebraic(_Types...)
             static if (allSatisfy!(hasSemiMutableConstruction, CC_AllowedTypes))
             this(return ref scope const Algebraic rhs)
             {
-                static if (AllowedTypes.length > 1) this._identifier_ = rhs._identifier_;
+                static foreach (member; metaFieldNames__)
+                    __traits(getMember, this, member) = __traits(getMember, rhs, member);
+
+                static if (AllowedTypes.length > 1) this.identifier__ = rhs.identifier__;
                 static foreach (int i, T; AllowedTypes)
                 static if (!is(T == typeof(null)) && !is(T == void))
                 {
-                    if (_identifier_ == i)
+                    if (identifier__ == i)
                     {
-                        _storage_ = () const {
-                            mixin(`const _Storage_ ret = { _member_` ~ i.stringof ~ ` : rhs.trustedGet!T };`);
+                        storage__ = () const {
+                            mixin(`const Storage__ ret = { _member_` ~ i.stringof ~ ` : rhs.trustedGet!T };`);
                             return ret;
                         } ();
                         return;
@@ -1179,55 +1286,189 @@ struct Algebraic(_Types...)
 
     /++
     +/
-    size_t toHash() @trusted nothrow const
+    static if (typeFieldNames__.length)
+    size_t toHash() scope @trusted const pure nothrow @nogc
     {
+        size_t hash;
+
+
         static if (AllowedTypes.length == 0 || is(AllowedTypes == AliasSeq!(typeof(null))))
         {
-            return 0;
         }
-        else
-        switch (_identifier_)
+        else{S:
+        switch (identifier__)
         {
+            import std.traits: isArray;
             static foreach (i, T; AllowedTypes)
             {
-                case i:
+                case i: {
                     static if (is(T == void))
-                        return i;
+                        hash = i;
                     else
                     static if (is(T == typeof(null)))
-                        return i;
+                        hash = i;
+                    else
+                    static if (typeFieldNames__.length) // force for tagged types
+                    {
+                        static if (__traits(hasMember, T, "toHash"))
+                            hash = trustedGet!T.toHash;
+                        else
+                        static if (isArray!T)
+                            foreach (ref e; trustedGet!T)
+                                static if (__traits(hasMember, typeof(e), "toHash"))
+                                    hash = hashOf(e.toHash, hash);
+                                else
+                                    hash = hashOf(e, hash);
+                        else
+                            hash = hashOf(trustedGet!T);
+                    }
                     else
-                    static if (__traits(compiles, hashOf(trustedGet!T, cast(size_t)i)))
-                        return hashOf(trustedGet!T, cast(size_t)i);
+                    static if (__traits(compiles, hashOf(trustedGet!T.hashOf, i ^ hash)))
+                        hash = hashOf(trustedGet!T.hashOf, i ^ hash);
                     else
                     {
-                        debug pragma(msg, "Mir warning: can't compute hash of " ~ (const T).stringof);
-                        return i;
+                        debug pragma(msg, "Mir warning: couldn't compute hash. Expected a `size_t toHash() scope @safe const pure nothrow @nogc` method for " ~ T.stringof);
+                        hash = i;
                     }
+                    break S;
+                }
             }
             default: assert(0);
+        }}
+
+        static foreach (i, T; MetaInfo__)
+        static if (!T.transparent)
+        {
+            static if (is(MetaFieldsTypes[i] == class) || is(MetaFieldsTypes[i] == interface))
+            {{
+                scope eqfun = delegate() {
+                    hash = hashOf(__traits(getMember, this, T.tag), hash);
+                };
+                trustedAllAttr(eqfun)();
+            }}
+            else
+                hash = hashOf(__traits(getMember, this, T.tag), hash);
         }
+        return hash;
     }
+    else
+    size_t toHash() const scope @trusted nothrow
+    {
+        size_t hash;
 
-    /++
-    +/
-    bool opEquals()(auto ref const typeof(this) rhs) const @trusted
+
+        static if (AllowedTypes.length == 0 || is(AllowedTypes == AliasSeq!(typeof(null))))
+        {
+        }
+        else{S:
+        switch (identifier__)
+        {
+            import std.traits: isArray;
+            static foreach (i, T; AllowedTypes)
+            {
+                case i: {
+                    static if (is(T == void))
+                        hash = i;
+                    else
+                    static if (is(T == typeof(null)))
+                        hash = i;
+                    else
+                    static if (typeFieldNames__.length) // force for tagged types
+                    {
+                        static if (__traits(hasMember, T, "toHash"))
+                            hash = trustedGet!T.toHash;
+                        else
+                        static if (isArray!T)
+                            foreach (ref e; trustedGet!T)
+                                static if (__traits(hasMember, typeof(e), "toHash"))
+                                    hash = hashOf(e.toHash, hash);
+                                else
+                                    hash = hashOf(e, hash);
+                        else
+                            hash = hashOf(trustedGet!T);
+                    }
+                    else
+                    static if (__traits(compiles, hashOf(trustedGet!T.hashOf, i ^ hash)))
+                        hash = hashOf(trustedGet!T.hashOf, i ^ hash);
+                    else
+                    {
+                        debug pragma(msg, "Mir warning: can't compute hash. Expexted `size_t toHash() scope @safe const pure nothrow @nogc` method for " ~ T.stringof);
+                        hash = i;
+                    }
+                    break S;
+                }
+            }
+            default: assert(0);
+        }}
+
+        static foreach (i, T; MetaInfo__)
+        static if (!T.transparent)
+        {
+            static if (is(MetaFieldsTypes[i] == class) || is(MetaFieldsTypes[i] == interface))
+            {{
+                scope eqfun = delegate() {
+                    hash = hashOf(__traits(getMember, this, T.tag), hash);
+                };
+                trustedAllAttr(eqfun)();
+            }}
+            else
+                hash = hashOf(__traits(getMember, this, T.tag), hash);
+        }
+        return hash;
+    }
+
+
+    ///
+    bool opEquals()(scope const Algebraic rhs) scope @trusted const pure nothrow @nogc
+    {
+        return opEquals(rhs);
+    }
+
+    /// ditto
+    bool opEquals()(scope ref const Algebraic rhs) scope @trusted const pure nothrow @nogc
     {
+        static foreach (i, T; MetaInfo__)
+        static if (!T.transparent)
+        {
+            static if (is(MetaFieldsTypes[i] == class) || is(MetaFieldsTypes[i] == interface))
+            {{
+                scope eqfun = delegate() {
+                    return __traits(getMember, this, T.tag) != __traits(getMember, rhs, T.tag);
+                };
+                if (trustedAllAttr(eqfun)())
+                    return false;
+            }}
+            else
+                if (__traits(getMember, this, T.tag) != __traits(getMember, rhs, T.tag))
+                    return false;
+        }
+
         static if (AllowedTypes.length == 0)
         {
             return true;
         }
         else
         {
-            if (this._identifier_ != rhs._identifier_)
+            if (this.identifier__ != rhs.identifier__)
                 return false;
-            switch (_identifier_)
+            switch (identifier__)
             {
                 static foreach (i, T; AllowedTypes)
                 {
                     case i:
                         static if (is(T == void))
                             return rhs._is!void;
+                        else
+                        static if (is(T == class) || is(T == interface))
+                        {{
+                            scope eqfun = delegate() {
+                                return this.trustedGet!T == rhs.trustedGet!T;
+                            };
+                            return trustedAllAttr(eqfun)();
+                        }}
+                        else
+                        static if (__traits(isFloating, T))
+                            return this.trustedGet!T == rhs.trustedGet!T || (this.trustedGet!T != this.trustedGet!T && rhs.trustedGet!T != rhs.trustedGet!T);
                         else
                             return this.trustedGet!T == rhs.trustedGet!T;
                 }
@@ -1238,42 +1479,130 @@ struct Algebraic(_Types...)
 
     /++
     +/
-    static if (is(AllowedTypes == _Types))
-    auto opCmp()(auto ref const typeof(this) rhs) const @trusted
+    static if (!anySatisfy!(templateOr!(isAssociativeArray, templateAnd!(isAggregateType, templateNot!hasOpCmp)), staticMap!(basicElementType, AllowedTypes)))
+    {
+    static if (typeFieldNames__.length)
+    int opCmp()(auto ref scope const typeof(this) rhs) scope @trusted const pure nothrow @nogc
     {
+        static foreach (i, T; MetaInfo__)
+        static if (!T.transparent)
+        {
+            static if (__traits(compiles, __cmp(__traits(getMember, this, T.tag), __traits(getMember, rhs, T.tag))))
+            {
+                if (auto d = __cmp(__traits(getMember, this, T.tag), __traits(getMember, rhs, T.tag)))
+                    return d;
+            }
+            else
+            static if (__traits(hasMember, __traits(getMember, this, T.tag), "opCmp") && !is(MetaFieldsTypes[i] == U*, U))
+            {
+                if (auto d = __traits(getMember, this, T.tag).opCmp(__traits(getMember, rhs, T.tag)))
+                    return d;
+            }
+            else
+            {
+                if (auto d = __traits(getMember, this, T.tag) < __traits(getMember, rhs, T.tag) ? -1 : __traits(getMember, this, T.tag) > __traits(getMember, rhs, T.tag) ? +1 : 0)
+                    return d;
+            }
+        }
+
+
         static if (AllowedTypes.length == 0)
         {
             return 0;
         }
         else
         {
-            import mir.internal.utility: isFloatingPoint;
-            if (auto d = int(this._identifier_) - int(rhs._identifier_))
+            import std.traits: isArray;
+            if (auto d = int(this.identifier__) - int(rhs.identifier__))
                 return d;
-            switch (_identifier_)
+            import std.traits: isArray, isPointer;
+            switch (identifier__)
             {
                 static foreach (i, T; AllowedTypes)
                 {
                     case i:
-                        static if (__traits(compiles, __cmp(trustedGet!T, rhs.trustedGet!T)))
-                            return __cmp(trustedGet!T, rhs.trustedGet!T);
+                        static if (__traits(hasMember, T, "opCmp") && !isPointer!T)
+                        {{
+                            auto ret = this.trustedGet!T.opCmp(rhs.trustedGet!T);
+                            static if (is(typeof(ret) == int))
+                                return ret;
+                            else
+                                return ret < 0 ? -1 : ret > 0 ? 1 : 0;
+                        }}
+                        else
+                        static if (!isArray!T)
+                            return this.trustedGet!T < rhs.trustedGet!T ? -1 :
+                                this.trustedGet!T > rhs.trustedGet!T ? +1 : 0;
                         else
-                        static if (__traits(hasMember, T, "opCmp") && !is(T == U*, U))
-                            return this.trustedGet!T.opCmp(rhs.trustedGet!T);
+                            return __cmp(trustedGet!T, rhs.trustedGet!T);
+                }
+                default: assert(0);
+            }
+        }
+    }
+    else
+    int opCmp()(auto ref scope const typeof(this) rhs) scope @trusted const //pure nothrow @nogc
+    {
+        static foreach (i, T; MetaInfo__)
+        static if (!T.transparent)
+        {
+            static if (__traits(compiles, __cmp(__traits(getMember, this, T.tag), __traits(getMember, rhs, T.tag))))
+            {
+                if (auto d = __cmp(__traits(getMember, this, T.tag), __traits(getMember, rhs, T.tag)))
+                    return d;
+            }
+            else
+            static if (__traits(hasMember, __traits(getMember, this, T.tag), "opCmp") && !is(MetaFieldsTypes[i] == U*, U))
+            {
+                if (auto d = __traits(getMember, this, T.tag).opCmp(__traits(getMember, rhs, T.tag)))
+                    return d;
+            }
+            else
+            {
+                if (auto d = __traits(getMember, this, T.tag) < __traits(getMember, rhs, T.tag) ? -1 : __traits(getMember, this, T.tag) > __traits(getMember, rhs, T.tag) ? +1 : 0)
+                    return d;
+            }
+        }
+
+
+        static if (AllowedTypes.length == 0)
+        {
+            return 0;
+        }
+        else
+        {
+            import std.traits: isArray;
+            if (auto d = int(this.identifier__) - int(rhs.identifier__))
+                return d;
+            import std.traits: isArray, isPointer;
+            switch (identifier__)
+            {
+                static foreach (i, T; AllowedTypes)
+                {
+                    case i:
+                        static if (__traits(hasMember, T, "opCmp") && !isPointer!T)
+                        {{
+                            auto ret = this.trustedGet!T.opCmp(rhs.trustedGet!T);
+                            static if (is(typeof(ret) == int))
+                                return ret;
+                            else
+                                return ret < 0 ? -1 : ret > 0 ? 1 : 0;
+                        }}
                         else
-                        // static if (isFloatingPoint!T)
-                        //     return trustedGet!T == rhs ? 0 : trustedGet!T - rhs.trustedGet!T;
-                        // else
+                        static if (!isArray!T)
                             return this.trustedGet!T < rhs.trustedGet!T ? -1 :
                                 this.trustedGet!T > rhs.trustedGet!T ? +1 : 0;
+                        else
+                            return __cmp(trustedGet!T, rhs.trustedGet!T);
                 }
                 default: assert(0);
             }
         }
     }
+    }
 
     /// Requires mir-algorithm package
-    string toString()() const
+    immutable(char)[] toString()() @trusted scope const
     {
         static if (AllowedTypes.length == 0)
         {
@@ -1282,22 +1611,34 @@ struct Algebraic(_Types...)
         else
         {
             import mir.conv: to;
-            switch (_identifier_)
+            immutable(char)[] ret;
+            static foreach (i, member; metaFieldNames__)
+            static if (!MetaInfo__[i].transparent)
+            {
+                static if (__traits(compiles, { auto s = to!(immutable(char)[])(__traits(getMember, this, member));}))
+                    // should be passed by value to workaround compiler bug
+                    ret ~= to!(immutable(char)[])(__traits(getMember, this, member));
+                else
+                    ret ~= AllowedTypes[i].stringof;
+                ret ~= "::";
+            }
+            switch (identifier__)
             {
                 static foreach (i, T; AllowedTypes)
                 {
                     case i:
                         static if (is(T == void))
-                            return "void";
+                            ret ~= "void";
                         else
                         static if (is(T == typeof(null)))
-                            return "null";
+                            ret ~= "null";
                         else
-                        static if (__traits(compiles, { auto s = to!string(trustedGet!T);}))
+                        static if (__traits(compiles, { auto s = to!(immutable(char)[])(trustedGet!T);}))
                             // should be passed by value to workaround compiler bug
-                            return to!string((()=>trustedGet!T)());
+                            ret ~= to!(immutable(char)[])(trustedGet!T);
                         else
-                            return AllowedTypes[i].stringof;
+                            ret ~= AllowedTypes[i].stringof;
+                        return ret;
                 }
                 default: assert(0);
             }
@@ -1305,27 +1646,40 @@ struct Algebraic(_Types...)
     }
 
     ///ditto
-    void toString(W)(scope ref W w) const
+    void toString(W)(ref scope W w) scope const @trusted pure
+        if (__traits(compiles, ()pure{ w.put("Algebraic"); }))
     {
+        if (false)
+            return w.put("Algebraic");
         static if (AllowedTypes.length == 0)
         {
             return w.put("Algebraic");
         }
         else
         {
-            switch (_identifier_)
+            import mir.format: print;
+            static foreach (i, member; metaFieldNames__)
+            static if (!MetaInfo__[i].transparent)
+            {
+                static if (__traits(compiles, { import mir.format: print; print(w, __traits(getMember, this, member)); }))
+                    { import mir.format: print; print(w, __traits(getMember, this, member)); }
+                else
+                    w.put(AllowedTypes[i].stringof);
+                w.put("::");
+            }
+            switch (identifier__)
             {
                 static foreach (i, T; AllowedTypes)
                 {
                     case i:
                         static if (is(T == void))
-                            return w.put("void");
+                            w.put("void");
                         else
                         static if (is(T == typeof(null)))
-                            return w.put("null");
+                            w.put("null");
                         else
                         static if (__traits(compiles, { import mir.format: print; print(w, trustedGet!T); }))
-                            { import mir.format: print; print(w, trustedGet!T); }
+                            toStringImpl!T(w);
                         else
                             w.put(AllowedTypes[i].stringof);
                         return;
@@ -1335,13 +1689,55 @@ struct Algebraic(_Types...)
         }
     }
 
+    ///ditto
+    void toString(W)(ref scope W w) scope const @trusted
+        if (!__traits(compiles, ()pure{ w.put("Algebraic"); }))
+    {
+        if (false)
+            return w.put("Algebraic");
+        static if (AllowedTypes.length == 0)
+        {
+            return w.put("Algebraic");
+        }
+        else
+        {
+            switch (identifier__)
+            {
+                static foreach (i, T; AllowedTypes)
+                {
+                    case i:
+                        static if (is(T == void))
+                            return w.put("void");
+                        else
+                        static if (is(T == typeof(null)))
+                            return w.put("null");
+                        else
+                        static if (__traits(compiles, { import mir.format: print; print(w, trustedGet!T); }))
+                            return toStringImpl!T(w);
+                        else
+                            return w.put(AllowedTypes[i].stringof);
+                }
+                default: assert(0);
+            }
+        }
+    }
+
+    private void toStringImpl(T, W)(ref scope W w)  @safe scope const pure nothrow @nogc
+    {
+        import mir.format: print;
+        scope pfun = delegate() {
+            print(w, trustedGet!T);
+        };
+        trustedAllAttr(pfun)();
+    }
+
     static if (is(AllowedTypes[0] == typeof(null)))
     {
         ///
         bool opCast(C)() const
             if (is(C == bool))
         {
-            return _identifier_ != 0;
+            return identifier__ != 0;
         }
 
         ///
@@ -1352,24 +1748,23 @@ struct Algebraic(_Types...)
         }
 
         /// Defined if the first type is `typeof(null)`
-        bool isNull() const @property { return _identifier_ == 0; }
+        bool isNull() const @property { return identifier__ == 0; }
         /// ditto
         void nullify() { this = null; }
 
         /// ditto
         auto get()()
-            if (allSatisfy!(isCopyable, AllowedTypes[1 .. $]) && AllowedTypes.length != 2)
+            if (allSatisfy!(isCopyable, AllowedTypes[1 .. $]) && AllowedTypes.length != 2 && is(AllowedTypes[0] == typeof(null)))
         {
             import mir.utility: _expect;
-            if (_expect(!_identifier_, false))
+            if (_expect(!identifier__, false))
             {
                 throw variantNullException;
             }
             static if (AllowedTypes.length != 2)
             {
-                Algebraic!(_Types[1 .. $]) ret;
-
-                S: switch (_identifier_)
+                Algebraic!(AllowedTypes[1 .. $]) ret;
+                S: switch (identifier__)
                 {
                     static foreach (i, T; AllowedTypes[1 .. $])
                     {
@@ -1377,14 +1772,17 @@ struct Algebraic(_Types...)
                             case i + 1:
                                 if (!hasElaborateCopyConstructor!T && !__ctfe)
                                     goto default;
-                                ret = this.trustedGet!T;
+                                static if (is(T == void))
+                                    ret = ret._void;
+                                else
+                                    ret = this.trustedGet!T;
                                 break S;
                         }
                     }
                     default:
-                        ret._storage_.bytes = this._storage_.bytes;
+                        ret.storage__.bytes = this.storage__.bytes;
                         static if (ret.AllowedTypes.length > 1)
-                            ret._identifier_ = cast(typeof(ret._identifier_))(this._identifier_ - 1);
+                            ret.identifier__ = cast(typeof(ret.identifier__))(this.identifier__ - 1);
                 }
                 return ret;
             }
@@ -1396,24 +1794,24 @@ struct Algebraic(_Types...)
             Gets the value if not null. If `this` is in the null state, and the optional
             parameter `fallback` was provided, it will be returned. Without `fallback`,
             calling `get` with a null state is invalid.
-        
+
             When the fallback type is different from the Nullable type, `get(T)` returns
             the common type.
-        
+
             Params:
                 fallback = the value to return in case the `Nullable` is null.
-        
+
             Returns:
                 The value held internally by this `Nullable`.
             +/
             auto ref inout(AllowedTypes[1]) get() return inout
             {
-                assert(_identifier_, "Called `get' on null Nullable!(" ~ AllowedTypes[1].stringof ~ ").");
+                assert(identifier__, "Called `get' on null Nullable!(" ~ AllowedTypes[1].stringof ~ ").");
                 return trustedGet!(AllowedTypes[1]);
             }
 
             version(mir_core_test)
-            static if (_variant_test_)
+            static if (variant_test__)
             ///
             @safe pure nothrow @nogc
             unittest
@@ -1444,7 +1842,7 @@ struct Algebraic(_Types...)
     bool _is(R : Algebraic!RetTypes, RetTypes...)() @safe pure nothrow @nogc const @property
         if (allSatisfy!(Contains!AllowedTypes, Algebraic!RetTypes.AllowedTypes))
     {
-        static if (is(RetTypes == _Types))
+        static if (is(RetTypes == Types__))
             return true;
         else
         {
@@ -1453,7 +1851,7 @@ struct Algebraic(_Types...)
             alias RhsAllowedTypes = Algebraic!RetTypes.AllowedTypes;
             alias Ret = CopyTypeQualifiers!(This, Algebraic!RetTypes);
             // uint rhsTypeId;
-            switch (_identifier_)
+            switch (identifier__)
             {
                 foreach (i, T; AllowedTypes)
                 static if (staticIndexOf!(T, RhsAllowedTypes) >= 0)
@@ -1480,7 +1878,7 @@ struct Algebraic(_Types...)
     auto ref trustedGet(R : Algebraic!RetTypes, this This, RetTypes...)() return @property
         if (allSatisfy!(Contains!AllowedTypes, Algebraic!RetTypes.AllowedTypes))
     {
-        static if (is(RetTypes == _Types))
+        static if (is(RetTypes == Types__))
             return this;
         else
         {
@@ -1489,7 +1887,7 @@ struct Algebraic(_Types...)
             alias RhsAllowedTypes = Algebraic!RetTypes.AllowedTypes;
             alias Ret = CopyTypeQualifiers!(This, Algebraic!RetTypes);
             // uint rhsTypeId;
-            switch (_identifier_)
+            switch (identifier__)
             {
                 foreach (i, T; AllowedTypes)
                 static if (staticIndexOf!(T, RhsAllowedTypes) >= 0)
@@ -1518,7 +1916,7 @@ struct Algebraic(_Types...)
     }
 
     version(mir_core_test)
-    static if (_variant_test_)
+    static if (variant_test__)
     ///
     @safe pure nothrow @nogc
     unittest
@@ -1541,12 +1939,12 @@ struct Algebraic(_Types...)
         assert(integer == 12L);
     }
 
-    static if (anySatisfy!(isTaggedType, _Types))
+    static if (typeFieldNames__.length)
     {
         /// `trustedGet` overload that accept $(LREF .Algebraic.Kind).
         alias trustedGet(Kind kind) = trustedGet!(AllowedTypes[kind]);
         /// ditto
-        alias trustedGet(string kind) = trustedGet!(__traits(getMember, Kind, kind));
+        alias trustedGet(immutable(char)[] kind) = trustedGet!(__traits(getMember, Kind, kind));
     }
 
     /++
@@ -1557,7 +1955,7 @@ struct Algebraic(_Types...)
     auto ref get(R : Algebraic!RetTypes, this This, RetTypes...)() return @property
         if (allSatisfy!(Contains!AllowedTypes, Algebraic!RetTypes.AllowedTypes))
     {
-        static if (is(RetTypes == _Types))
+        static if (is(RetTypes == Types__))
             return this;
         else
         {
@@ -1566,7 +1964,7 @@ struct Algebraic(_Types...)
             alias RhsAllowedTypes = Algebraic!RetTypes.AllowedTypes;
             alias Ret = CopyTypeQualifiers!(This, Algebraic!RetTypes);
             // uint rhsTypeId;
-            switch (_identifier_)
+            switch (identifier__)
             {
                 foreach (i, T; AllowedTypes)
                 static if (staticIndexOf!(T, RhsAllowedTypes) >= 0)
@@ -1595,7 +1993,7 @@ struct Algebraic(_Types...)
     }
 
     version(mir_core_test)
-    static if (_variant_test_)
+    static if (variant_test__)
     ///
     @safe pure @nogc
     unittest
@@ -1616,12 +2014,20 @@ struct Algebraic(_Types...)
         assert(integer == 12L);
     }
 
-    static if (anySatisfy!(isTaggedType, _Types))
+    static if (typeFieldNames__.length)
     {
         /// `get` overload that accept $(LREF .Algebraic.Kind).
         alias get(Kind kind) = get!(AllowedTypes[kind]);
         /// ditto
-        alias get(string kind) = get!(__traits(getMember, Kind, kind));
+        alias get(immutable(char)[] kind) = get!(__traits(getMember, Kind, kind));
+
+        /// `_is` overload that accept $(LREF .Algebraic.Kind).
+        alias _is(Kind kind) = _is!(AllowedTypes[kind]);
+        /// ditto
+        alias _is(immutable(char)[] kind) = _is!(__traits(getMember, Kind, kind));
+
+        static foreach (member; typeFieldNames__)
+            mixin ("alias " ~ member ~ `() = get!"` ~ member ~ `";`);
     }
 
     private alias _ReflectionTypes = AllowedTypes[is(AllowedTypes[0] == typeof(null)) .. $];
@@ -1654,30 +2060,10 @@ struct Algebraic(_Types...)
     {
         static foreach (member; AllMembersRec!(_ReflectionTypes[0]))
         static if (
-            member != "_ID_" &&
-            member != "_identifier_" &&
-            member != "_is" &&
-            member != "_storage_" &&
-            member != "_Storage_" &&
-            member != "_variant_test_" &&
-            member != "_void" &&
-            member != "AllowedTypes" &&
-            member != "get" &&
-            member != "isNull" &&
-            member != "kind" &&
-            member != "Kind" &&
-            member != "nullify" &&
-            member != "opAssign" &&
-            member != "opCast" &&
-            member != "opCmp" &&
-            member != "opEquals" &&
-            member != "opPostMove" &&
-            member != "toHash" &&
-            member != "toString" &&
-            member != "trustedGet" &&
-            member != "deserializeFromAsdf" &&
-            member != "deserializeFromIon" &&
-            !(member.length >= 2 && member[0 .. 2] == "__"))
+            !.algebraicMembers.contains(member) &&
+            !metaFieldNames__.contains(member) &&
+            !typeFieldNames__.contains(member) &&
+            !(member.length >= 2 && (member[0 .. 2] == "__" || member[$ - 2 .. $] == "__")))
         static if (allSatisfy!(ApplyRight!(hasMember, member), _ReflectionTypes))
         static if (!anySatisfy!(ApplyRight!(isMemberType, member), _ReflectionTypes))
         static if (allSatisfy!(ApplyRight!(isSingleMember, member), _ReflectionTypes))
@@ -1701,29 +2087,30 @@ struct Algebraic(_Types...)
 
     ///
     ref opAssign(RhsTypes...)(Algebraic!RhsTypes rhs) return @trusted
-        if (RhsTypes.length < AllowedTypes.length && allSatisfy!(Contains!AllowedTypes, Algebraic!RhsTypes.AllowedTypes))
+        if (allSatisfy!(Contains!AllowedTypes, Algebraic!RhsTypes.AllowedTypes) && !is(Algebraic == Algebraic!RhsTypes))
     {
         import core.lifetime: forward;
-        static if (anySatisfy!(hasElaborateDestructor, AllowedTypes))
-            this.__dtor();
+        this = this.init;
         __ctor(forward!rhs);
         return this;
     }
 
+    // pragma(msg, AllowedTypes);
+
     static foreach (int i, T; AllowedTypes)
     {
         /// Zero cost always nothrow `get` alternative
         auto ref trustedGet(E)() @trusted @property return inout nothrow
             if (is(E == T))
         {
-            assert (i == _identifier_);
+            assert (i == identifier__);
             static if (is(T == typeof(null)))
                 return null;
             else
             static if (is(T == void))
                 return;
             else
-                return _storage_.payload[i];
+                return storage__.payload[i];
         }
 
         /++
@@ -1735,7 +2122,7 @@ struct Algebraic(_Types...)
             import mir.utility: _expect;
             static if (AllowedTypes.length > 1)
             {
-                if (_expect(i != _identifier_, false))
+                if (_expect(i != identifier__, false))
                 {
                     throw variantException;
                 }
@@ -1749,7 +2136,7 @@ struct Algebraic(_Types...)
         bool _is(E)() const @property nothrow @nogc
             if (is(E == T))
         {
-            return _identifier_ == i;
+            return identifier__ == i;
         }
 
         static if (is(T == void))
@@ -1758,12 +2145,12 @@ struct Algebraic(_Types...)
             static Algebraic _void()
             {
                 Algebraic ret;
-                ret._storage_ = () {
+                ret.storage__ = () {
                     import core.lifetime: forward;
-                    mixin(`_Storage_ ret = { _member_` ~ i.stringof ~ ` : _Void!().init };`);
+                    mixin(`Storage__ ret = { _member_` ~ i.stringof ~ ` : _Void!().init };`);
                     return ret;
                 } ();
-                ret._identifier_ = i;
+                ret.identifier__ = i;
                 return ret;
             }
         }
@@ -1781,20 +2168,20 @@ struct Algebraic(_Types...)
 
                 static if (__VERSION__ < 2094 && anySatisfy!(hasElaborateCopyConstructor, AllowedTypes))
                 {
-                    _storage_.bytes = () @trusted {
+                    storage__.bytes = () @trusted {
                         auto ret =  _StorageI!i(rhs);
                         return ret.bytes;
                     } ();
                 }
                 else
                 {
-                    _storage_ = () {
-                        mixin(`_Storage_ ret = { _member_` ~ i.stringof ~ ` : rhs };`);
+                    storage__ = () {
+                        mixin(`Storage__ ret = { _member_` ~ i.stringof ~ ` : rhs };`);
                         return ret;
                     } ();
                 }
                 static if (_Payload.length > 1)
-                    _identifier_ = i;
+                    identifier__ = i;
             }
 
             /// ditto
@@ -1807,20 +2194,20 @@ struct Algebraic(_Types...)
                     alias rhs = value;
                 static if (__VERSION__ < 2094 && anySatisfy!(hasElaborateCopyConstructor, AllowedTypes))
                 {
-                    _storage_.bytes = () const @trusted {
+                    storage__.bytes = () const @trusted {
                         auto ret =  const _StorageI!i(rhs);
                         return ret.bytes;
                     } ();
                 }
                 else
                 {
-                    _storage_ = () {
-                        mixin(`const _Storage_ ret = { _member_` ~ i.stringof ~ ` : rhs };`);
+                    storage__ = () {
+                        mixin(`const Storage__ ret = { _member_` ~ i.stringof ~ ` : rhs };`);
                         return ret;
                     } ();
                 }
                 static if (_Payload.length > 1)
-                    _identifier_ = i;
+                    identifier__ = i;
             }
 
             /// ditto
@@ -1833,50 +2220,57 @@ struct Algebraic(_Types...)
                     alias rhs = value;
                 static if (__VERSION__ < 2094 && anySatisfy!(hasElaborateCopyConstructor, AllowedTypes))
                 {
-                    _storage_.bytes = () const @trusted {
+                    storage__.bytes = () const @trusted {
                         auto ret = immutable  _StorageI!i(rhs);
                         return ret.bytes;
                     } ();
                 }
                 else
                 {
-                    _storage_ = () {
-                        mixin(`immutable _Storage_ ret = { _member_` ~ i.stringof ~ ` : rhs };`);
+                    storage__ = () {
+                        mixin(`immutable Storage__ ret = { _member_` ~ i.stringof ~ ` : rhs };`);
                         return ret;
                     } ();
                 }
                 static if (_Payload.length > 1)
-                    _identifier_ = i;
+                    identifier__ = i;
             }
 
             static if (__traits(compiles, (ref T a, ref T b) { moveEmplace(a, b); }))
             ///
             ref opAssign(T rhs) return @trusted
             {
+                static foreach (T; MetaInfo__)
+                    __traits(getMember, this, T.tag) = T.Type.init;
+
                 import core.lifetime: forward;
-                static if (anySatisfy!(hasElaborateDestructor, AllowedTypes))
-                    this.__dtor();
+                this = this.init;
                 __ctor(forward!rhs);
                 return this;
             }
 
             /++
             +/
-            auto opEquals()(auto ref const T rhs) const
+            bool opEquals()(scope ref const UnqualRec!T rhs) scope @trusted const //pure nothrow @nogc
             {
                 static if (AllowedTypes.length > 1)
-                    if (_identifier_ != i)
+                    if (identifier__ != i)
                         return false;
                 return trustedGet!T == rhs;
-            } 
+            }
+
+            ///ditto
+            bool opEquals()(scope const UnqualRec!T rhs) scope @trusted const //pure nothrow @nogc
+            {
+                return opEquals(rhs);
+            }
 
             /++
             +/
-            auto opCmp()(auto ref const T rhs) const
+            auto opCmp()(auto ref scope const UnqualRec!T rhs) scope @trusted const pure nothrow @nogc
             {
-                import mir.internal.utility: isFloatingPoint;
                 static if (AllowedTypes.length > 1)
-                    if (auto d = int(_identifier_) - int(i))
+                    if (auto d = int(identifier__) - int(i))
                         return d;
                 static if (__traits(compiles, __cmp(trustedGet!T, rhs)))
                     return __cmp(trustedGet!T, rhs);
@@ -1884,11 +2278,7 @@ struct Algebraic(_Types...)
                 static if (__traits(hasMember, T, "opCmp") && !is(T == U*, U))
                     return trustedGet!T.opCmp(rhs);
                 else
-                static if (isFloatingPoint!T)
-                    return trustedGet!T == rhs ? 0 : trustedGet!T - rhs;
-                else
-                    return trustedGet!T < rhs ? -1 :
-                        trustedGet!T > rhs ? +1 : 0;
+                    return trustedGet!T < rhs ? -1 : trustedGet!T > rhs ? +1 : 0;
             }
 
             static if (is(Unqual!T == bool))
@@ -1919,7 +2309,7 @@ struct Algebraic(_Types...)
                     auto opEquals()(int rhs) const
                     {
                         return opEquals(long(rhs));
-                    } 
+                    }
 
                     auto opCmp()(int rhs) const
                     {
@@ -1952,7 +2342,7 @@ struct Algebraic(_Types...)
                     auto opEquals()(uint rhs) const
                     {
                         return opEquals(ulong(rhs));
-                    } 
+                    }
 
                     auto opCmp()(uint rhs) const
                     {
@@ -1963,7 +2353,7 @@ struct Algebraic(_Types...)
         }
     }
 
-    static if (anySatisfy!(isErr, _Types))
+    static if (anySatisfy!(isErr, AllowedTypes))
     {
         /++
         Determines if the variant holds value of some none-$(LREF isVariant) type.
@@ -1971,7 +2361,7 @@ struct Algebraic(_Types...)
         +/
         bool isOk() @safe pure nothrow @nogc const @property
         {
-            switch (_identifier_)
+            switch (identifier__)
             {
                 static foreach (i, T; AllowedTypes)
                 {
@@ -1995,9 +2385,9 @@ unittest
         double d;
     }
 
-    static class C
+    static class Cc
     {
-        // alias this members are supported 
+        // alias this members are supported
         Base base;
         alias base this;
 
@@ -2006,6 +2396,8 @@ unittest
 
     @safe pure nothrow @nogc:
 
+        override size_t toHash() scope const { return hashOf(_b) ^ a; }
+
         string b() const @property { return _b; }
         void b(string b) @property { _b = b; }
 
@@ -2027,17 +2419,17 @@ unittest
         double retArg(double v) { return v; }
         double retArgT(TArgs...)(int v) { return v * TArgs.length; }
 
-        // alias this members are supported 
+        // alias this members are supported
         Base base;
         alias base this;
     }
 
     static void inc(ref int a) { a++; }
 
-    alias V = Nullable!(C, S); // or Variant!
+    alias V = Nullable!(Cc, S); // or Variant!
 
     auto v = V(2, "str");
-    assert(v._is!C);
+    assert(v._is!Cc);
     assert(v.a == 2);
     assert(v.b == "str");
     // members are returned by reference if possible
@@ -2045,7 +2437,7 @@ unittest
     assert(v.a == 3);
     v.b = "s";
     assert(v.b == "s");
-    // alias this members are supported 
+    // alias this members are supported
     v.d = 10;
     assert(v.d == 10);
     // method call support
@@ -2065,13 +2457,12 @@ unittest
     assert(v.a == 6);
     v.b = "s";
     assert(v.b == "s");
-    // alias this members are supported 
+    // alias this members are supported
     v.d = 15;
     assert(v.d == 15);
     // method call support
     assert(v.retArg(300)._is!double);
     assert(v.retArg(300) == 300.0);
-
 }
 
 // test CTFE
@@ -2131,11 +2522,11 @@ version(mir_core_test) unittest
 
 
     static if (hasToHash)
-        size_t toHash() { return hashOf(_payload); }
+        size_t toHash() scope { return hashOf(_payload); }
 
     static if (hasOpEquals)
-        auto opEquals(ref const typeof(this) rhs) @trusted { return memcmp(_payload.ptr, rhs._payload.ptr, _payload.length); }
-        auto opCmp(ref const typeof(this) rhs) { return _payload == rhs._payload; }
+        auto opEquals(ref const scope  typeof(this) rhs) scope   { return _payload == rhs._payload; }
+        auto opCmp(ref const scope typeof(this) rhs) @trusted scope  { return memcmp(_payload.ptr, rhs._payload.ptr, _payload.length); }
     }
 
     static foreach (size1; [1, 2, 4, 8, 10, 16, 20])
@@ -2313,14 +2704,14 @@ version(mir_core_test) unittest
         this(this) @safe pure nothrow @nogc {}
         // void opAssign(typeof(this) rhs) {}
     }
-    static struct C { const(uint)* value; }
+    static struct C1 { const(uint)* value; }
 
     S s;
     S r = s;
     r = s;
     r = S.init;
 
-    alias V = Variant!(S, C);
+    alias V = Variant!(S, C1);
     V v = S();
     V w = v;
     w = S();
@@ -2388,7 +2779,7 @@ version(mir_core_test) unittest
     assert(array[2] == 100);
     array.length = 4;
     assert(array == [0L, 0, 100, 0]);
-    array = array[2 .. 3];    
+    array = array[2 .. 3];
     assert(array.length == 1);
     assert(array[0] == 100);
     array[0] = 10.Variant!(long, double);
@@ -2421,20 +2812,20 @@ $(LREF Algerbraic)`.toString` requries `mir-algorithm` package
     V variant;
 
     assert(secondOrderVisitorHandler(visitorHandler(variant)) == "NULL");
-    assert(variant.to!string == "null");
+    assert(variant.toString == "null");
 
     variant = V._void;
     assert(variant._is!void);
     assert(is(typeof(variant.get!void()) == void));
 
     assert(secondOrderVisitorHandler(visitorHandler(variant)) == "VOID");
-    assert(variant.to!string == "void");
+    assert(variant.toString == "void");
 
     variant = 5;
 
     assert(secondOrderVisitorHandler(visitorHandler(variant)) == "SO VOID");
     assert(variant == 6);
-    assert(variant.to!string == (MIR_ALGORITHM ? "6" : "int"));
+    assert(variant.toString == (MIR_ALGORITHM ? "6" : "int"));
 }
 
 version(mir_core_test)
@@ -2585,7 +2976,7 @@ unittest
 
     alias collideWith = tryMatch!(
         (Asteroid x, Asteroid y) => "a/a",
-        // No visitor for A/S pair 
+        // No visitor for A/S pair
         // (Asteroid x, Spaceship y) => "a/s",
         (Spaceship x, Asteroid y) => "s/a",
         (Spaceship x, Spaceship y) => "s/s",
@@ -2661,7 +3052,7 @@ unittest
 
     alias collideWith = optionalMatch!(
         (Asteroid x, Asteroid y) => "a/a",
-        // No visitor for A/S pair 
+        // No visitor for A/S pair
         // (Asteroid x, Spaceship y) => "a/s",
         (Spaceship x, Asteroid y) => "s/a",
         (Spaceship x, Spaceship y) => "s/s",
@@ -2704,7 +3095,7 @@ unittest
     assert(collide(os, es) == "big-boom");
     assert(collide(os, os) == "big-boom");
 
-    // check types  
+    // check types
 
     static assert(!__traits(compiles, collide(Asteroid.init, Spaceship.init)));
     static assert(is(typeof(collideWith(Asteroid.init, Spaceship.init)) == Nullable!()));
@@ -2737,7 +3128,7 @@ unittest
 
     alias collideWith = autoMatch!(
         (Asteroid x, Asteroid y) => "a/a",
-        // No visitor for A/S pair 
+        // No visitor for A/S pair
         // (Asteroid x, Spaceship y) => "a/s",
         (Spaceship x, Asteroid y) => "s/a",
         (Spaceship x, Spaceship y) => "s/s",
@@ -2780,7 +3171,7 @@ unittest
     assert(collide(os, es) == "big-boom");
     assert(collide(os, os) == "big-boom");
 
-    // check types  
+    // check types
 
     static assert(!__traits(compiles, collide(Asteroid.init, Spaceship.init)));
     static assert(is(typeof(collideWith(Asteroid.init, Spaceship.init)) == Nullable!()));
@@ -2807,12 +3198,12 @@ alias getMember(string member, TArgs...) = visitImpl!(getMemberHandler!(member,
 version(mir_core_test) unittest
 {
     static struct S { auto bar(int a) { return a; } enum boolean = true; }
-    static struct C { alias bar = (double a) => a * 2; enum boolean = false; }
+    static struct C2 { alias bar = (double a) => a * 2; enum boolean = false; }
 
-    alias V = Variant!(S, C);
+    alias V = Variant!(S, C2);
 
     V x = S();
-    V y = C();
+    V y = C2();
 
     static assert(is(typeof(x.getMember!"bar"(2)) == Variant!(int, double)));
     assert(x.getMember!"bar"(2) == 2);
@@ -2844,17 +3235,17 @@ version(mir_core_test) unittest
         Nullable!int m;
     }
 
-    static struct C
+    static struct C1
     {
         Variant!(float, double) m;
     }
 
-    alias V = Variant!(S, C);
+    alias V = Variant!(S, C1);
 
     V x = S(2.nullable);
-    V y = C(Variant!(float, double)(4.0));
+    V y = C1(Variant!(float, double)(4.0));
 
-    // getMember returns an algebraic of algebaics
+    // getMember returns an algebraic of algebraics
     static assert(is(typeof(x.getMember!"m") == Variant!(Variant!(float, double), Nullable!int)));
     // matchMember returns a fused algebraic
     static assert(is(typeof(x.matchMember!"m") == Nullable!(int, float, double)));
@@ -2874,12 +3265,12 @@ alias tryGetMember(string member) = visitImpl!(getMemberHandler!member, Exhausti
 version(mir_core_test) unittest
 {
     static struct S { int bar(int a) { return a; }}
-    static struct C { alias Bar = (double a) => a * 2; }
+    static struct C3 { alias Bar = (double a) => a * 2; }
 
-    alias V = Variant!(S, C);
+    alias V = Variant!(S, C3);
 
     V x = S();
-    V y = C();
+    V y = C3();
 
     static assert(is(typeof(x.tryGetMember!"bar"(2)) == int));
     static assert(is(typeof(y.tryGetMember!"Bar"(2)) == double));
@@ -3146,7 +3537,7 @@ template visitImpl(alias visitor, Exhaustive exhaustive, bool fused, alias Filte
             else
                 alias AllReturnTypes = NoDuplicates!(staticMap!(VariantReturnTypesImpl, Args[0].AllowedTypes));
 
-            switch (args[0]._identifier_)
+            switch (args[0].identifier__)
             {
                 static foreach (i, T; Args[0].AllowedTypes)
                 {
@@ -3194,7 +3585,7 @@ template visitImpl(alias visitor, Exhaustive exhaustive, bool fused, alias Filte
     }
 }
 
-private string enumKindText()(string[] strs)
+private string enumKindText()(scope const char[][] strs)
 {
     auto r = "enum Kind {";
     foreach (s; strs)
@@ -3357,8 +3748,8 @@ version(mir_core_test)
     alias V = Variant!(long, int, string, long[], int[]);
     alias autoGetElementType = match!(
         (string s) => "string", // we override the suit handler below for string
-        suit!(isDynamicArray, a => Unqual!(typeof(a[0])).stringof), 
-        suit!(templateNot!isDynamicArray, a => Unqual!(typeof(a)).stringof), 
+        suit!(isDynamicArray, a => Unqual!(typeof(a[0])).stringof),
+        suit!(templateNot!isDynamicArray, a => Unqual!(typeof(a)).stringof),
     );
     assert(autoGetElementType(V(string.init)) == "string");
     assert(autoGetElementType(V((long[]).init)) == "long");
@@ -3529,11 +3920,6 @@ template isErr(T)
     import std.traits: isAggregateType, hasUDA;
     static if (is(T == enum) || isAggregateType!T)
     {
-        static if (isTaggedType!T)
-        {
-            enum isErr = .isErr!(getTaggedTypeUnderlying!T);
-        }
-        else
         static if (is(immutable T == immutable Err!V, V))
         {
             enum isErr = true;
@@ -3629,9 +4015,9 @@ private template withNewLine(alias arg)
     alias withNewLine = AliasSeq!("\n", arg);
 }
 
-private noreturn throwMe(Args...)(auto ref Args args) {
-    static if (Args.length == 1)
-        enum simpleThrow = is(immutable Args[0] : immutable Throwable);
+private noreturn throwMe(T...)(auto ref T args) {
+    static if (T.length == 1)
+        enum simpleThrow = is(immutable T[0] : immutable Throwable);
     else
         enum simpleThrow = false;
     static if (simpleThrow)
@@ -3644,7 +4030,7 @@ private noreturn throwMe(Args...)(auto ref Args args) {
         static if (__traits(compiles, { import mir.format: print; }))
         {
             import std.meta: staticMap;
-            throw new MirException("assumeOk failure:", staticMap!(withNewLine, args)); 
+            throw new MirException("assumeOk failure:", staticMap!(withNewLine, args));
         }
         else
         {
@@ -3732,7 +4118,7 @@ unittest
 version(mir_core_test)
 unittest
 {
-    struct RequestToken
+    static struct RequestToken
     {
         Variant!(long, string) value;
         alias value this;
@@ -3754,3 +4140,45 @@ unittest
 
     static assert(is(typeof(r) == Variant!(long, string)));
 }
+
+package auto trustedAllAttr(T)(scope T t) @trusted
+{
+    import std.traits;
+    enum attrs = (functionAttributes!T & ~FunctionAttribute.system)
+        | FunctionAttribute.pure_
+        | FunctionAttribute.safe
+        | FunctionAttribute.nogc
+        | FunctionAttribute.nothrow_;
+    return cast(SetFunctionAttributes!(T, functionLinkage!T, attrs)) t;
+}
+
+private static immutable algebraicMembers = [
+    "_is",
+    "_void",
+    "AllowedTypes",
+    "MetaFieldsTypes",
+    "get",
+    "isNull",
+    "kind",
+    "Kind",
+    "nullify",
+    "opAssign",
+    "opCast",
+    "opCmp",
+    "opEquals",
+    "opPostMove",
+    "toHash",
+    "toString",
+    "trustedGet",
+    "deserializeFromAsdf",
+    "deserializeFromIon",
+];
+
+private template UnqualRec(T)
+{
+    import std.traits: Unqual, isDynamicArray, ForeachType;
+    static if (isDynamicArray!T)
+        alias UnqualRec = UnqualRec!(ForeachType!T)[];
+    else
+        alias UnqualRec = Unqual!T;
+}
diff --git a/source/mir/complex/package.d b/source/mir/complex/package.d
index 94f8c1e..5861333 100644
--- a/source/mir/complex/package.d
+++ b/source/mir/complex/package.d
@@ -105,7 +105,7 @@ struct Complex(T)
         return this;
     }
 
-const:
+scope const:
 
     ///
     bool opEquals(const Complex rhs)
@@ -120,8 +120,6 @@ const:
         return hashOf(val) ;
     }
 
-scope:
-
     ///
     bool opEquals(R)(Complex!R rhs)
         if (!is(R == T))
diff --git a/source/mir/conv.d b/source/mir/conv.d
index 34b4ee6..5d6b199 100644
--- a/source/mir/conv.d
+++ b/source/mir/conv.d
@@ -136,7 +136,7 @@ template to(T)
                             {
                                 import mir.appender: UnsafeArrayBuffer;
                                 alias C = Unqual!(ForeachType!T);
-                                C[64] array = '\0';
+                                C[64] array = void;
                                 auto buffer = UnsafeArrayBuffer!C(array);
                             }
                             else
diff --git a/source/mir/exception.d b/source/mir/exception.d
index 2cc52ec..c69cbf1 100644
--- a/source/mir/exception.d
+++ b/source/mir/exception.d
@@ -65,7 +65,20 @@ unittest
     {
         import mir.exception;
         try throw new MirException("Hi D", 2, "!");
-        catch(Exception e) assert(e.msg == "Hi D2!");
+        catch(MirException e) assert(e.scopeMessage == "Hi D2!");
+    }
+}
+
+/// Generic style, GC allocated MSG
+version (mir_test) static if (NOGCEXP && HASFORMAT)
+@safe pure nothrow @nogc
+unittest
+{
+    static if (__traits(compiles, (()@nogc {import mir.format;})()))
+    {
+        import mir.exception;
+        try throw new MirException("Hi D", 2, "!");
+        catch(Exception e) assert(e.message == "Hi D2!");
     }
 }
 
@@ -79,7 +92,7 @@ unittest
         import mir.exception;
         import mir.format;
         try throw new MirException(stringBuf() << "Hi D" << 2 << "!" << getData);
-        catch(Exception e) assert(e.msg == "Hi D2!");
+        catch(Exception e) assert(e.scopeMessage == "Hi D2!");
     }
 }
 
@@ -221,6 +234,18 @@ mixin template MirThrowableImpl()
     private char[maxMirExceptionMsgLen] _payload = void;
     import mir.exception: maxMirExceptionMsgLen, mirExceptionInitilizePayloadImpl;
 
+    const(char)[] _msg;
+
+    override string message() const @safe pure nothrow
+    {
+        return _msg ? _msg.idup : msg;
+    }
+
+    const(char)[] scopeMessage() scope const @safe pure nothrow @nogc
+    {
+        return _msg ? _msg : msg;
+    }
+
     /++
     Params:
         msg = message. No-scope `msg` is assumed to have the same lifetime as the throwable. scope strings are copied to internal buffer.
@@ -228,15 +253,17 @@ mixin template MirThrowableImpl()
         line = line number
         nextInChain = next exception in the chain (optional)
     +/
-    @nogc @safe pure nothrow this(scope const(char)[] msg, string file = __FILE__, size_t line = __LINE__, Throwable nextInChain = null)
+    @nogc @trusted pure nothrow this(scope const(char)[] msg, string file = __FILE__, size_t line = __LINE__, Throwable nextInChain = null)
     {
-        super((() @trusted => cast(immutable) mirExceptionInitilizePayloadImpl(_payload, msg))(), file, line, nextInChain);
+        this._msg = mirExceptionInitilizePayloadImpl(_payload, msg);
+        super(cast(immutable)this._msg, file, line, nextInChain);
     }
 
     /// ditto
-    @nogc @safe pure nothrow this(scope const(char)[] msg, Throwable nextInChain, string file = __FILE__, size_t line = __LINE__)
+    @nogc @trusted pure nothrow this(scope const(char)[] msg, Throwable nextInChain, string file = __FILE__, size_t line = __LINE__)
     {
-        super((() @trusted => cast(immutable) mirExceptionInitilizePayloadImpl(_payload, msg))(), file, line, nextInChain);
+        this._msg = mirExceptionInitilizePayloadImpl(_payload, msg);
+        super(cast(immutable)this._msg, file, line, nextInChain);
     }
 
     /// ditto
@@ -265,13 +292,26 @@ mixin template MirThrowableImpl()
     Generic multiargument overload.
     Constructs a string using the `print` function.
     +/
-    this(Args...)(scope auto ref Args args, string file = __FILE__, size_t line = __LINE__, Throwable nextInChain = null)
-        if (Args.length > 1)
+    this(Args...)(auto ref scope const Args args, string file = __FILE__, size_t line = __LINE__, Throwable nextInChain = null) pure
+        if (Args.length > 1 && !is(Args[$ - 1] == Throwable))
+    {
+        static assert (__traits(compiles, {import mir.format;}), "MirThrowableImpl needs mir-algorithm for mir.format and exception formatting.");
+        import mir.format;
+        auto buf = stringBuf();
+        foreach(ref arg; args)
+            buf.print(arg);
+        this(buf.data, file, line, nextInChain);
+    }
+
+    this(Args...)(auto ref scope const Args args) pure @trusted
+        if (Args.length > 4 && is(Args[$ - 1] == Throwable))
     {
         static assert (__traits(compiles, {import mir.format;}), "MirThrowableImpl needs mir-algorithm for mir.format and exception formatting.");
         import mir.format;
         auto buf = stringBuf();
-        this(buf.print(args).data, file, line, nextInChain);
+        foreach(ref arg; args[0 .. $ - 3])
+            buf.print(arg);
+        this(buf.data, args[$ - 3 .. $ - 1], cast() args[$ - 1]);
     }
 }
 
diff --git a/source/mir/functional.d b/source/mir/functional.d
index 733c380..ddb7fb9 100644
--- a/source/mir/functional.d
+++ b/source/mir/functional.d
@@ -23,11 +23,11 @@ $(TR $(TH Function Name) $(TH Description))
     $(TR $(TD $(LREF forward))
         $(TD Forwards function arguments with saving ref-ness.
     ))
-    $(TR $(TD $(LREF refTuple))
+    $(TR $(TD $(LREF tuple))
         $(TD Removes $(LREF Ref) shell.
     ))
     $(TR $(TD $(LREF unref))
-        $(TD Creates a $(LREF RefTuple) structure.
+        $(TD Creates a $(LREF Tuple) structure.
     ))
     $(TR $(TD $(LREF __ref))
         $(TD Creates a $(LREF Ref) structure.
@@ -52,9 +52,21 @@ public import core.lifetime : forward;
 /++
 Constructs static array.
 +/
-T[N] staticArray(T, size_t N)(T[N] a...)
+T[N] staticArray(T, size_t N)(return scope T[N] a...) {
+    import std.traits: isDynamicArray;
+    static if (isDynamicArray!T) {  
+        T[N] ret;
+        static foreach(i; 0..a.length) ret[i] = a[i];
+        return ret;
+    }
+    else return a;
+}
+
+@safe version(mir_core_test) unittest
 {
-    return a;
+    string[2] v = ["AA", "BB"];
+    auto res = staticArray(v);
+    assert(res == v);
 }
 
 /++
@@ -123,7 +135,7 @@ private mixin template _RefTupleMixin(T...)
 Simplified tuple structure. Some fields may be type of $(LREF Ref).
 Ref stores a pointer to a values.
 +/
-struct RefTuple(T...)
+struct Tuple(T...)
 {
     @optmath:
     T expand;
@@ -131,26 +143,32 @@ struct RefTuple(T...)
     mixin _RefTupleMixin!T;
 }
 
+deprecated("Use 'Tuple' instead")
+alias RefTuple = Tuple;
+
 /// Removes $(LREF Ref) shell.
 alias Unref(V : Ref!T, T) = T;
 /// ditto
-template Unref(V : RefTuple!T, T...)
+template Unref(V : Tuple!T, T...)
 {
     import std.meta: staticMap;
-    alias Unref = RefTuple!(staticMap!(.Unref, T));
+    alias Unref = Tuple!(staticMap!(.Unref, T));
 }
 
 /// ditto
 alias Unref(V) = V;
 
 /++
-Returns: a $(LREF RefTuple) structure.
+Returns: a $(LREF Tuple) structure.
 +/
-RefTuple!Args refTuple(Args...)(auto ref Args args)
+Tuple!Args tuple(Args...)(auto ref Args args)
 {
-    return RefTuple!Args(args);
+    return Tuple!Args(args);
 }
 
+deprecated("Use 'tuple' instead")
+alias refTuple = tuple;
+
 /// Removes $(LREF Ref) shell.
 ref T unref(V : Ref!T, T)(scope return V value)
 {
@@ -158,7 +176,7 @@ ref T unref(V : Ref!T, T)(scope return V value)
 }
 
 /// ditto
-Unref!(RefTuple!T) unref(V : RefTuple!T, T...)(V value)
+Unref!(Tuple!T) unref(V : Tuple!T, T...)(V value)
 {
     typeof(return) ret;
     foreach(i, ref elem; ret.expand)
@@ -191,7 +209,7 @@ private template autoExpandAndForwardElem(alias value)
 }
 
 template autoExpandAndForward(alias value)
-    if (is(typeof(value) : RefTuple!Types, Types...))
+    if (is(typeof(value) : Tuple!Types, Types...))
 {
 
     import core.lifetime: move;
@@ -226,7 +244,7 @@ template autoExpandAndForward(alias value)
 version(mir_core_test) unittest
 {
     long v;
-    auto tup = refTuple(v._ref, 2.3);
+    auto tup = tuple(v._ref, 2.3);
 
     auto f(ref long a, double b)
     {
@@ -257,7 +275,7 @@ private auto copyArg(alias a)()
 
 /++
 Takes multiple functions and adjoins them together. The result is a
-$(LREF RefTuple) with one element per passed-in function. Upon
+$(LREF Tuple) with one element per passed-in function. Upon
 invocation, the returned tuple is the adjoined results of all
 functions.
 Note: In the special case where only a single function is provided
@@ -283,7 +301,7 @@ template adjoin(fun...) if (fun.length && fun.length <= 26)
                 }
 
                 import mir.internal.utility;
-                mixin("return refTuple(" ~ [staticMap!(_adjoin, Iota!(fun.length))].joinStrings ~ ");");
+                mixin("return tuple(" ~ [staticMap!(_adjoin, Iota!(fun.length))].joinStrings ~ ");");
             }
         }
         else alias adjoin = .adjoin!(staticMap!(naryFun, fun));
@@ -297,7 +315,7 @@ template adjoin(fun...) if (fun.length && fun.length <= 26)
     static bool f1(int a) { return a != 0; }
     static int f2(int a) { return a / 2; }
     auto x = adjoin!(f1, f2)(5);
-    assert(is(typeof(x) == RefTuple!(bool, int)));
+    assert(is(typeof(x) == Tuple!(bool, int)));
     assert(x.a == true && x.b == 2);
 }
 
@@ -315,10 +333,10 @@ template adjoin(fun...) if (fun.length && fun.length <= 26)
     auto x1 = adjoin!(F1)(5);
     static int F2(int a) { return a / 2; }
     auto x2 = adjoin!(F1, F2)(5);
-    assert(is(typeof(x2) == RefTuple!(bool, int)));
+    assert(is(typeof(x2) == Tuple!(bool, int)));
     assert(x2.a && x2.b == 2);
     auto x3 = adjoin!(F1, F2, F2)(5);
-    assert(is(typeof(x3) == RefTuple!(bool, int, int)));
+    assert(is(typeof(x3) == Tuple!(bool, int, int)));
     assert(x3.a && x3.b == 2 && x3.c == 2);
 
     bool F4(int a) { return a != x1; }
@@ -341,18 +359,18 @@ version(mir_core_test) unittest
     alias funs = staticMap!(naryFun, "a", "a * 2", "a * 3", "a * a", "-a");
     alias afun = adjoin!funs;
     int a = 5, b = 5;
-    assert(afun(a) == refTuple(Ref!int(a), 10, 15, 25, -5));
-    assert(afun(a) == refTuple(Ref!int(b), 10, 15, 25, -5));
+    assert(afun(a) == tuple(Ref!int(a), 10, 15, 25, -5));
+    assert(afun(a) == tuple(Ref!int(b), 10, 15, 25, -5));
 
     static class C{}
     alias IC = immutable(C);
     IC foo(){return typeof(return).init;}
-    RefTuple!(IC, IC, IC, IC) ret1 = adjoin!(foo, foo, foo, foo)();
+    Tuple!(IC, IC, IC, IC) ret1 = adjoin!(foo, foo, foo, foo)();
 
     static struct S{int* p;}
     alias IS = immutable(S);
     IS bar(){return typeof(return).init;}
-    enum RefTuple!(IS, IS, IS, IS) ret2 = adjoin!(bar, bar, bar, bar)();
+    enum Tuple!(IS, IS, IS, IS) ret2 = adjoin!(bar, bar, bar, bar)();
 }
 
 private template needOpCallAlias(alias fun)
diff --git a/source/mir/internal/meta.d b/source/mir/internal/meta.d
index a7e6cdd..ac976fa 100644
--- a/source/mir/internal/meta.d
+++ b/source/mir/internal/meta.d
@@ -13,7 +13,7 @@ module mir.internal.meta;
 template getUDAs(T, string member, alias attribute)
 {
     import std.meta : Filter, AliasSeq;
-    T* aggregate;
+    private __gshared T* aggregate;
     static if (__traits(compiles, __traits(getAttributes, __traits(getMember, *aggregate, member))))
         alias getUDAs = Filter!(isDesiredUDA!attribute, __traits(getAttributes, __traits(getMember, *aggregate, member)));
     else
@@ -56,7 +56,7 @@ private template isDesiredUDA(alias attribute)
 
 template memberTypeOf(T, string member)
 {
-    T* aggregate;
+    private __gshared T* aggregate;
     alias memberTypeOf = typeof(__traits(getMember, aggregate, member));
 }
 
@@ -77,7 +77,7 @@ template AllMembersRec(T)
     {
         static if (__traits(getAliasThis, T).length)
         {
-            T* aggregate;
+            private __gshared T* aggregate;
             static if (is(typeof(__traits(getMember, aggregate, __traits(getAliasThis, T)))))
             {
                 import std.meta: Filter, AliasSeq;
@@ -109,6 +109,7 @@ enum canImplicitlyRemoveConst(T) = __traits(compiles, {static T _function_(ref c
 enum canRemoveConst(T) = canConstructWith!(const T, T);
 enum canRemoveImmutable(T) = canConstructWith!(immutable T, T);
 enum hasOpPostMove(T) = __traits(hasMember, T, "opPostMove");
+enum hasOpCmp(T) = __traits(hasMember, T, "opCmp");
 enum hasToHash(T) = __traits(hasMember, T, "toHash");
 static if (__VERSION__ < 2094)
     enum isCopyable(S) = is(typeof({ S foo = S.init; S copy = foo; }));
@@ -649,3 +650,12 @@ version(mir_core_test) @safe unittest
     class C : I!int {}
     static assert(is(ReplaceType!(int, string, C) == C));
 }
+
+template basicElementType(T)
+{
+    import std.traits: isArray, ForeachType;
+    static if (isArray!T)
+        alias basicElementType = ForeachType!T;
+    else
+        alias basicElementType = T;
+}
diff --git a/source/mir/math/common.d b/source/mir/math/common.d
index f68990f..64c06cb 100644
--- a/source/mir/math/common.d
+++ b/source/mir/math/common.d
@@ -281,7 +281,7 @@ else version(GNU)
     ///
     T nearbyint(T)(in T x) if (isFloatingPoint!T) { mixin(mixinGCCBuiltin!`nearbyint`); }
     ///
-    T copysign(T)(in T mag, in T sgn) if (isFloatingPoint!T) { alias y = sgn; mixin(mixinGCCBuiltin2!`copysign`); }
+    T copysign(T)(in T x, in T sgn) if (isFloatingPoint!T) { alias y = sgn; mixin(mixinGCCBuiltin2!`copysign`); }
     ///
     T round(T)(in T x) if (isFloatingPoint!T) { mixin(mixinGCCBuiltin!`round`); }
     ///
diff --git a/source/mir/primitives.d b/source/mir/primitives.d
index 245d07c..e128418 100644
--- a/source/mir/primitives.d
+++ b/source/mir/primitives.d
@@ -116,8 +116,8 @@ package(mir) bool anyEmptyShape(size_t N)(scope const auto ref size_t[N] shape)
 }
 
 ///
-bool anyEmpty(Range)(scope const auto ref Range range) @property
-    if (hasShape!Range || __traits(hasMember, Range, "anyEmpty"))
+bool anyEmpty(Range)(scope auto ref Range range) @property
+    if (hasShape!Range || __traits(hasMember, Range, "anyEmpty") || is(ReturnType!((Range r) => r.empty) == bool))
 {
     static if (__traits(hasMember, Range, "anyEmpty"))
     {
diff --git a/source/mir/qualifier.d b/source/mir/qualifier.d
index ce66536..cbf4c7f 100644
--- a/source/mir/qualifier.d
+++ b/source/mir/qualifier.d
@@ -69,7 +69,7 @@ This funciton should be used only when the result never skips the current scope.
 
 This function is used by some algorithms to optimise work with reference counted types.
 +/
-auto ref lightScope(T)(auto ref return T v)
+auto ref lightScope(T)(auto ref return scope T v)
     if (!is(T : P*, P) && __traits(hasMember, T, "lightScope"))
 {
     return v.lightScope;
@@ -77,7 +77,7 @@ auto ref lightScope(T)(auto ref return T v)
 
 /// ditto
 auto ref lightScope(T)(auto return ref T v)
-    if (is(T : P*, P) || !__traits(hasMember, T, "lightScope"))
+    if (!is(T : P*, P) && !__traits(hasMember, T, "lightScope"))
 {
     static if (is(T == immutable))
         return lightImmutable(v);
@@ -88,6 +88,13 @@ auto ref lightScope(T)(auto return ref T v)
         return v;
 }
 
+/// ditto
+auto lightScope(T)(return T v)
+    if (is(T : P*, P))
+{
+    return cast(typeof(*v)*) v;
+}
+
 ///
 auto lightImmutable(T)(auto ref immutable T v)
     if (!is(T : P*, P) && __traits(hasMember, immutable T, "lightImmutable"))
diff --git a/source/mir/reflection.d b/source/mir/reflection.d
index bcdd111..1f77f77 100644
--- a/source/mir/reflection.d
+++ b/source/mir/reflection.d
@@ -2,7 +2,7 @@
 Base reflection utilities.
 
 License: $(HTTP www.apache.org/licenses/LICENSE-2.0, Apache-2.0)
-Authors: Ilia Ki 
+Authors: Ilia Ki
 Macros:
 +/
 module mir.reflection;
@@ -10,6 +10,7 @@ module mir.reflection;
 import std.meta;
 import std.traits: hasUDA, getUDAs, Parameters, isSomeFunction, FunctionAttribute, functionAttributes, EnumMembers, isAggregateType;
 import mir.internal.meta: hasUDA;
+import mir.functional: Tuple;
 
 deprecated
 package alias isSomeStruct = isAggregateType;
@@ -26,7 +27,7 @@ template isStdNullable(T)
 {
     import std.traits : hasMember;
 
-    T* aggregate;
+    private __gshared T* aggregate;
 
     enum bool isStdNullable =
         hasMember!(T, "isNull") &&
@@ -524,7 +525,7 @@ Checks if member is property.
 +/
 template isProperty(T, string member)
 {
-    T* aggregate;
+    private __gshared T* aggregate;
 
     static if (__traits(compiles, isSomeFunction!(__traits(getMember, *aggregate, member))))
     {
@@ -759,10 +760,41 @@ private template Deserializable(T, string member)
 
 private enum SerdeFieldsAndProperties(T) = Reverse!(NoDuplicates!(Reverse!(SerdeFieldsAndPropertiesImpl!T)));
 
+
+private static immutable exlMembers = [
+    "opAssign",
+    "opCast",
+    "opCmp",
+    "opEquals",
+    "opPostMove",
+    "toHash",
+    "toString",
+    "trustedGet",
+    "deserializeFromAsdf",
+    "deserializeFromIon",
+];
+
+private auto filterMembers(string[] members)
+{
+    string[] ret;
+
+    L: foreach(member; members)
+    {
+        if (member.length >= 2 && (member[0 .. 2] == "__" || member[$ - 2 .. $] == "__"))
+            continue;
+        foreach(exlMember; exlMembers)
+            if (exlMember == member)
+                continue L;
+        ret ~= member;
+    }
+    return ret;
+};
+
 private template allMembers(T)
 {
+    import std.meta: aliasSeqOf;
     static if (isAggregateType!T)
-        alias allMembers = __traits(allMembers, T);
+        alias allMembers = aliasSeqOf!(filterMembers([__traits(allMembers, T)]));
     else
         alias allMembers = AliasSeq!();
 }
@@ -772,7 +804,7 @@ private template SerdeFieldsAndPropertiesImpl(T)
     alias isProperty = ApplyLeft!(.isProperty, T);
     alias hasField = ApplyLeft!(.hasField, T);
     alias isOriginalMember = ApplyLeft!(.isOriginalMember, T);
-    T* aggregate;
+    private __gshared T* aggregate;
     template hasReflectSerde(string member)
     {
         static if (is(typeof(__traits(getMember, *aggregate, member))))
@@ -781,7 +813,7 @@ private template SerdeFieldsAndPropertiesImpl(T)
             enum hasReflectSerde = false;
     }
     alias isMember = templateAnd!(templateOr!(hasField, isProperty, hasReflectSerde), isOriginalMember);
-    static if (__traits(getAliasThis, T).length)
+    static if (!is(immutable T == Tuple!Types, Types...) && __traits(getAliasThis, T).length)
     {
         alias A = typeof(__traits(getMember, aggregate, __traits(getAliasThis, T)));
         static if (isAggregateType!T)
@@ -805,27 +837,44 @@ private template SerdeFieldsAndPropertiesImpl(T)
 // check if the member is readable
 private template isReadable(T, string member)
 {
-    T* aggregate;
+    private __gshared T* aggregate;
     enum bool isReadable = __traits(compiles, { static fun(T)(auto ref T t) {} fun(__traits(getMember, *aggregate, member)); });
 }
 
 // check if the member is readable/writeble?
 private template isReadableAndWritable(T, string member)
 {
-    T* aggregate;
+    private __gshared T* aggregate;
     enum bool isReadableAndWritable = __traits(compiles, __traits(getMember, *aggregate, member) = __traits(getMember, *aggregate, member));
 }
 
 package template isPublic(T, string member)
 {
-    T* aggregate;
-    enum bool isPublic = !__traits(getProtection, __traits(getMember, *aggregate, member)).privateOrPackage;
+    private __gshared T* aggregate;
+    static if (__traits(compiles, { auto _ = __traits(getProtection, __traits(getMember, *aggregate, member)); }))
+        enum bool isPublic = !__traits(getProtection, __traits(getMember, *aggregate, member)).privateOrPackage;
+    else
+        enum bool isPublic = false;
+}
+
+version(unittest)
+{
+    final class ZipArchive
+    {
+    public:
+        static const ushort zip64ExtractVersion = 45;
+    }
+}
+
+version (mir_core_test) @nogc nothrow pure @safe unittest
+{
+    static assert(!isPublic!(ZipArchive, "zip64ExtractVersion"));
 }
 
 // check if the member is property
 private template isSetter(T, string member)
 {
-    T* aggregate;
+    private __gshared T* aggregate;
     static if (__traits(compiles, isSomeFunction!(__traits(getMember, *aggregate, member))))
     {
         static if (isSomeFunction!(__traits(getMember, *aggregate, member)))
@@ -843,7 +892,7 @@ private template isSetter(T, string member)
 
 private template isGetter(T, string member)
 {
-    T* aggregate;
+    private __gshared T* aggregate;
     static if (__traits(compiles, isSomeFunction!(__traits(getMember, *aggregate, member))))
     {
         static if (isSomeFunction!(__traits(getMember, *aggregate, member)))

Debdiff

[The following lists of changes regard files as different if they have different names, permissions or owners.]

Files in second set of .debs but not in first

-rw-r--r--  root/root   /usr/lib/debug/.build-id/7c/476ca546cb20e7cd7b15d3b52de14401813e77.debug

Files in first set of .debs but not in second

-rw-r--r--  root/root   /usr/lib/debug/.build-id/e5/175b9be8c912712603b2009b1553d8a9805493.debug

No differences were encountered between the control files of package libmir-core-dev

No differences were encountered between the control files of package libmir-core1

Control files of package libmir-core1-dbgsym: lines which differ (wdiff format)

  • Build-Ids: e5175b9be8c912712603b2009b1553d8a9805493 7c476ca546cb20e7cd7b15d3b52de14401813e77

More details

Full run details