ctutils/traits/
ct_lookup.rs1use crate::{CtAssign, CtEq, CtOption};
2use core::ops::AddAssign;
3
4#[cfg(doc)]
5use core::ops::Index;
6
7pub trait CtLookup<Idx> {
10 type Output: CtAssign;
12
13 #[must_use]
16 fn ct_lookup(&self, index: Idx) -> CtOption<Self::Output>;
17}
18
19impl<T, Idx> CtLookup<Idx> for [T]
20where
21 T: CtAssign + Default,
22 Idx: AddAssign + CtEq + Default + From<u8>,
23{
24 type Output = T;
25
26 #[inline]
27 #[allow(clippy::arithmetic_side_effects)]
28 fn ct_lookup(&self, index: Idx) -> CtOption<T> {
29 let mut ret = CtOption::none();
30 let mut i = Idx::default();
31
32 for item in self {
33 ret.insert_if(item, i.ct_eq(&index));
34
35 i += Idx::from(1u8);
37 }
38
39 ret
40 }
41}
42
43impl<T, Idx, const N: usize> CtLookup<Idx> for [T; N]
44where
45 T: CtAssign + Default,
46 Idx: AddAssign + CtEq + Default + From<u8>,
47{
48 type Output = T;
49
50 #[inline]
51 fn ct_lookup(&self, index: Idx) -> CtOption<T> {
52 self.as_slice().ct_lookup(index)
53 }
54}
55
56#[cfg(feature = "alloc")]
57mod alloc {
58 use super::{AddAssign, CtAssign, CtEq, CtLookup, CtOption};
59 use ::alloc::{boxed::Box, vec::Vec};
60
61 impl<T, Idx> CtLookup<Idx> for Box<[T]>
62 where
63 T: CtAssign + Default,
64 Idx: AddAssign + CtEq + Default + From<u8>,
65 {
66 type Output = T;
67
68 #[inline]
69 fn ct_lookup(&self, index: Idx) -> CtOption<T> {
70 (**self).ct_lookup(index)
71 }
72 }
73
74 impl<T, Idx> CtLookup<Idx> for Vec<T>
75 where
76 T: CtAssign + Default,
77 Idx: AddAssign + CtEq + Default + From<u8>,
78 {
79 type Output = T;
80
81 #[inline]
82 fn ct_lookup(&self, index: Idx) -> CtOption<T> {
83 self.as_slice().ct_lookup(index)
84 }
85 }
86}
87
88#[cfg(test)]
89mod tests {
90 mod array {
91 use crate::CtLookup;
92
93 const EXAMPLE: [u8; 3] = [1, 2, 3];
94
95 #[test]
96 fn ct_lookup_u32() {
97 assert_eq!(EXAMPLE.ct_lookup(0u32).unwrap(), 1);
98 assert_eq!(EXAMPLE.ct_lookup(1u32).unwrap(), 2);
99 assert_eq!(EXAMPLE.ct_lookup(2u32).unwrap(), 3);
100 assert!(EXAMPLE.ct_lookup(3u32).is_none().to_bool());
101 assert!(EXAMPLE.ct_lookup(4u32).is_none().to_bool());
102 }
103
104 #[test]
105 fn ct_lookup_usize() {
106 assert_eq!(EXAMPLE.ct_lookup(0usize).unwrap(), 1);
107 assert_eq!(EXAMPLE.ct_lookup(1usize).unwrap(), 2);
108 assert_eq!(EXAMPLE.ct_lookup(2usize).unwrap(), 3);
109 assert!(EXAMPLE.ct_lookup(3usize).is_none().to_bool());
110 assert!(EXAMPLE.ct_lookup(4usize).is_none().to_bool());
111 }
112 }
113
114 mod slice {
115 use crate::CtLookup;
116
117 const EXAMPLE: &[u8] = &[1, 2, 3];
118
119 #[test]
120 fn ct_lookup_u32() {
121 assert_eq!(EXAMPLE.ct_lookup(0u32).unwrap(), 1);
122 assert_eq!(EXAMPLE.ct_lookup(1u32).unwrap(), 2);
123 assert_eq!(EXAMPLE.ct_lookup(2u32).unwrap(), 3);
124 assert!(EXAMPLE.ct_lookup(3u32).is_none().to_bool());
125 assert!(EXAMPLE.ct_lookup(4u32).is_none().to_bool());
126 }
127
128 #[test]
129 fn ct_lookup_usize() {
130 assert_eq!(EXAMPLE.ct_lookup(0usize).unwrap(), 1);
131 assert_eq!(EXAMPLE.ct_lookup(1usize).unwrap(), 2);
132 assert_eq!(EXAMPLE.ct_lookup(2usize).unwrap(), 3);
133 assert!(EXAMPLE.ct_lookup(3usize).is_none().to_bool());
134 assert!(EXAMPLE.ct_lookup(4usize).is_none().to_bool());
135 }
136 }
137}