hashed_type_def_core/
lib.rs

1//! This is part of [**Silx**](https://crates.io/crates/silx) project  
2//!   
3//! `hashed-type-def-core` contains the core definition and implementations for deriving type hashcode:
4//! * The hashcode is generated as `u128` constant and as `Uuid` constant
5//! * The hashcode generated by the derive macro is built from the morphology of the type definition and does not depend on the rust version  
6//! 
7//! 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
8//! 
9//! # Content
10//! The crate provides two traits `HashedTypeDef` and `HashedTypeMethods`
11//! * the `HashedTypeDef` trait is the basis for defining a type's hashcode
12//!   * It provides constant value of the hashcode under `u128` and `Uuid` formats
13//! * the `HashedTypeMethods` trait provides additional methods for accessing the hashcode  
14//! 
15//! The regular way to implement `HashedTypeDef` is by using the procedural macro `#[derive(HashedTypeDef)]`  
16//! 
17//! The following example gives an overview of `hashed-type-def` features.
18//! 
19//! # Example of type hashcode implementation
20//! ## Cargo.toml
21//! ```toml
22//! [package]
23//! name = "silx_hashed-type-def_examples"
24//! version = "0.1.2"
25//! edition = "2021"
26//! 
27//! [dependencies]
28//! uuid = "1.7.0"
29//! hashed-type-def = { version = "0.1.2", features = ["derive"] }
30//! ```
31//! ## main.rs
32//! ```text
33//! use std::fmt::Debug;
34//! 
35//! use hashed_type_def::{ HashedTypeDef, add_hashed_type_def_param, };
36//! 
37//! /// case 1: a named structure to be tested with procedural derivation
38//! /// * procedural macro `#[derive(HashedTypeDef)]` is the regular way to implement `HashedTypeDef`
39//! #[derive(Debug,HashedTypeDef)]
40//! struct MyStruct<'a,'b,T,U: Debug,const C1: usize, const C2: bool> where T: Into<U> + 'b, 'a: 'b {
41//!     #[allow(dead_code)] un: &'a String,
42//!     #[allow(dead_code)] deux: T,
43//!     #[allow(dead_code)] trois: &'b U,
44//! }
45//! 
46//! pub mod instance0 {
47//!     use hashed_type_def::HashedTypeDef;
48//!     use std::fmt::Debug;
49//! 
50//!     /// case 2: a structure with same definition and procedural derivation as case 1
51//!     /// * type hash should be the same than case 1
52//!     #[derive(Debug,HashedTypeDef)]
53//!     pub struct MyStruct<'a,'b,T,U: Debug,const C1: usize, const C2: bool> where T: Into<U> + 'b, 'a: 'b {
54//!         #[allow(dead_code)] un: &'a String,
55//!         #[allow(dead_code)] deux: T,
56//!         #[allow(dead_code)] trois: &'b U,
57//!     }
58//! } 
59//! 
60//! pub mod instance1 {
61//!     use hashed_type_def::{ add_hashed_type_def, HashedTypeDef, };
62//!     use std::fmt::Debug;
63//!     /// 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
64//!     /// * type hash should be the same than case 1
65//!     pub struct MyStruct<'a,'b,T,U: Debug,const C1: usize, const C2: bool> where T: Into<U> + 'b, 'a: 'b {
66//!         #[allow(dead_code)] un: &'a String,
67//!         #[allow(dead_code)] deux: T,
68//!         #[allow(dead_code)] trois: &'b U,
69//!     }
70//! 
71//!     add_hashed_type_def!{
72//!         pub struct MyStruct<'a,'b,T,U: Debug,const C1: usize, const C2: bool> where T: Into<U> + 'b, 'a: 'b {
73//!             un: &'a String,
74//!             deux: T,
75//!             trois: &'b U,
76//!         }    
77//!     }
78//! } 
79//! 
80//! pub mod instance2 {
81//!     use hashed_type_def::HashedTypeDef;
82//!     use std::fmt::Debug;
83//!     /// case 4: a structure with procedural derivation and same definition as case 1 except a swap on lifetime names
84//!     /// * type hash should be different than case 1
85//!     #[derive(Debug,HashedTypeDef)]
86//!     pub struct MyStruct<'b,'a,T,U: Debug,const C1: usize, const C2: bool> where T: Into<U> + 'a, 'b: 'a {
87//!         #[allow(dead_code)] un: &'b String,
88//!         #[allow(dead_code)] deux: T,
89//!         #[allow(dead_code)] trois: &'a U,
90//!     }
91//! } 
92//! 
93//! pub mod instance3 {
94//!     use hashed_type_def::{ add_hashed_type_def, HashedTypeDef, };
95//!     use std::fmt::Debug;
96//!     /// case 5: a structure with same definition as case 1 and post derivation obtained by macro `add_hashed_type_def!` processing on altered definition
97//!     /// * type hash should be different than case 1
98//!     pub struct MyStruct<'a,'b,T,U: Debug,const C1: usize, const C2: bool> where T: Into<U> + 'b, 'a: 'b {
99//!         #[allow(dead_code)] un: &'a String,
100//!         #[allow(dead_code)] deux: T,
101//!         #[allow(dead_code)] trois: &'b U,
102//!     }
103//! 
104//!     add_hashed_type_def!{
105//!         pub struct MyStruct<'a,'b,T,U: Debug,const C1: usize, const C2: bool> where T: Into<U> + 'b, 'a: 'b {
106//!             instance3_MyStruct: (),
107//!             un: &'a String,
108//!             deux: T,
109//!             trois: &'b U,
110//!         }    
111//!     }
112//! } 
113//! 
114//! pub mod instance4 {
115//!     use hashed_type_def::HashedTypeDef;
116//!     use std::fmt::Debug;
117//!     /// case 6: a structure with procedural derivation and same definition as case 1 except conditions are moved to where clauses
118//!     /// * type hash should be different than case 1
119//!     #[derive(Debug,HashedTypeDef)]
120//!     pub struct MyStruct<'a,'b,T,U,const C1: usize, const C2: bool> where 'a: 'b, T: Into<U> + 'b, U: Debug, {
121//!         #[allow(dead_code)] un: &'a String,
122//!         #[allow(dead_code)] deux: T,
123//!         #[allow(dead_code)] trois: &'b U,
124//!     }
125//! } 
126//! 
127//! pub mod instance5 {
128//!     use hashed_type_def::HashedTypeDef;
129//!     use std::fmt::Debug;
130//!     /// case 7: a structure with procedural derivation and same definition as case 1 except conditions are moved from where clauses
131//!     /// * type hash should be different than case 1
132//!     #[derive(Debug,HashedTypeDef)]
133//!     pub struct MyStruct<'a: 'b,'b, T: Into<U> + 'b, U: Debug, const C1: usize, const C2: bool> {
134//!         #[allow(dead_code)] un: &'a String,
135//!         #[allow(dead_code)] deux: T,
136//!         #[allow(dead_code)] trois: &'b U,
137//!     }
138//! } 
139//! 
140//! pub mod instance6 {
141//!     use hashed_type_def::HashedTypeDef;
142//!     use std::fmt::Debug;
143//!     /// case 8: a structure with procedural derivation and same definition as case 1 except a conditions is removed from parameters list
144//!     /// * type hash should be different than case 1    
145//!     #[derive(Debug,HashedTypeDef)]
146//!     pub struct MyStruct<'a,'b,T,U,const C1: usize, const C2: bool> where T: Into<U> + 'b, 'a: 'b {
147//!         #[allow(dead_code)] un: &'a String,
148//!         #[allow(dead_code)] deux: T,
149//!         #[allow(dead_code)] trois: &'b U,
150//!     }
151//! } 
152//! 
153//! pub mod instance7 {
154//!     use hashed_type_def::HashedTypeDef;
155//!     use std::fmt::Debug;
156//!     /// case 9: a structure with procedural derivation and same definition as case 1 except a condition is removed from where clauses
157//!     /// * type hash should be different than case 1
158//!     #[derive(Debug,HashedTypeDef)]
159//!     pub struct MyStruct<'a,'b,T,U: Debug,const C1: usize, const C2: bool> where T: Into<U> + 'b, {
160//!         #[allow(dead_code)] un: &'a String,
161//!         #[allow(dead_code)] deux: T,
162//!         #[allow(dead_code)] trois: &'b U,
163//!     }
164//! } 
165//! 
166//! /// build type hash (Uuid format) of case 1 for specific lifetime
167//! /// * type hash should not change
168//! fn fn_type_hash<'a: 'b,'b>(_tmp1: &'a (), _tmp2: &'b ()) -> uuid::Uuid { MyStruct::<'a,'b,f32,f64,12,true>::UUID }
169//! 
170//! /// case 10: a unnamed structure to be tested with procedural derivation
171//! #[derive(Debug,HashedTypeDef)]
172//! struct MyTupleStruct<T,U: Debug>(String,T,U,) where T: Into<U>;
173//! 
174//! /// case 11: a unit structure to be tested with procedural derivation
175//! #[derive(Debug,HashedTypeDef)]
176//! struct MyEmptyStruct;
177//! 
178//! /// case 12: enum to be tested with procedural derivation
179//! #[derive(Debug,HashedTypeDef)]
180//! enum MyEnum<T,U: Debug> where T: Into<U> {
181//!     #[allow(dead_code)] Zero,
182//!     #[allow(dead_code)] Un(String, T,),
183//!     #[allow(dead_code)] Deux {
184//!         double: f64,
185//!         trois: U,
186//!     },
187//!     #[allow(dead_code)] Trois,
188//! }
189//! 
190//! /// case 13: empty enum to be tested with procedural derivation
191//! #[derive(Debug,HashedTypeDef)]
192//! enum MyEmptyEnum { }
193//! 
194//! /// case 14: a struct to be tested with post derivation with parameter tag `(Option<u32>,[u128;24])`
195//! struct AnotherStruct<T: Debug> where T: Default { #[allow(dead_code)] t: T }
196//! 
197//! add_hashed_type_def_param!((Option<u32>,[u128;24]); struct AnotherStruct<T: Debug> where T: Default { t: T });
198//! 
199//! /// Different cases of type hash derivation
200//! fn main() {
201//!     // case 1 with `true` parameter
202//!     println!("MyStruct::<'static,'static,f32,f64,12,true>::UUID -> {:x}", MyStruct::<'static,'static,f32,f64,12,true>::UUID);
203//!     // case 1 with `true` parameter and different lifetime
204//!     println!("MyStruct::<'a,'b,f32,f64,12,true>::UUID -> {:x}", { let a = (); { let b = (); fn_type_hash(&a,&b) } });
205//!     // case 1 with `false` parameter
206//!     println!("MyStruct::<'static,'static,f32,f64,12,false>::UUID -> {:x}", MyStruct::<'static,'static,f32,f64,12,false>::UUID);
207//!     // case 2 with `false` parameter
208//!     println!("instance0::MyStruct::<'static,'static,f32,f64,12,false>::UUID -> {:x}", instance0::MyStruct::<'static,'static,f32,f64,12,false>::UUID);
209//!     // case 3 with `false` parameter
210//!     println!("instance1::MyStruct::<'static,'static,f32,f64,12,false>::UUID -> {:x}", instance1::MyStruct::<'static,'static,f32,f64,12,false>::UUID);
211//!     // case 4 with `false` parameter
212//!     println!("instance2::MyStruct::<'static,'static,f32,f64,12,false>::UUID -> {:x}", instance2::MyStruct::<'static,'static,f32,f64,12,false>::UUID);
213//!     // case 5 with `false` parameter
214//!     println!("instance3::MyStruct::<'static,'static,f32,f64,12,false>::UUID -> {:x}", instance3::MyStruct::<'static,'static,f32,f64,12,false>::UUID);
215//!     // case 6 with `false` parameter
216//!     println!("instance4::MyStruct::<'static,'static,f32,f64,12,false>::UUID -> {:x}", instance4::MyStruct::<'static,'static,f32,f64,12,false>::UUID);
217//!     // case 7 with `false` parameter
218//!     println!("instance5::MyStruct::<'static,'static,f32,f64,12,false>::UUID -> {:x}", instance5::MyStruct::<'static,'static,f32,f64,12,false>::UUID);
219//!     // case 8 with `false` parameter
220//!     println!("instance6::MyStruct::<'static,'static,f32,f64,12,false>::UUID -> {:x}", instance6::MyStruct::<'static,'static,f32,f64,12,false>::UUID);
221//!     // case 9 with `false` parameter
222//!     println!("instance7::MyStruct::<'static,'static,f32,f64,12,false>::UUID -> {:x}", instance7::MyStruct::<'static,'static,f32,f64,12,false>::UUID);
223//!     // case 10
224//!     println!("MyTupleStruct::<f32,f64>::UUID -> {:x}", MyTupleStruct::<f32,f64>::UUID);
225//!     // case 11
226//!     println!("MyEmptyStruct::UUID -> {:x}", MyEmptyStruct::UUID);
227//!     // case 12
228//!     println!("MyEnum::<f32,f64,>::UUID -> {:x}", MyEnum::<f32,f64,>::UUID);
229//!     // case 13
230//!     println!("MyEmptyEnum::UUID -> {:x}", MyEmptyEnum::UUID);
231//!     // case 14
232//!     println!("AnotherStruct::<Vec<u16>>::UUID -> {:x}", AnotherStruct::<Vec<u16>>::UUID);
233//! }
234//! ```
235//! ## Typical output
236//! ```txt
237//! MyStruct::<'static,'static,f32,f64,12,true>::UUID -> bd84ac66-d0fa-5d1c-ae5e-25647a13dcb3
238//! MyStruct::<'a,'b,f32,f64,12,true>::UUID -> bd84ac66-d0fa-5d1c-ae5e-25647a13dcb3
239//! MyStruct::<'static,'static,f32,f64,12,false>::UUID -> 1a8a7365-1c9c-afed-cca3-983399a91fd8
240//! instance0::MyStruct::<'static,'static,f32,f64,12,false>::UUID -> 1a8a7365-1c9c-afed-cca3-983399a91fd8
241//! instance1::MyStruct::<'static,'static,f32,f64,12,false>::UUID -> 1a8a7365-1c9c-afed-cca3-983399a91fd8
242//! instance2::MyStruct::<'static,'static,f32,f64,12,false>::UUID -> bbe982ff-fcad-5390-86f0-cce2e7dbae6b
243//! instance3::MyStruct::<'static,'static,f32,f64,12,false>::UUID -> 56d4f1b7-af31-d361-3afb-dc89e52c2ded
244//! instance4::MyStruct::<'static,'static,f32,f64,12,false>::UUID -> 394096e5-5187-edf4-ac77-3f6edc052b72
245//! instance5::MyStruct::<'static,'static,f32,f64,12,false>::UUID -> e7e26201-4095-31d1-bfa3-fd4b62abc938
246//! instance6::MyStruct::<'static,'static,f32,f64,12,false>::UUID -> 0bee6197-ef3e-a446-890a-c34705c30cdd
247//! instance7::MyStruct::<'static,'static,f32,f64,12,false>::UUID -> f8f3fcc7-e4a5-e021-e200-763b4cf9df7a
248//! MyTupleStruct::<f32,f64>::UUID -> ddd04a26-6807-0f27-67b2-227db8f17b75
249//! MyEmptyStruct::UUID -> 4ede75e3-1bf7-5298-ae87-0ee1d57a1357
250//! MyEnum::<f32,f64,>::UUID -> fcad4ca3-6cd0-6c7e-21ea-658a12369d9f
251//! MyEmptyEnum::UUID -> 9dec7519-c5f4-12b9-0509-b5b2ef1d521c
252//! AnotherStruct::<Vec<u16>>::UUID -> 933ae311-b69a-f600-7caa-030743cbb5e5
253//! ```
254//! 
255
256use hashed_type_def_procmacro::build_hasher;
257
258mod macros;
259mod impl_basis;
260mod impl_uuid;
261#[cfg(feature = "impl_nalgebra")]
262mod impl_nalgebra;
263#[cfg(feature = "impl_rend")]
264mod impl_rend;
265
266/// Type hash code definition; derive macro for this trait is based on 128bit FNV-1a computed from the type definition
267/// * `REF = ()` : type parameter `REF` offers more flexibility to rule *Only traits defined in the current crate can be implemented for arbitrary types* 
268///   * If `REF` is defined in another crate, then `HashedTypeDef<REF>` can be implemented for arbitrary types in that other crate
269///   * This is a stop-gap that should be avoided: the default definition with `REF = ()` should be used.
270///   * Derivation macro #\[derive(HashedTypeDef)\] only implements default definition with `REF = ()`
271///   * Note: the `silx-core` crate requires implementations with the default definition
272pub trait HashedTypeDef<REF = ()> {
273    /// native hash computation
274    const TYPE_HASH_NATIVE: u128; 
275    /// hash encoded to little endianess
276    const TYPE_HASH_LE: u128 = {Self::TYPE_HASH_NATIVE.to_le()}; 
277    /// hash encoded to big endianess
278    const TYPE_HASH_BE: u128 = {Self::TYPE_HASH_NATIVE.to_be()}; 
279    /// hash encoded to Uuid
280    const UUID: uuid::Uuid = uuid::Uuid::from_u128(<Self as HashedTypeDef<REF>>::TYPE_HASH_NATIVE);
281}
282
283// definition of methods `start_hash_fnv1a(bytes: &[u8]) -> u128` and `pub const fn add_hash_fnv1a(bytes: &[u8], mut hash: u128,) -> u128`
284build_hasher!();
285
286/// Methods for getting type hash under different forms
287/// * This trait is implemented for all objects, but method calls require the object to implement the `HashedTypeDef<REF>` trait
288/// * In normal use, the type to be evaluated must implement the `HashedTypeDef<REF>` trait for one and only one `REF` parameter, and typically the default `Ref=()` parameter
289/// * A multiple implementation will require the use of turbofish when calling the methods
290pub trait HashedTypeMethods {
291    /// return native type hash
292    #[inline] fn type_hash_native<REF>() -> u128 where Self: HashedTypeDef<REF> {
293        <Self as HashedTypeDef<REF>>::TYPE_HASH_NATIVE
294    }
295    
296    /// return little endianess type hash
297    #[inline] fn type_hash_le<REF>() -> u128 where Self: HashedTypeDef<REF> {
298        <Self as HashedTypeDef<REF>>::TYPE_HASH_LE
299    }
300    
301    /// return big endianess type hash
302    #[inline] fn type_hash_be<REF>() -> u128 where Self: HashedTypeDef<REF> {
303        <Self as HashedTypeDef<REF>>::TYPE_HASH_BE
304    }
305    
306    /// return uuid derived from type hash
307    #[inline] fn type_uuid<REF>() -> uuid::Uuid where Self: HashedTypeDef<REF> {
308        <Self as HashedTypeDef<REF>>::UUID 
309    }
310
311    /// return uuid hyphenated string
312    #[inline] fn type_uuid_hyphenated<REF>() -> String where Self: HashedTypeDef<REF> {
313        Self::type_uuid().as_hyphenated().to_string()
314    }
315
316    /// return native type hash from instance
317    #[inline] fn self_type_hash_native<REF>(&self) -> u128 where Self: HashedTypeDef<REF> {
318        Self::type_hash_native::<REF>()
319    }
320    
321    /// return little endianess type hash from instance
322    #[inline] fn self_type_hash_le<REF>(&self) -> u128 where Self: HashedTypeDef<REF> {
323        Self::type_hash_le::<REF>()
324    }
325    
326    /// return big endianess type hash from instance
327    #[inline] fn self_type_hash_be<REF>(&self) -> u128 where Self: HashedTypeDef<REF> {
328        Self::type_hash_be::<REF>()
329    }
330    
331    /// return type hash-derived uuid from instance
332    #[inline] fn self_type_uuid<REF>(&self) -> uuid::Uuid where Self: HashedTypeDef<REF> {
333        Self::type_uuid::<REF>()
334    }
335
336    /// return uuid hyphenated string from instance
337    #[inline] fn self_type_uuid_hyphenated<REF>(&self) -> String where Self: HashedTypeDef<REF> {
338        Self::type_uuid_hyphenated::<REF>()
339    }
340}
341    
342/// (Deprecated) Methods for getting type hash under different forms
343/// * Use trait `HashedTypeMethods` instead 
344#[deprecated(since="0.1.2", note="please use `HashedTypeMethods` trait")]
345pub trait HashedTypeUuid {
346    /// return native type hash
347    #[inline] fn type_hash_native<REF>() -> u128 where Self: HashedTypeDef<REF> {
348        <Self as HashedTypeDef<REF>>::TYPE_HASH_NATIVE
349    }
350    
351    /// return little endianess type hash
352    #[inline] fn type_hash_le<REF>() -> u128 where Self: HashedTypeDef<REF> {
353        <Self as HashedTypeDef<REF>>::TYPE_HASH_LE
354    }
355    
356    /// return big endianess type hash
357    #[inline] fn type_hash_be<REF>() -> u128 where Self: HashedTypeDef<REF> {
358        <Self as HashedTypeDef<REF>>::TYPE_HASH_BE
359    }
360    
361    /// return uuid derived from type hash
362    #[inline] fn type_uuid<REF>() -> uuid::Uuid where Self: HashedTypeDef<REF> {
363        <Self as HashedTypeDef<REF>>::UUID 
364    }
365
366    /// return uuid hyphenated string
367    #[inline] fn type_uuid_hyphenated<REF>() -> String where Self: HashedTypeDef<REF> {
368        Self::type_uuid().as_hyphenated().to_string()
369    }
370
371    /// return native type hash from instance
372    #[inline] fn self_type_hash_native<REF>(&self) -> u128 where Self: HashedTypeDef<REF> {
373        Self::type_hash_native::<REF>()
374    }
375    
376    /// return little endianess type hash from instance
377    #[inline] fn self_type_hash_le<REF>(&self) -> u128 where Self: HashedTypeDef<REF> {
378        Self::type_hash_le::<REF>()
379    }
380    
381    /// return big endianess type hash from instance
382    #[inline] fn self_type_hash_be<REF>(&self) -> u128 where Self: HashedTypeDef<REF> {
383        Self::type_hash_be::<REF>()
384    }
385    
386    /// return type hash-derived uuid from instance
387    #[inline] fn self_type_uuid<REF>(&self) -> uuid::Uuid where Self: HashedTypeDef<REF> {
388        Self::type_uuid::<REF>()
389    }
390
391    /// return uuid hyphenated string from instance
392    #[inline] fn self_type_uuid_hyphenated<REF>(&self) -> String where Self: HashedTypeDef<REF> {
393        Self::type_uuid_hyphenated::<REF>()
394    }
395}
396    
397#[allow(deprecated)]
398impl<T> HashedTypeUuid for T { }
399
400impl<T> HashedTypeMethods for T { }
401
402#[doc(hidden)]
403/// Probes for testing features activation
404pub mod probes;