Skip to main content

dactyl/nice/
nice_u8.rs

1/*!
2# Dactyl: Nice `u8`.
3*/
4
5use super::{
6	nice_arr,
7	nice_str,
8	nice_uint,
9	NiceChar,
10};
11use std::num::NonZeroU8;
12
13
14
15#[repr(u8)]
16#[derive(Debug, Clone, Copy, Eq, Ord, PartialEq, PartialOrd)]
17/// # `NiceU8` Indices.
18enum NiceU8Idx {
19	From00 = 0_u8, // 2
20	From01 = 1_u8, // 5
21	From02 = 2_u8, // 5
22}
23
24#[cfg_attr(
25	not(test),
26	expect(dead_code, reason = "For consistency with bigger index types.")
27)]
28impl NiceU8Idx {
29	/// # Digit Indices (Reverse Order).
30	const DIGITS: [Self; 3] = [
31		Self::From02, Self::From01, Self::From00,
32	];
33
34	/// # Last.
35	const LAST: Self = Self::From02;
36
37	/// # Length.
38	const LEN: usize = 3;
39}
40
41
42
43nice_uint! {
44	NiceU8, NiceU8Idx,
45	u8, NonZeroU8,
46	[ 0 0 0 ],
47	[ 2 5 5 ]
48}
49
50impl From<u8> for NiceU8 {
51	#[inline]
52	fn from(src: u8) -> Self {
53		let (data, from) = data_from(src);
54		Self { data, from }
55	}
56}
57
58impl NiceU8 {
59	#[must_use]
60	#[inline]
61	/// # Double Digit Bytes.
62	///
63	/// This method returns a zero-padded two-byte representation of the
64	/// nice value, _except_ for values requiring three digits (i.e. `100+`).
65	///
66	/// ## Examples
67	///
68	/// ```
69	/// assert_eq!(dactyl::NiceU8::from(3).as_bytes2(), b"03");
70	/// assert_eq!(dactyl::NiceU8::from(50).as_bytes2(), b"50");
71	/// assert_eq!(dactyl::NiceU8::from(113).as_bytes2(), b"113");
72	/// ```
73	pub const fn as_bytes2(&self) -> &[u8] {
74		NiceChar::as_bytes(
75			if matches!(self.from, NiceU8Idx::From00) { self.data.as_slice() }
76			else {
77				let (_, rest) = self.data.split_at(1);
78				rest
79			}
80		)
81	}
82
83	#[must_use]
84	#[inline]
85	/// # Triple Digit Bytes.
86	///
87	/// This method returns a zero-padded three-byte representation of the
88	/// nice value.
89	///
90	/// ## Examples
91	///
92	/// ```
93	/// assert_eq!(dactyl::NiceU8::from(3).as_bytes3(), b"003");
94	/// assert_eq!(dactyl::NiceU8::from(50).as_bytes3(), b"050");
95	/// assert_eq!(dactyl::NiceU8::from(113).as_bytes3(), b"113");
96	/// ```
97	pub const fn as_bytes3(&self) -> &[u8] {
98		NiceChar::as_bytes(self.data.as_slice())
99	}
100
101	#[must_use]
102	#[inline]
103	/// # Double Digit Str.
104	///
105	/// This method returns a zero-padded two-byte representation of the
106	/// nice value, _except_ for values requiring three digits (i.e. `100+`).
107	///
108	/// ## Examples
109	///
110	/// ```
111	/// assert_eq!(dactyl::NiceU8::from(3).as_str2(), "03");
112	/// assert_eq!(dactyl::NiceU8::from(50).as_str2(), "50");
113	/// assert_eq!(dactyl::NiceU8::from(113).as_str2(), "113");
114	/// ```
115	pub const fn as_str2(&self) -> &str {
116		NiceChar::as_str(
117			if matches!(self.from, NiceU8Idx::From00) { self.data.as_slice() }
118			else {
119				let (_, rest) = self.data.split_at(1);
120				rest
121			}
122		)
123	}
124
125	#[must_use]
126	#[inline]
127	/// # Triple Digit Str.
128	///
129	/// This method returns a zero-padded three-byte representation of the
130	/// nice value.
131	///
132	/// ## Examples
133	///
134	/// ```
135	/// assert_eq!(dactyl::NiceU8::from(3).as_str3(), "003");
136	/// assert_eq!(dactyl::NiceU8::from(50).as_str3(), "050");
137	/// assert_eq!(dactyl::NiceU8::from(113).as_str3(), "113");
138	/// ```
139	pub const fn as_str3(&self) -> &str {
140		NiceChar::as_str(self.data.as_slice())
141	}
142}
143
144impl NiceU8 {
145	/// # Replace.
146	///
147	/// Reuse the backing storage behind `self` to hold a new nice number.
148	///
149	/// ## Examples.
150	///
151	/// ```
152	/// use dactyl::NiceU8;
153	///
154	/// let mut num = NiceU8::from(123_u8);
155	/// assert_eq!(num.as_str(), "123");
156	///
157	/// num.replace(1);
158	/// assert_eq!(num.as_str(), "1");
159	/// ```
160	pub const fn replace(&mut self, src: u8) {
161		(self.data, self.from) = data_from(src);
162	}
163}
164
165
166
167#[inline]
168/// # Data and From.
169///
170/// The `u8` range is too small to benefit from our `Digiter` helper; this
171/// method handles the conversion all in one go, and is constant.
172const fn data_from(num: u8) -> ([NiceChar; 3], NiceU8Idx) {
173	// Three digits.
174	if 99 < num {
175		let a = if 199 < num { NiceChar::Digit2 } else { NiceChar::Digit1 };
176		let b = NiceChar::from_digit_u8(num / 10);
177		let c = NiceChar::from_digit_u8(num);
178		([a, b, c], NiceU8Idx::From00)
179	}
180	// Two digits.
181	else if 9 < num {
182		let b = NiceChar::from_digit_u8(num / 10);
183		let c = NiceChar::from_digit_u8(num);
184		([NiceChar::Digit0, b, c], NiceU8Idx::From01)
185	}
186	// One digit.
187	else {
188		(
189			[NiceChar::Digit0, NiceChar::Digit0, NiceChar::from_digit_u8(num)],
190			NiceU8Idx::From02
191		)
192	}
193}
194
195
196
197#[cfg(test)]
198mod tests {
199	use super::*;
200
201	#[test]
202	fn t_nice() {
203		// Explicitly check default, min, and max.
204		assert_eq!(NiceU8::default(), NiceU8::from(0));
205		assert_eq!(NiceU8::MIN, NiceU8::from(0));
206		assert_eq!(NiceU8::MAX, NiceU8::from(u8::MAX));
207
208		let mut last = NiceU8::MAX;
209		for i in u8::MIN..=u8::MAX {
210			let istr = i.to_string();
211			let nice = NiceU8::from(i);
212
213			assert_eq!(istr, nice.as_str());
214			assert_eq!(istr.as_bytes(), nice.as_bytes());
215			assert_eq!(istr.len(), nice.len());
216
217			// This should not equal the last value!
218			assert_ne!(nice, last);
219
220			// Now it should!
221			last.replace(i);
222			assert_eq!(nice, last);
223		}
224	}
225
226	super::super::nice_test!(NiceU8Idx);
227}