linearize/linearized.rs
1use {
2 crate::Linearize,
3 core::{
4 cmp::Ordering,
5 fmt::{Debug, Formatter},
6 hash::{Hash, Hasher},
7 marker::PhantomData,
8 },
9};
10
11/// Pre-computed output of [Linearize::linearize].
12///
13/// [StaticMap] and [StaticCopyMap] can be index directly with a [Linearize] type.
14/// That operation computes the output of [linearize] ad-hoc. While the linearize function
15/// is zero cost for many types, you might be using types for which the cost is non-zero
16/// or unknown.
17///
18/// In such situations, the `Linearized` type allows you to cache the output of
19/// [linearize].
20///
21/// It is guaranteed that the value cached by this type is the output of the linearize
22/// function. In particular, the value is less than [LENGTH].
23///
24/// # Example
25///
26/// ```rust
27/// # use linearize::{Linearize, LinearizeExt, StaticMap};
28/// fn add_one<L: Linearize>(map: &mut StaticMap<L, u8>, key: L) {
29/// let key = key.linearized();
30/// let v = map[key];
31/// map[key] = v + 1;
32/// }
33/// ```
34///
35/// # Trait Implementations
36///
37/// This type implements traits such as [Debug], [Hash], etc. These implementations
38/// operate on the pre-computed `usize`. In particular, the [Debug] implementation does
39/// not print the name of the original value used to create this object.
40///
41/// [StaticMap]: crate::StaticMap
42/// [StaticCopyMap]: crate::StaticCopyMap
43/// [linearize]: Linearize::linearize
44/// [LENGTH]: Linearize::LENGTH
45#[repr(transparent)]
46pub struct Linearized<L>
47where
48 L: ?Sized,
49{
50 index: usize,
51 _phantom: PhantomData<L>,
52}
53
54impl<L> Linearized<L>
55where
56 L: ?Sized,
57{
58 /// Pre-computes the linearized value.
59 ///
60 /// This function pre-computes the output of [linearize](Linearize::linearize).
61 ///
62 /// The [LinearizeExt](crate::LinearizeExt) extension trait provides the
63 /// [linearized](crate::LinearizeExt::linearized) function which does the same.
64 ///
65 /// # Example
66 ///
67 /// ```rust
68 /// # use linearize::{Linearize, LinearizeExt, Linearized, StaticMap};
69 /// fn get_value<L: Linearize>(map: &StaticMap<L, u8>, key: L) -> u8 {
70 /// map[Linearized::new(&key)]
71 /// // Or: map[key.linearized()]
72 /// }
73 /// ```
74 pub fn new(l: &L) -> Self
75 where
76 L: Linearize,
77 {
78 unsafe {
79 // SAFETY: l.linearize() guarantees that it is less than L::LENGTH.
80 Self::new_unchecked(l.linearize())
81 }
82 }
83
84 /// Wraps an already computed values.
85 ///
86 /// # Safety
87 ///
88 /// The index must be less than `L::LENGTH`.
89 pub const unsafe fn new_unchecked(index: usize) -> Self {
90 Self {
91 index,
92 _phantom: PhantomData,
93 }
94 }
95
96 /// Returns the linearized value.
97 ///
98 /// This function returns the output of [linearize](Linearize::linearize) that was
99 /// computed when this object was created.
100 ///
101 /// # Example
102 ///
103 /// ```rust
104 /// # use linearize::{Linearize, LinearizeExt};
105 /// fn get<L: Linearize>(key: L) {
106 /// assert_eq!(key.linearized().get(), key.linearize());
107 /// }
108 /// ```
109 pub fn get(self) -> usize {
110 self.index
111 }
112
113 /// Returns the value that was used to create this object.
114 ///
115 /// This function returns the output of
116 /// [from_linear_unchecked](Linearize::from_linear_unchecked). This value is required
117 /// to be the same that was used to create this object.
118 ///
119 /// # Example
120 ///
121 /// ```rust
122 /// # use std::fmt::Debug;
123 /// # use linearize::{Linearize, LinearizeExt};
124 /// fn get<L: Linearize + Eq + Debug>(key: L) {
125 /// assert_eq!(key.linearized().delinearize(), key);
126 /// }
127 /// ```
128 pub fn delinearize(self) -> L
129 where
130 L: Linearize + Sized,
131 {
132 unsafe {
133 // SAFETY: self.index is only written by Self::new_unchecked which requires
134 // that it is less than L::LENGTH.
135 L::from_linear_unchecked(self.index)
136 }
137 }
138}
139
140impl<L> Copy for Linearized<L> where L: ?Sized {}
141
142impl<L> Clone for Linearized<L>
143where
144 L: ?Sized,
145{
146 fn clone(&self) -> Self {
147 *self
148 }
149}
150
151impl<L> Debug for Linearized<L>
152where
153 L: ?Sized,
154{
155 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
156 self.index.fmt(f)
157 }
158}
159
160impl<L> Hash for Linearized<L>
161where
162 L: ?Sized,
163{
164 fn hash<H: Hasher>(&self, state: &mut H) {
165 self.index.hash(state)
166 }
167}
168
169impl<L> PartialEq for Linearized<L>
170where
171 L: ?Sized,
172{
173 fn eq(&self, other: &Self) -> bool {
174 self.index == other.index
175 }
176}
177
178impl<L> PartialEq<usize> for Linearized<L>
179where
180 L: ?Sized,
181{
182 fn eq(&self, other: &usize) -> bool {
183 self.index == *other
184 }
185}
186
187impl<L> Eq for Linearized<L> where L: ?Sized {}
188
189impl<L> PartialOrd for Linearized<L>
190where
191 L: ?Sized,
192{
193 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
194 Some(self.cmp(other))
195 }
196}
197
198impl<L> PartialOrd<usize> for Linearized<L>
199where
200 L: ?Sized,
201{
202 fn partial_cmp(&self, other: &usize) -> Option<Ordering> {
203 self.index.partial_cmp(other)
204 }
205}
206
207impl<L> Ord for Linearized<L>
208where
209 L: ?Sized,
210{
211 fn cmp(&self, other: &Self) -> Ordering {
212 self.index.cmp(&other.index)
213 }
214}