dtolnay / request-for-implementation

Crates that don't exist, but should
610 stars 6 forks source link

A marker to allow compile-type checks for when the uniquely serializable representation in required #50

Open MOZGIII opened 4 years ago

MOZGIII commented 4 years ago

Sometimes you want to build a data structure that, when serialized, in guaranteed to have the same representation for the same data.

An example of this would be a BitTorrent protocol: there's an info dictionary that's serialized via bencode (this lives in .torrent files and describes the contents of a torrent file), and an info_hash field that's used by trackers - a SHA1 hashsum of the serialized info struct.

info is an example of a well-defined struct, that only includes fields that have trivially understood serialization representations: scalars, arrays but no maps of any kind for instance.

It would be great to have a system that would allow validating at compile-time that a particular data structure only consists of fields that are guaranteed to be represented in a single way possible.

Consider this example:

// This sets up the basics.

trait UniqueRepr {}

impl UniqueRepr for u64 {}
impl<T: UniqueRepr> UniqueRepr for &[T] {}

// no impl for `f*` types, like f64
impl UniqueRepr for NormalF64 {} // an abstract newtype for f64 that ensures `is_normal() == true`

// This is how it helps to check our types.

// Works.
#[derive(UniqueRepr)]
struct MyStruct {
    a: u64,
}

// Doesn't work: f64 doesn't implement `UniqueRepr`
#[derive(UniqueRepr)]
struct MyBadStruct {
    b: f64,
}

// This works, because `NormalF64` implements `UniqueRepr`
#[derive(UniqueRepr)]
struct MyFixedStruct {
    b: NormalF64,
}

fn my_hash_exchange_system<T: UniqueRepr>(val: T) { ... }

my_hash_exchange_system(0u64); // works
my_hash_exchange_system(MyStruct{a: 123}) // works
my_hash_exchange_system(0f64) // nope
my_hash_exchange_system(NormalF64::try_from(0f64).unwrap()) // works

This is useful for all kinds of applications where you need to produce a type for which the serialization has to reliably hashed. Maybe for something else too, generically speaking - for reliably producing the reproducible representations.

MOZGIII commented 4 years ago

This has a relation to the Hash marker from the std. This is different, in that it specifies the properties for the serialized value, not the in-memory representation.