egml_core/model/base/
id.rs

1use crate::Error;
2use sha2::{Digest, Sha256};
3use std::fmt;
4use std::fmt::Write;
5use uuid::Uuid;
6
7#[derive(Debug, Clone, PartialEq, Eq, Hash)]
8pub struct Id(String);
9
10impl Id {
11    /// Constructs an Id by hashing the provided bytes using SHA-256.
12    /// The resulting Id is a 64-character uppercase hex string.
13    pub fn from_hashed_bytes(val: impl AsRef<[u8]>) -> Self {
14        Self(Self::hash_bytes_to_hex(val.as_ref()))
15    }
16
17    /// Constructs an Id by hashing the provided string using SHA-256.
18    pub fn from_hashed_string(val: &str) -> Self {
19        Self::from_hashed_bytes(val.as_bytes())
20    }
21
22    /// Constructs an Id by hashing the provided u64 using SHA-256.
23    pub fn from_hashed_u64(val: u64) -> Self {
24        Self::from_hashed_bytes(val.to_le_bytes())
25    }
26
27    /// Generate a random UUID v4
28    pub fn generate_uuid_v4() -> Self {
29        Self(Uuid::new_v4().to_string())
30    }
31}
32
33impl Id {
34    // Low-level helper for hashing bytes
35    fn hash_bytes_to_hex(val: &[u8]) -> String {
36        let mut sha256 = Sha256::new();
37        sha256.update(val);
38        let result = sha256.finalize();
39
40        // Preallocate 64-char string
41        let mut hash = String::with_capacity(64);
42        for byte in result {
43            write!(&mut hash, "{:02X}", byte).unwrap();
44        }
45        hash
46    }
47}
48
49impl From<Id> for String {
50    fn from(item: Id) -> Self {
51        item.0
52    }
53}
54
55impl TryFrom<&String> for Id {
56    type Error = Error;
57
58    fn try_from(item: &String) -> Result<Self, Self::Error> {
59        if item.is_empty() {
60            Err(Error::MustNotBeEmpty("id"))
61        } else {
62            Ok(Self(item.to_string()))
63        }
64    }
65}
66
67impl TryFrom<&str> for Id {
68    type Error = Error;
69
70    fn try_from(item: &str) -> Result<Self, Self::Error> {
71        if item.is_empty() {
72            Err(Error::MustNotBeEmpty("id"))
73        } else {
74            Ok(Self(item.to_string()))
75        }
76    }
77}
78
79impl TryFrom<String> for Id {
80    type Error = Error;
81
82    fn try_from(item: String) -> Result<Self, Self::Error> {
83        if item.is_empty() {
84            Err(Error::MustNotBeEmpty("id"))
85        } else {
86            Ok(Self(item))
87        }
88    }
89}
90
91/*impl From<String> for Id {
92    fn from(item: String) -> Self {
93        Self(item)
94    }
95}*/
96
97impl fmt::Display for Id {
98    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
99        write!(f, "{}", self.0)
100    }
101}