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
//! Author --- daniel.bechaz@gmail.com //! Last Moddified --- 2018/03/13 use super::*; /// Derives an `identifier` from a value. /// /// `DeriveIdent` is a "quality of life" trait when using [`WithIdent`](./struct.WithIdent.html). /// /// Any type `T` which implements this trait can easily be converted into a /// `WithIdent<T, I,>` instance using `From` and `Into`. pub trait DeriveIdent<I,> { /// Returns an `Identifier` value derived from the passed `value`. /// /// Note: this is an associated function, which means that you have to call it as /// `DeriveIdent::derive_ident(value)` instead of `value.derive_ident()`. This is so /// that there is no conflict with a method on the inner type. /// /// # Examples /// /// ```rust /// # extern crate ident; /// # use ident::*; /// # fn main() { /// assert_eq!(5, DeriveIdent::derive_ident(&5)); //Integer types return themselves by default. /// /// let wi = WithIdent::from(5); /// assert_eq!(wi.ident(), &5); /// assert_eq!(*wi, 5); /// # } /// ``` fn derive_ident(value: &Self) -> I; } impl<T: DeriveIdent<I,>, I,> From<T> for WithIdent<T, I,> { fn from(from: T) -> Self { Self::new(DeriveIdent::derive_ident(&from), from) } } impl<T: DeriveIdent<I,> + Default, I,> Default for WithIdent<T, I,> { fn default() -> Self { T::default().into() } } impl<T: DeriveIdent<I,>, I,> WithIdent<T, I,> { /// Consumes the `WithIdent` and returns a new instance with an updated `identifier` /// derived from the inner value. /// /// Note: this is an associated function, which means that you have to call it as /// `WithIdent::update_ident(wi)` instead of `wi.update_ident()`. This is so that /// there is no conflict with a method on the inner type. /// /// # Examples /// /// ```rust /// # extern crate ident; /// # use ident::*; /// # fn main() { /// let mut wi = WithIdent::from(5); /// assert_eq!(5, *wi.ident()); /// /// *wi = 10; /// wi = WithIdent::update_ident(wi); /// assert_eq!(10, *wi.ident()); /// # } /// ``` #[inline] pub fn update_ident(mut wi: Self) -> Self { wi.identifier = DeriveIdent::derive_ident(&wi.value); wi } } /// In some cases, such as `integer` types, a value is its own unique `identifier`. /// /// This macro implements [`DeriveIdent`](./trait.DeriveIdent.html) for the passed type to /// simply return itself. (NOTE: the type must derive `Clone`) #[macro_export] macro_rules! impl_identity { ($type:ty) => { impl DeriveIdent<$type> for $type { fn derive_ident(value: &Self) -> $type { value.clone() } } }; ($type:tt $($t:tt)*) => { impl_identity!($type); impl_identity!($($t)*); }; } impl_identity! { usize isize u8 i8 u16 i16 u32 i32 u64 i64 } /// A hash is often a useful and convenient `identifier` value. /// /// This macro implements [`DeriveIdent<u64>`](./trait.DeriveIdent.html) for the passed /// type using the passed [`Hasher`](https://doc.rust-lang.org/std/hash/trait.Hasher.html). /// (NOTE: the type must derive [`Hash`](https://doc.rust-lang.org/std/hash/trait.Hash.html)) /// /// # Examples /// /// ```rust /// #[macro_use] /// extern crate ident; /// /// use std::collections::hash_map::DefaultHasher; /// use ident::*; /// /// #[derive(Hash)] /// struct MyType(pub usize); /// /// //Implements DeriveIdent<u64> for MyType using DefaultHasher to calculate the hash. /// impl_hash_identity!(MyType, DefaultHasher); /// /// fn main() { /// let x = MyType(5); /// println!("{}", DeriveIdent::<u64>::derive_ident(&x)); /// } /// ``` #[macro_export] macro_rules! impl_hash_identity { (($type:tt, $hasher:tt)) => { impl DeriveIdent<u64> for $type { fn derive_ident(value: &Self) -> u64 { use std::hash::{Hash, Hasher}; let mut hasher = $hasher::default(); value.hash(&mut hasher); hasher.finish() } } }; (($type:tt, $hasher:tt) $($t:tt)*) => { impl_hash_identity!(($type, $hasher)); impl_hash_identity!($($t)*); }; ($type:tt, $hasher:tt) => (impl_hash_identity!(($type, $hasher));); }