Type_reg 0.1.0 -- Serializable / Deserializable Map of Any Type

Heya, I just published type_reg 0.1.0, which allows you to serialize and deserialize a map of any (serializable / deserializable) type.

There are two kinds of TypeReg and TypeMap:

Tagged Type Registry

Serialization

use serde::{Deserialize, Serialize};
use type_reg::tagged::TypeMap;

#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
struct A(u32);

fn main() {
    let mut type_map = TypeMap::new();
    type_map.insert("one", 1u32);
    type_map.insert("two", 2u64);
    type_map.insert("three", A(3));

    println!("{}", serde_yaml::to_string(&type_map).unwrap());

    // ---
    // one:
    //   u32: 1
    // three:
    //   "rust_out::A": 3
    // two:
    //   u64: 2
}

Deserialization

use serde::{Deserialize, Serialize};
use type_reg::tagged::{TypeMap, TypeReg};

#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
struct A(u32);

fn main() {
    let mut type_reg = TypeReg::new();
    type_reg.register::<u32>();
    type_reg.register::<u64>();
    type_reg.register::<A>();

    let serialized = "---\n\
        one:   { u32: 1 }\n\
        two:   { u64: 2 }\n\
        three: { 'tagged_deserialize_map::A': 3 }\n\
        ";

    let deserializer = serde_yaml::Deserializer::from_str(serialized);
    let type_map: TypeMap<String> = type_reg.deserialize_map(deserializer).unwrap();

    let data_u32 = type_map.get::<u32, _>("one").copied().unwrap();
    let data_u64 = type_map.get::<u64, _>("two").copied().unwrap();
    let data_a = type_map.get::<A, _>("three").copied().unwrap();

    println!("{data_u32}, {data_u64}, {data_a:?}");

    // 1, 2, A(3)
}
Untagged Type Registry

Serialization

use serde::{Deserialize, Serialize};
use type_reg::untagged::TypeMap;

#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
struct A(u32);

fn main() {
    let mut type_map = TypeMap::new();
    type_map.insert("one", 1u32);
    type_map.insert("two", 2u64);
    type_map.insert("three", A(3));

    println!("{}", serde_yaml::to_string(&type_map).unwrap());

    // ---
    // two: 2
    // one: 1
    // three: 3
}

Deserialization

use serde::{Deserialize, Serialize};
use type_reg::untagged::{TypeMap, TypeReg};

#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
struct A(u32);

fn main() {
    let mut type_reg = TypeReg::<String>::new();
    type_reg.register::<u32>(String::from("one"));
    type_reg.register::<u64>(String::from("two"));
    type_reg.register::<A>(String::from("three"));

    let serialized = "---\n\
        one: 1\n\
        two: 2\n\
        three: 3\n\
        ";

    let deserializer = serde_yaml::Deserializer::from_str(serialized);
    let type_map: TypeMap<String> = type_reg.deserialize_map(deserializer).unwrap();

    let data_u32 = type_map.get::<u32, _>("one").copied().unwrap();
    let data_u64 = type_map.get::<u64, _>("two").copied().unwrap();
    let data_a = type_map.get::<A, _>("three").copied().unwrap();

    println!("{data_u32}, {data_u64}, {data_a:?}");

    // 1, 2, A(3)
}

Links:

Hope you find it useful.

I don't think the use of std::any::type_name() is correct.

From the documentation:

This is intended for diagnostic use. The exact contents and format of the string returned are not specified, other than being a best-effort description of the type.

The returned string must not be considered to be a unique identifier of a type as multiple types may map to the same type name. Similarly, there is no guarantee that all parts of a type will appear in the returned string: for example, lifetime specifiers are currently not included. In addition, the output may change between versions of the compiler.

This means that your crate can break if the serializing code uses a different version of the compiler than the one used by the deserializing code. It can also break (fail or succeed unexpectedly) if there are multiple types with the same name.

1 Like

ah true, so the tagged type registry is relying on an unstable value.

Shall add a warning note; but pity though, as it captures the information that a person can understand, and is implemented for all types. That said, perhaps untagged is more useful since one can map multiple values for the same type.

Thanks!

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.