indexed_valued_enums/valued_enum/mod.rs
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
use crate::indexed_enum::{discriminant_internal, Indexed, split_usize_to_isizes};
/// Allows to get a value from an enum's variant, where this enum implements [Indexed], for example,
/// having the following implementation:
///
/// ```rust
/// use indexed_valued_enums::{indexed_enum::Indexed, valued_enum::Valued};
///
///
/// enum Number{ First, Second, Third }
///
/// impl Indexed for Number{
/// const VARIANTS: &'static [Self] = &[Number::First, Number::Second, Number::Third];
/// }
///
/// impl Valued for Number{
/// type Value = u16;
/// const VALUES: &'static [Self::Value] = &[100,200,300];
/// }
/// ```
/// Calling [Valued::value] on every enum produces [First->100, Second->200, Third->300]
///
/// Since the type of the values (u16) implements PartialEq, we can also call
/// [Valued::value_to_variant] to get the variants corresponding to the values
/// [100->First, 200->Second, 300->Third]
///
/// Note this documentation it's solely informational, it is dis-recommended to implement this trait
/// manually, but using the derive macro [crate::Valued] or the declarative macro
/// [crate::create_indexed_valued_enum] instead.
pub trait Valued: Indexed {
/// Type of the values the enumeration resolves to
type Value;
/// Values each enumeration resolves to, each value must be stored to match it's corresponding
/// variant, this means it must be sorted in the same order as [Indexed::VARIANTS]
///
/// This means values must be const
const VALUES: &'static [Self::Value];
/// Gives the value corresponding to this variant, this is an O(1) operation as it just gets the
/// value as a copy from [Valued::VALUES]
///
/// The type of [Valued::Value] doesn't need to implement the [Clone] trait as the array is
/// treated as a raw pointer whose value is read without cloning through
/// [core::ptr::read]
///
/// If you just need a reference to the value, use [Valued::value_ref_opt] instead, as it doesn't
/// do a read copy.
///
/// Note that if implemented correctly (ensured by using [crate::create_indexed_valued_enum]),
/// calling this method will always produce [Option::Some(Value)]
fn value_opt(&self) -> Option<Self::Value> {
value_opt_internal(self)
}
/// Gives the value corresponding to this variant, this is an O(1) operation as it just gets the
/// value as a copy from [Valued::VALUES]
/// If you just need a reference to the value, use [Valued::value_opt] instead, as it doesn't
/// do a read copy.
fn value(&self) -> Self::Value {
self.value_opt().unwrap()
}
/// Gives the value corresponding for a variant of an enum marked with #[repr(usize)] and
/// implementing the [Valued] trait, this is an O(1) operation as it just gets a reference to the
/// value as a copy.
///
/// If you need the value as structure but it doesn't implement clone, use [value_opt_internal]
/// instead, as it performs a read copy
///
/// Note that if implemented correctly (ensured by the declarative macro
/// [crate::create_indexed_valued_enum]), calling this method will always produce
/// [Option::Some(&Value)]
fn value_ref_opt(&self) -> Option<&'static Self::Value> {
value_ref_opt_internal(self)
}
/// Gives the value corresponding for a variant of an enum marked with #[repr(usize)] and
/// implementing the [Valued] trait, this is an O(1) operation as it just gets a reference to the
/// value as a copy.
///
/// If you need the value as structure but it doesn't implement clone, use [value_internal]
/// instead, as it performs a read copy
///
/// Note that if implemented correctly (ensured by the declarative macro
/// [crate::create_indexed_valued_enum]), calling this method will never panic
fn value_ref(&self) -> &'static Self::Value {
value_ref_internal(self)
}
/// Gives variant corresponding to a value, this is an O(n) operation as it does so by comparing
/// every single value contained in [Valued::VALUES]
fn value_to_variant_opt(value: &Self::Value) -> Option<Self> where Self::Value: PartialEq {
let discriminant = Self::VALUES.iter()
.enumerate()
.filter(|(_, variant_value)| value.eq(variant_value)).next()
.map(|(discriminant, _)| discriminant);
Self::from_discriminant_opt(discriminant?)
}
/// Gives variant corresponding to a value, this is an O(n) operation as it does so by comparing
/// every single value contained in [Valued::VALUES]
fn value_to_variant(value: &Self::Value) -> Self where Self::Value: PartialEq {
Self::value_to_variant_opt(value).unwrap()
}
}
/// Gives the value corresponding for a variant of an enum marked with #[repr(usize)], this is an
/// O(1) operation as it just gets the value as a copy from [Valued::VALUES]
///
/// The type of [Valued::Value] doesn't need to implement the [Clone] trait as the array is
/// treated as a raw pointer whose value is read without cloning through
/// [core::ptr::read]
///
/// Note that if implemented correctly (ensured by the declarative macro
/// [crate::create_indexed_valued_enum]), calling this method will always produce
/// [Option::Some(Value)]
pub const fn value_opt_internal<ValuedType: Valued>(variant: &ValuedType) -> Option<ValuedType::Value> {
let discriminant = discriminant_internal(variant);
if discriminant >= ValuedType::VARIANTS.len() { return None; }
let (first_offset, second_offset, third_offset) = split_usize_to_isizes(discriminant);
Some(unsafe { ValuedType::VALUES.as_ptr().offset(first_offset).offset(second_offset).offset(third_offset).read() })
}
/// Gives the value corresponding for a variant of an enum marked with #[repr(usize)], this is an
/// O(1) operation as it just gets the value as a copy from [Valued::VALUES]
///
/// The type of [Valued::Value] doesn't need to implement the [Clone] trait as the array is
/// treated as a raw pointer whose value is read without cloning through
/// [core::ptr::read]
///
/// Note that if implemented correctly (ensured by the declarative macro
/// [crate::create_indexed_valued_enum]), this method should never panic.
pub const fn value_internal<ValuedType: Valued>(variant: &ValuedType) -> ValuedType::Value {
let discriminant = discriminant_internal(variant);
if discriminant >= ValuedType::VARIANTS.len() { panic!("Tried to get a variant's value whose index is larger than the amount of Variants") }
let (first_offset, second_offset, third_offset) = split_usize_to_isizes(discriminant);
unsafe { ValuedType::VALUES.as_ptr().offset(first_offset).offset(second_offset).offset(third_offset).read() }
}
/// Gives the value corresponding for a variant of an enum marked with #[repr(usize)] and
/// implementing the [Valued] trait, this is an O(1) operation as it just gets a reference to the
/// value as a copy.
///
/// If you need the value as structure but it doesn't implement clone, use [value_opt_internal]
/// instead, as it performs a read copy
///
/// Note that if implemented correctly (ensured by the declarative macro
/// [crate::create_indexed_valued_enum]), calling this method will always produce
/// [Option::Some(&Value)]
pub const fn value_ref_opt_internal<ValuedType: Valued>(variant: &ValuedType) -> Option<&'static ValuedType::Value> {
let discriminant = discriminant_internal(variant);
if discriminant >= ValuedType::VARIANTS.len() { return None; }
Some(&ValuedType::VALUES[discriminant])
}
/// Gives the value corresponding for a variant of an enum marked with #[repr(usize)] and
/// implementing the [Valued] trait, this is an O(1) operation as it just gets a reference to the
/// value as a copy.
///
/// If you need the value as structure but it doesn't implement clone, use [value_internal]
/// instead, as it performs a read copy
///
/// Note that if implemented correctly (ensured by the declarative macro
/// [crate::create_indexed_valued_enum]), calling this method will never panic
pub const fn value_ref_internal<ValuedType: Valued>(variant: &ValuedType) -> &'static ValuedType::Value {
let discriminant = discriminant_internal(variant);
if discriminant >= ValuedType::VARIANTS.len() { panic!("Tried to get a variant's value whose index is larger than the amount of Variants") }
&ValuedType::VALUES[discriminant]
}