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]
}