digitalmars.D.announce - Json Algebraics with Mir
- 9il (107/107) Apr 11 2021 Hi all,
Hi all, As you may know, [Mir](https://github.com/libmir) provides two JSON libraries: [asdf](http://asdf.libmir.org/) and WIP [mir-ion](http://mir-ion.libmir.org/). The last one is based on Amazon's Ion dual format. Both libraries provide a direct de/serialization API that doesn't need to have a mutable JSON value. This works awesome for almost all cases, except when we want to work with JSON tree directly and dynamically change it. Or sometimes a JSON value may have different types and we want to check them at runtime. Looking into JSON value implementations, we can find that they are _tagged nullable self-referencing algebraic_ types. - _algebraic_ - type can store a value of a type from a fixed typeset. - _self-referencing_ - algebraic typeset types can refer to this algebraic type - _nullable_ - `typeof(null)` type is supported, and it is the default - _tagged_ - we have an enumeration (`enum`) of the whole typeset, and value has a property, which returns an enumeration value that corresponds to the underlying type. We can define such algebraics with [mir.algebraic](http://mir-core.libmir.org/mir_algebraic.html): ```d import mir.algebraic: TaggedVariant, This; union JsonAlgebraicUnion { typeof(null) null_; bool boolean; long integer; double float_; immutable(char)[] string; /// Self alias in array This[] array; /// Self alias in associative This[immutable(char)[]] object; } alias JsonAlgebraic = TaggedVariant!JsonAlgebraicUnion; unittest { JsonAlgebraic value; JsonAlgebraic[string] object; // Default assert(value.isNull); assert(value.kind == JsonAlgebraic.Kind.null_); // Boolean value = true; object["key"] = value; assert(!value.isNull); assert(value == true); assert(value.kind == JsonAlgebraic.Kind.boolean); assert(value.get!bool == true); assert(value.get!(JsonAlgebraic.Kind.boolean) == true); ... ``` We added serialization of [mir.algebraic](http://mir-core.libmir.org/mir_algebraic.html) a few months ago to both JSON libraries. It is effortless to implement: send a serialization lambda to a visitor. And the typeset isn't limited to JSON-like types (bool, string, double, etc.). If all types of the typeset are serializable, then algebraic is serializable as well. Deserialization is more complicated. We need to define a rule of how we want to deserialize a JSON type set to an algebraic typeset. And more, we don't need to provide a unique JsonAlgebraic type. Instead, we provide a common JSON algebraic alias [mir.algebraic_alias.json](http://mir-algorithm.libmir.org/mir_algebr ic_alias_json.html) and support user-provided algebraic aliases as well. For example, user-provided types can be: ```d import mir.algebraic: Variant, Nullable, This; struct Color { ubyte a, r, g, b; } alias JsonValue0 = Variant!(string, Color[], This[string]); alias JsonValue1 = Nullable!(This[], long); ``` Asdf match Json types according to the following rules: - `typeof(null)` can handle JSON `null` - `bool` can handle JSON `true` and `false` - `string` can handle JSON strings - `double` can handle JSON numbers - `long` can handle JSON integer numbers and has priority for them comparing to `double` - `T[]` can handle JSON arrays, where T is a deserializable type, including the algebraic itself - `StringMap!T` and `T[string]` can handle JSON objects, where T is a deserializable type, including the algebraic type itself. [StringMap](http://mir-algorithm.libmir.org/mir_string_map.html) is an ordered string-value associative array with fast search operations. It has a priority over built-in associative arrays. - Other types of algebraic typeset aren't used for deserialization. - If no type can handle the current JSON value, then an exception is thrown. Users APIs will be consistent even if they will define different, their own JSON algebraic aliases. Mir algebraic types: - are order-independent: `Variant!(A, B)` is the same type as `Variant!(B, A)` - can be constructed from their algebraic subset. - can get their algebraic subset. mir-ion support for algebraic deserialization will be added later and extended with Ion types, including Blob, Clob, Timestamp, Decimal, and 4 bytes floats. Kind regards, Ilya --- This work has been sponsored by Symmetry Investments and Kaleidic Associates.
Apr 11 2021