Crate hashed_type_def

source ·
Expand description

This is part of Silx project

hashed-type-def contains components and macros for deriving, at compile time, type hashcode to identify a type:

  • The hashcode is generated as u128 constant and as Uuid constant
  • The hashcode generated by the derive macro is built from the morphology of the type definition and does not depend on the rust version

As the crate uses a procedural macro, however, the result could depend on the sequences generated by the parser (syn) and therefore on the evolution of this parser

§Content

The crate provides two traits HashedTypeDef and HashedTypeMethods

  • the HashedTypeDef trait is the basis for defining a type’s hashcode
    • It provides constant value of the hashcode under u128 and Uuid formats
  • the HashedTypeMethods trait provides additional methods for accessing the hashcode

The regular way to implement HashedTypeDef is by using the procedural macro #[derive(HashedTypeDef)]

The following example gives an overview of hashed-type-def features.

§Example of type hashcode implementation

§Cargo.toml

[package]
name = "silx_hashed-type-def_examples"
version = "0.1.2"
edition = "2021"
 
[dependencies]
uuid = "1.7.0"
hashed-type-def = { version = "0.1.2", features = ["derive"] }

§main.rs

use std::fmt::Debug;
 
use hashed_type_def::{ HashedTypeDef, add_hashed_type_def_param, };
 
/// case 1: a named structure to be tested with procedural derivation
/// * procedural macro `#[derive(HashedTypeDef)]` is the regular way to implement `HashedTypeDef`
#[derive(Debug,HashedTypeDef)]
struct MyStruct<'a,'b,T,U: Debug,const C1: usize, const C2: bool> where T: Into<U> + 'b, 'a: 'b {
    #[allow(dead_code)] un: &'a String,
    #[allow(dead_code)] deux: T,
    #[allow(dead_code)] trois: &'b U,
}
 
pub mod instance0 {
    use hashed_type_def::HashedTypeDef;
    use std::fmt::Debug;
 
    /// case 2: a structure with same definition and procedural derivation as case 1
    /// * type hash should be the same than case 1
    #[derive(Debug,HashedTypeDef)]
    pub struct MyStruct<'a,'b,T,U: Debug,const C1: usize, const C2: bool> where T: Into<U> + 'b, 'a: 'b {
        #[allow(dead_code)] un: &'a String,
        #[allow(dead_code)] deux: T,
        #[allow(dead_code)] trois: &'b U,
    }
} 
 
pub mod instance1 {
    use hashed_type_def::{ add_hashed_type_def, HashedTypeDef, };
    use std::fmt::Debug;
    /// case 3: a structure with same definition as case 1 and post derivation obtained by macro `add_hashed_type_def!` processing on the same definition
    /// * type hash should be the same than case 1
    pub struct MyStruct<'a,'b,T,U: Debug,const C1: usize, const C2: bool> where T: Into<U> + 'b, 'a: 'b {
        #[allow(dead_code)] un: &'a String,
        #[allow(dead_code)] deux: T,
        #[allow(dead_code)] trois: &'b U,
    }
 
    add_hashed_type_def!{
        pub struct MyStruct<'a,'b,T,U: Debug,const C1: usize, const C2: bool> where T: Into<U> + 'b, 'a: 'b {
            un: &'a String,
            deux: T,
            trois: &'b U,
        }    
    }
} 
 
pub mod instance2 {
    use hashed_type_def::HashedTypeDef;
    use std::fmt::Debug;
    /// case 4: a structure with procedural derivation and same definition as case 1 except a swap on lifetime names
    /// * type hash should be different than case 1
    #[derive(Debug,HashedTypeDef)]
    pub struct MyStruct<'b,'a,T,U: Debug,const C1: usize, const C2: bool> where T: Into<U> + 'a, 'b: 'a {
        #[allow(dead_code)] un: &'b String,
        #[allow(dead_code)] deux: T,
        #[allow(dead_code)] trois: &'a U,
    }
} 
 
pub mod instance3 {
    use hashed_type_def::{ add_hashed_type_def, HashedTypeDef, };
    use std::fmt::Debug;
    /// case 5: a structure with same definition as case 1 and post derivation obtained by macro `add_hashed_type_def!` processing on altered definition
    /// * type hash should be different than case 1
    pub struct MyStruct<'a,'b,T,U: Debug,const C1: usize, const C2: bool> where T: Into<U> + 'b, 'a: 'b {
        #[allow(dead_code)] un: &'a String,
        #[allow(dead_code)] deux: T,
        #[allow(dead_code)] trois: &'b U,
    }
 
    add_hashed_type_def!{
        pub struct MyStruct<'a,'b,T,U: Debug,const C1: usize, const C2: bool> where T: Into<U> + 'b, 'a: 'b {
            instance3_MyStruct: (),
            un: &'a String,
            deux: T,
            trois: &'b U,
        }    
    }
} 
 
pub mod instance4 {
    use hashed_type_def::HashedTypeDef;
    use std::fmt::Debug;
    /// case 6: a structure with procedural derivation and same definition as case 1 except conditions are moved to where clauses
    /// * type hash should be different than case 1
    #[derive(Debug,HashedTypeDef)]
    pub struct MyStruct<'a,'b,T,U,const C1: usize, const C2: bool> where 'a: 'b, T: Into<U> + 'b, U: Debug, {
        #[allow(dead_code)] un: &'a String,
        #[allow(dead_code)] deux: T,
        #[allow(dead_code)] trois: &'b U,
    }
} 
 
pub mod instance5 {
    use hashed_type_def::HashedTypeDef;
    use std::fmt::Debug;
    /// case 7: a structure with procedural derivation and same definition as case 1 except conditions are moved from where clauses
    /// * type hash should be different than case 1
    #[derive(Debug,HashedTypeDef)]
    pub struct MyStruct<'a: 'b,'b, T: Into<U> + 'b, U: Debug, const C1: usize, const C2: bool> {
        #[allow(dead_code)] un: &'a String,
        #[allow(dead_code)] deux: T,
        #[allow(dead_code)] trois: &'b U,
    }
} 
 
pub mod instance6 {
    use hashed_type_def::HashedTypeDef;
    use std::fmt::Debug;
    /// case 8: a structure with procedural derivation and same definition as case 1 except a conditions is removed from parameters list
    /// * type hash should be different than case 1    
    #[derive(Debug,HashedTypeDef)]
    pub struct MyStruct<'a,'b,T,U,const C1: usize, const C2: bool> where T: Into<U> + 'b, 'a: 'b {
        #[allow(dead_code)] un: &'a String,
        #[allow(dead_code)] deux: T,
        #[allow(dead_code)] trois: &'b U,
    }
} 
 
pub mod instance7 {
    use hashed_type_def::HashedTypeDef;
    use std::fmt::Debug;
    /// case 9: a structure with procedural derivation and same definition as case 1 except a condition is removed from where clauses
    /// * type hash should be different than case 1
    #[derive(Debug,HashedTypeDef)]
    pub struct MyStruct<'a,'b,T,U: Debug,const C1: usize, const C2: bool> where T: Into<U> + 'b, {
        #[allow(dead_code)] un: &'a String,
        #[allow(dead_code)] deux: T,
        #[allow(dead_code)] trois: &'b U,
    }
} 
 
/// build type hash (Uuid format) of case 1 for specific lifetime
/// * type hash should not change
fn fn_type_hash<'a: 'b,'b>(_tmp1: &'a (), _tmp2: &'b ()) -> uuid::Uuid { MyStruct::<'a,'b,f32,f64,12,true>::UUID }
 
/// case 10: a unnamed structure to be tested with procedural derivation
#[derive(Debug,HashedTypeDef)]
struct MyTupleStruct<T,U: Debug>(String,T,U,) where T: Into<U>;
 
/// case 11: a unit structure to be tested with procedural derivation
#[derive(Debug,HashedTypeDef)]
struct MyEmptyStruct;
 
/// case 12: enum to be tested with procedural derivation
#[derive(Debug,HashedTypeDef)]
enum MyEnum<T,U: Debug> where T: Into<U> {
    #[allow(dead_code)] Zero,
    #[allow(dead_code)] Un(String, T,),
    #[allow(dead_code)] Deux {
        double: f64,
        trois: U,
    },
    #[allow(dead_code)] Trois,
}
 
/// case 13: empty enum to be tested with procedural derivation
#[derive(Debug,HashedTypeDef)]
enum MyEmptyEnum { }
 
/// case 14: a struct to be tested with post derivation with parameter tag `(Option<u32>,[u128;24])`
struct AnotherStruct<T: Debug> where T: Default { #[allow(dead_code)] t: T }
 
add_hashed_type_def_param!((Option<u32>,[u128;24]); struct AnotherStruct<T: Debug> where T: Default { t: T });
 
/// Different cases of type hash derivation
fn main() {
    // case 1 with `true` parameter
    println!("MyStruct::<'static,'static,f32,f64,12,true>::UUID -> {:x}", MyStruct::<'static,'static,f32,f64,12,true>::UUID);
    // case 1 with `true` parameter and different lifetime
    println!("MyStruct::<'a,'b,f32,f64,12,true>::UUID -> {:x}", { let a = (); { let b = (); fn_type_hash(&a,&b) } });
    // case 1 with `false` parameter
    println!("MyStruct::<'static,'static,f32,f64,12,false>::UUID -> {:x}", MyStruct::<'static,'static,f32,f64,12,false>::UUID);
    // case 2 with `false` parameter
    println!("instance0::MyStruct::<'static,'static,f32,f64,12,false>::UUID -> {:x}", instance0::MyStruct::<'static,'static,f32,f64,12,false>::UUID);
    // case 3 with `false` parameter
    println!("instance1::MyStruct::<'static,'static,f32,f64,12,false>::UUID -> {:x}", instance1::MyStruct::<'static,'static,f32,f64,12,false>::UUID);
    // case 4 with `false` parameter
    println!("instance2::MyStruct::<'static,'static,f32,f64,12,false>::UUID -> {:x}", instance2::MyStruct::<'static,'static,f32,f64,12,false>::UUID);
    // case 5 with `false` parameter
    println!("instance3::MyStruct::<'static,'static,f32,f64,12,false>::UUID -> {:x}", instance3::MyStruct::<'static,'static,f32,f64,12,false>::UUID);
    // case 6 with `false` parameter
    println!("instance4::MyStruct::<'static,'static,f32,f64,12,false>::UUID -> {:x}", instance4::MyStruct::<'static,'static,f32,f64,12,false>::UUID);
    // case 7 with `false` parameter
    println!("instance5::MyStruct::<'static,'static,f32,f64,12,false>::UUID -> {:x}", instance5::MyStruct::<'static,'static,f32,f64,12,false>::UUID);
    // case 8 with `false` parameter
    println!("instance6::MyStruct::<'static,'static,f32,f64,12,false>::UUID -> {:x}", instance6::MyStruct::<'static,'static,f32,f64,12,false>::UUID);
    // case 9 with `false` parameter
    println!("instance7::MyStruct::<'static,'static,f32,f64,12,false>::UUID -> {:x}", instance7::MyStruct::<'static,'static,f32,f64,12,false>::UUID);
    // case 10
    println!("MyTupleStruct::<f32,f64>::UUID -> {:x}", MyTupleStruct::<f32,f64>::UUID);
    // case 11
    println!("MyEmptyStruct::UUID -> {:x}", MyEmptyStruct::UUID);
    // case 12
    println!("MyEnum::<f32,f64,>::UUID -> {:x}", MyEnum::<f32,f64,>::UUID);
    // case 13
    println!("MyEmptyEnum::UUID -> {:x}", MyEmptyEnum::UUID);
    // case 14
    println!("AnotherStruct::<Vec<u16>>::UUID -> {:x}", AnotherStruct::<Vec<u16>>::UUID);
}

§Typical output

MyStruct::<'static,'static,f32,f64,12,true>::UUID -> bd84ac66-d0fa-5d1c-ae5e-25647a13dcb3
MyStruct::<'a,'b,f32,f64,12,true>::UUID -> bd84ac66-d0fa-5d1c-ae5e-25647a13dcb3
MyStruct::<'static,'static,f32,f64,12,false>::UUID -> 1a8a7365-1c9c-afed-cca3-983399a91fd8
instance0::MyStruct::<'static,'static,f32,f64,12,false>::UUID -> 1a8a7365-1c9c-afed-cca3-983399a91fd8
instance1::MyStruct::<'static,'static,f32,f64,12,false>::UUID -> 1a8a7365-1c9c-afed-cca3-983399a91fd8
instance2::MyStruct::<'static,'static,f32,f64,12,false>::UUID -> bbe982ff-fcad-5390-86f0-cce2e7dbae6b
instance3::MyStruct::<'static,'static,f32,f64,12,false>::UUID -> 56d4f1b7-af31-d361-3afb-dc89e52c2ded
instance4::MyStruct::<'static,'static,f32,f64,12,false>::UUID -> 394096e5-5187-edf4-ac77-3f6edc052b72
instance5::MyStruct::<'static,'static,f32,f64,12,false>::UUID -> e7e26201-4095-31d1-bfa3-fd4b62abc938
instance6::MyStruct::<'static,'static,f32,f64,12,false>::UUID -> 0bee6197-ef3e-a446-890a-c34705c30cdd
instance7::MyStruct::<'static,'static,f32,f64,12,false>::UUID -> f8f3fcc7-e4a5-e021-e200-763b4cf9df7a
MyTupleStruct::<f32,f64>::UUID -> ddd04a26-6807-0f27-67b2-227db8f17b75
MyEmptyStruct::UUID -> 4ede75e3-1bf7-5298-ae87-0ee1d57a1357
MyEnum::<f32,f64,>::UUID -> fcad4ca3-6cd0-6c7e-21ea-658a12369d9f
MyEmptyEnum::UUID -> 9dec7519-c5f4-12b9-0509-b5b2ef1d521c
AnotherStruct::<Vec<u16>>::UUID -> 933ae311-b69a-f600-7caa-030743cbb5e5

Traits§

  • Type hash code definition; derive macro for this trait is based on 128bit FNV-1a computed from the type definition
  • Methods for getting type hash under different forms
  • HashedTypeUuidDeprecated
    (Deprecated) Methods for getting type hash under different forms

Functions§

  • Build incremental FNV1a hash code for a bytes sequence and an initial hash code
  • Build initial FNV1a hash code for a bytes sequence