1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
//! This is part of [**Silx**](https://crates.io/crates/silx) project  
//!   
//! `hashed-type-def-core` contains the core definition and implementations for deriving type hashcode:
//! * 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
//! ```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
//! ```text
//! 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
//! ```txt
//! 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
//! ```
//! 

use hashed_type_def_procmacro::build_hasher;

mod macros;
mod impl_basis;
mod impl_uuid;
#[cfg(feature = "impl_nalgebra")]
mod impl_nalgebra;
#[cfg(feature = "impl_rend")]
mod impl_rend;

/// Type hash code definition; derive macro for this trait is based on 128bit FNV-1a computed from the type definition
/// * `REF = ()` : type parameter `REF` offers more flexibility to rule *Only traits defined in the current crate can be implemented for arbitrary types* 
///   * If `REF` is defined in another crate, then `HashedTypeDef<REF>` can be implemented for arbitrary types in that other crate
///   * This is a stop-gap that should be avoided: the default definition with `REF = ()` should be used.
///   * Derivation macro #\[derive(HashedTypeDef)\] only implements default definition with `REF = ()`
///   * Note: the `silx-core` crate requires implementations with the default definition
pub trait HashedTypeDef<REF = ()> {
    /// native hash computation
    const TYPE_HASH_NATIVE: u128; 
    /// hash encoded to little endianess
    const TYPE_HASH_LE: u128 = {Self::TYPE_HASH_NATIVE.to_le()}; 
    /// hash encoded to big endianess
    const TYPE_HASH_BE: u128 = {Self::TYPE_HASH_NATIVE.to_be()}; 
    /// hash encoded to Uuid
    const UUID: uuid::Uuid = uuid::Uuid::from_u128(<Self as HashedTypeDef<REF>>::TYPE_HASH_NATIVE);
}

// definition of methods `start_hash_fnv1a(bytes: &[u8]) -> u128` and `pub const fn add_hash_fnv1a(bytes: &[u8], mut hash: u128,) -> u128`
build_hasher!();

/// Methods for getting type hash under different forms
/// * This trait is implemented for all objects, but method calls require the object to implement the `HashedTypeDef<REF>` trait
/// * 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
/// * A multiple implementation will require the use of turbofish when calling the methods
pub trait HashedTypeMethods {
    /// return native type hash
    #[inline] fn type_hash_native<REF>() -> u128 where Self: HashedTypeDef<REF> {
        <Self as HashedTypeDef<REF>>::TYPE_HASH_NATIVE
    }
    
    /// return little endianess type hash
    #[inline] fn type_hash_le<REF>() -> u128 where Self: HashedTypeDef<REF> {
        <Self as HashedTypeDef<REF>>::TYPE_HASH_LE
    }
    
    /// return big endianess type hash
    #[inline] fn type_hash_be<REF>() -> u128 where Self: HashedTypeDef<REF> {
        <Self as HashedTypeDef<REF>>::TYPE_HASH_BE
    }
    
    /// return uuid derived from type hash
    #[inline] fn type_uuid<REF>() -> uuid::Uuid where Self: HashedTypeDef<REF> {
        <Self as HashedTypeDef<REF>>::UUID 
    }

    /// return uuid hyphenated string
    #[inline] fn type_uuid_hyphenated<REF>() -> String where Self: HashedTypeDef<REF> {
        Self::type_uuid().as_hyphenated().to_string()
    }

    /// return native type hash from instance
    #[inline] fn self_type_hash_native<REF>(&self) -> u128 where Self: HashedTypeDef<REF> {
        Self::type_hash_native::<REF>()
    }
    
    /// return little endianess type hash from instance
    #[inline] fn self_type_hash_le<REF>(&self) -> u128 where Self: HashedTypeDef<REF> {
        Self::type_hash_le::<REF>()
    }
    
    /// return big endianess type hash from instance
    #[inline] fn self_type_hash_be<REF>(&self) -> u128 where Self: HashedTypeDef<REF> {
        Self::type_hash_be::<REF>()
    }
    
    /// return type hash-derived uuid from instance
    #[inline] fn self_type_uuid<REF>(&self) -> uuid::Uuid where Self: HashedTypeDef<REF> {
        Self::type_uuid::<REF>()
    }

    /// return uuid hyphenated string from instance
    #[inline] fn self_type_uuid_hyphenated<REF>(&self) -> String where Self: HashedTypeDef<REF> {
        Self::type_uuid_hyphenated::<REF>()
    }
}
    
/// (Deprecated) Methods for getting type hash under different forms
/// * Use trait `HashedTypeMethods` instead 
#[deprecated(since="0.1.2", note="please use `HashedTypeMethods` trait")]
pub trait HashedTypeUuid {
    /// return native type hash
    #[inline] fn type_hash_native<REF>() -> u128 where Self: HashedTypeDef<REF> {
        <Self as HashedTypeDef<REF>>::TYPE_HASH_NATIVE
    }
    
    /// return little endianess type hash
    #[inline] fn type_hash_le<REF>() -> u128 where Self: HashedTypeDef<REF> {
        <Self as HashedTypeDef<REF>>::TYPE_HASH_LE
    }
    
    /// return big endianess type hash
    #[inline] fn type_hash_be<REF>() -> u128 where Self: HashedTypeDef<REF> {
        <Self as HashedTypeDef<REF>>::TYPE_HASH_BE
    }
    
    /// return uuid derived from type hash
    #[inline] fn type_uuid<REF>() -> uuid::Uuid where Self: HashedTypeDef<REF> {
        <Self as HashedTypeDef<REF>>::UUID 
    }

    /// return uuid hyphenated string
    #[inline] fn type_uuid_hyphenated<REF>() -> String where Self: HashedTypeDef<REF> {
        Self::type_uuid().as_hyphenated().to_string()
    }

    /// return native type hash from instance
    #[inline] fn self_type_hash_native<REF>(&self) -> u128 where Self: HashedTypeDef<REF> {
        Self::type_hash_native::<REF>()
    }
    
    /// return little endianess type hash from instance
    #[inline] fn self_type_hash_le<REF>(&self) -> u128 where Self: HashedTypeDef<REF> {
        Self::type_hash_le::<REF>()
    }
    
    /// return big endianess type hash from instance
    #[inline] fn self_type_hash_be<REF>(&self) -> u128 where Self: HashedTypeDef<REF> {
        Self::type_hash_be::<REF>()
    }
    
    /// return type hash-derived uuid from instance
    #[inline] fn self_type_uuid<REF>(&self) -> uuid::Uuid where Self: HashedTypeDef<REF> {
        Self::type_uuid::<REF>()
    }

    /// return uuid hyphenated string from instance
    #[inline] fn self_type_uuid_hyphenated<REF>(&self) -> String where Self: HashedTypeDef<REF> {
        Self::type_uuid_hyphenated::<REF>()
    }
}
    
#[allow(deprecated)]
impl<T> HashedTypeUuid for T { }

impl<T> HashedTypeMethods for T { }

#[doc(hidden)]
/// Probes for testing features activation
pub mod probes;