1use std::{fmt, io::Read, ops::Deref, path::Path, str::FromStr};
4
5use binrw::{BinRead, BinWrite};
6use derive_more::{Constructor, Display};
7use rand::{RngCore, rng};
8use serde_derive::{Deserialize, Serialize};
9
10use crate::{
11 crypto::hasher::hash_reader,
12 error::{ErrorKind, RusticError, RusticResult},
13};
14
15pub(crate) mod constants {
16 pub(super) const LEN: usize = 32;
18 pub(crate) const HEX_LEN: usize = LEN * 2;
20}
21
22#[macro_export]
23macro_rules! define_new_id_struct {
25 ($a:ident, $b: expr) => {
26 #[doc = concat!("An Id identifying a ", stringify!($b))]
27 #[derive(
28 Debug,
29 Clone,
30 Copy,
31 Default,
32 PartialEq,
33 Eq,
34 PartialOrd,
35 Ord,
36 Hash,
37 derive_more::Deref,
38 derive_more::Display,
39 derive_more::From,
40 derive_more::FromStr,
41 serde::Serialize,
42 serde::Deserialize,
43 )]
44 #[serde(transparent)]
45 pub struct $a($crate::Id);
46
47 impl $a {
48 #[must_use]
50 pub fn into_inner(self) -> $crate::Id {
51 self.0
52 }
53 }
54 };
55}
56
57#[derive(
61 Serialize,
62 Deserialize,
63 Clone,
64 Copy,
65 Default,
66 PartialEq,
67 Eq,
68 Hash,
69 PartialOrd,
70 Ord,
71 Constructor,
72 BinWrite,
73 BinRead,
74 Display,
75)]
76#[display("{}", &self.to_hex()[0..8])]
77pub struct Id(
78 #[serde(serialize_with = "hex::serde::serialize")]
80 #[serde(deserialize_with = "hex::serde::deserialize")]
81 [u8; constants::LEN],
82);
83
84impl FromStr for Id {
85 type Err = Box<RusticError>;
86 fn from_str(s: &str) -> Result<Self, Self::Err> {
87 let mut id = Self::default();
88 hex::decode_to_slice(s, &mut id.0).map_err(|err| {
89 RusticError::with_source(
90 ErrorKind::InvalidInput,
91 "Failed to decode hex string `{value}` into Id. The value must be a valid hexadecimal string.",
92 err
93 )
94 .attach_context("value", s)
95 })?;
96
97 Ok(id)
98 }
99}
100
101impl Id {
102 #[deprecated(note = "use FromStr::from_str instead")]
120 pub fn from_hex(s: &str) -> RusticResult<Self> {
121 s.parse()
122 }
123
124 #[must_use]
126 pub fn random_from_rng(rng: &mut impl RngCore) -> Self {
127 let mut id = Self::default();
128 rng.fill_bytes(&mut id.0);
129 id
130 }
131
132 #[must_use]
134 pub fn random() -> Self {
135 Self::random_from_rng(&mut rng())
136 }
137
138 #[must_use]
155 pub fn to_hex(self) -> HexId {
156 let mut hex_id = HexId::EMPTY;
157 hex::encode_to_slice(self.0, &mut hex_id.0).unwrap();
159 hex_id
160 }
161
162 #[must_use]
174 pub fn is_null(&self) -> bool {
175 self == &Self::default()
176 }
177
178 pub fn blob_matches_reader(&self, length: u64, r: &mut impl Read) -> bool {
189 let r = r.take(length);
191 hash_reader(r).is_ok_and(|id| self == &id)
192 }
193
194 #[must_use]
196 pub fn as_u32(&self) -> u32 {
197 u32::from_le_bytes([self.0[0], self.0[1], self.0[2], self.0[3]])
198 }
199
200 pub fn find_starts_with_from_iter<T: AsRef<str>, I: IntoIterator<Item = Self>>(
215 vec: &[T],
216 iter: I,
217 ) -> RusticResult<Vec<Self>> {
218 iter.into_iter()
219 .find_unique_multiple(|id: &Self, v: &T| id.to_hex().starts_with(v.as_ref()), vec)
220 .assert_found(vec)
221 }
222}
223
224impl fmt::Debug for Id {
225 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
227 write!(f, "{}", &*self.to_hex())
228 }
229}
230
231#[derive(Copy, Clone, Debug)]
233pub struct HexId([u8; constants::HEX_LEN]);
234
235impl HexId {
236 const EMPTY: Self = Self([b'0'; constants::HEX_LEN]);
238
239 #[must_use]
245 pub fn as_str(&self) -> &str {
246 std::str::from_utf8(&self.0).unwrap()
248 }
249}
250
251impl Deref for HexId {
252 type Target = str;
253
254 fn deref(&self) -> &Self::Target {
255 self.as_str()
256 }
257}
258
259impl AsRef<Path> for HexId {
260 fn as_ref(&self) -> &Path {
261 self.as_str().as_ref()
262 }
263}
264
265#[derive(Debug, Clone, Copy, PartialEq, Eq)]
267pub enum FindResult<T> {
268 NotFound,
269 Found(T),
270 NonUnique,
271}
272
273#[derive(Debug)]
274pub struct FindUniqueResults<T>(Vec<FindResult<T>>);
276
277impl<T: Clone> FindUniqueResults<T> {
278 pub fn new<S>(vec: &[S]) -> Self {
279 Self(vec![FindResult::NotFound; vec.len()])
280 }
281 pub fn add_item<S, F: FnMut(&T, &S) -> bool>(&mut self, item: T, mut cmp: F, with: &[S]) {
282 for (i, v) in with.iter().enumerate() {
283 if cmp(&item, v) {
284 if matches!(self.0[i], FindResult::NotFound) {
285 self.0[i] = FindResult::Found(item.clone());
286 } else {
287 self.0[i] = FindResult::NonUnique;
288 }
289 }
290 }
291 }
292 pub fn assert_found<S: AsRef<str>>(self, vec: &[S]) -> RusticResult<Vec<T>> {
293 self.0
294 .into_iter()
295 .enumerate()
296 .map(|(i, id)| match id {
297 FindResult::Found(id) => Ok(id),
298 FindResult::NotFound => Err(RusticError::new(
299 ErrorKind::Backend,
300 "No suitable id found for `{id}`.",
301 )
302 .attach_context("id", vec[i].as_ref().to_string())),
303 FindResult::NonUnique => Err(RusticError::new(
304 ErrorKind::Backend,
305 "Id not unique: `{id}`.",
306 )
307 .attach_context("id", vec[i].as_ref().to_string())),
308 })
309 .collect()
310 }
311}
312
313pub trait FindUniqueMultiple: Iterator + Sized
314where
315 Self::Item: Clone,
316{
317 fn find_unique_multiple<T, F: FnMut(&Self::Item, &T) -> bool>(
318 self,
319 mut cmp: F,
320 with: &[T],
321 ) -> FindUniqueResults<Self::Item> {
322 let mut results = FindUniqueResults::new(with);
323 for item in self {
324 results.add_item(item, &mut cmp, with);
325 }
326 results
327 }
328}
329
330impl<I: Iterator> FindUniqueMultiple for I where I::Item: Clone {}