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;