1use core::fmt;
4use core::str::FromStr;
5
6use super::{Decode, DecodeError, Encode, Reader, Sink, ValueError, Writer, hex};
7use crate::log::hash::{TAG_ENTRY_ID, tagged};
8
9#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
22pub struct LedgerId(String);
23
24impl LedgerId {
25 pub const MAX_BYTES: usize = 255;
27
28 pub fn new(text: impl Into<String>) -> Result<Self, ValueError> {
36 let text = text.into();
37 if text.is_empty() {
38 return Err(ValueError::Empty);
39 }
40 if text.len() > Self::MAX_BYTES {
41 return Err(ValueError::TooLong {
42 max: Self::MAX_BYTES,
43 found: text.len(),
44 });
45 }
46 if let Some(found) = text.chars().find(|c| !matches!(c, '!'..='~') || *c == '+') {
47 return Err(ValueError::InvalidCharacter { found });
48 }
49 Ok(Self(text))
50 }
51
52 #[must_use]
54 pub fn as_str(&self) -> &str {
55 &self.0
56 }
57}
58
59#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
66pub struct IdempotencyKey(String);
67
68impl IdempotencyKey {
69 pub const MAX_BYTES: usize = 128;
71
72 pub fn new(text: impl Into<String>) -> Result<Self, ValueError> {
79 let text = text.into();
80 if text.is_empty() {
81 return Err(ValueError::Empty);
82 }
83 if text.len() > Self::MAX_BYTES {
84 return Err(ValueError::TooLong {
85 max: Self::MAX_BYTES,
86 found: text.len(),
87 });
88 }
89 if text.chars().any(char::is_control) {
90 return Err(ValueError::ControlCharacter);
91 }
92 Ok(Self(text))
93 }
94
95 #[must_use]
97 pub fn as_str(&self) -> &str {
98 &self.0
99 }
100}
101
102macro_rules! text_id {
103 ($($ty:ident),*) => {$(
104 impl fmt::Display for $ty {
105 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
106 super::encoding::pad(f, &self.0)
107 }
108 }
109
110 impl fmt::Debug for $ty {
111 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
112 write!(f, concat!(stringify!($ty), "({:?})"), self.0)
113 }
114 }
115
116 impl FromStr for $ty {
117 type Err = ValueError;
118
119 fn from_str(text: &str) -> Result<Self, Self::Err> {
120 Self::new(text)
121 }
122 }
123
124 impl TryFrom<&str> for $ty {
125 type Error = ValueError;
126
127 fn try_from(text: &str) -> Result<Self, Self::Error> {
128 Self::new(text)
129 }
130 }
131
132 impl TryFrom<String> for $ty {
133 type Error = ValueError;
134
135 fn try_from(text: String) -> Result<Self, Self::Error> {
136 Self::new(text)
137 }
138 }
139
140 impl AsRef<str> for $ty {
141 fn as_ref(&self) -> &str {
142 &self.0
143 }
144 }
145
146 impl Encode for $ty {
147 fn encode<S: Sink>(&self, w: &mut Writer<S>) {
148 w.str(&self.0);
149 }
150 }
151
152 impl Decode for $ty {
153 fn decode(r: &mut Reader<'_>, field: &'static str) -> Result<Self, DecodeError> {
154 Self::new(r.str(field)?).map_err(|error| DecodeError::Value { field, error })
155 }
156 }
157
158 #[cfg(feature = "serde")]
159 impl serde::Serialize for $ty {
160 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
161 serializer.serialize_str(&self.0)
162 }
163 }
164
165 #[cfg(feature = "serde")]
166 impl<'de> serde::Deserialize<'de> for $ty {
167 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
168 super::serde_str::deserialize(deserializer)
169 }
170 }
171 )*};
172}
173
174text_id!(LedgerId, IdempotencyKey);
175
176#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
194pub struct EntryId([u8; 16]);
195
196impl EntryId {
197 #[must_use]
199 pub fn derive(ledger: &LedgerId, key: &IdempotencyKey) -> Self {
200 let mut payload = Writer::new(Vec::new());
201 payload.value(ledger);
202 payload.value(key);
203 let digest = tagged(TAG_ENTRY_ID, &payload.into_inner());
204 let mut id = [0u8; 16];
205 for (slot, byte) in id.iter_mut().zip(digest.as_bytes()) {
206 *slot = *byte;
207 }
208 Self(id)
209 }
210
211 #[must_use]
214 pub const fn from_bytes(bytes: [u8; 16]) -> Self {
215 Self(bytes)
216 }
217
218 #[must_use]
220 pub const fn as_bytes(&self) -> &[u8; 16] {
221 &self.0
222 }
223}
224
225impl fmt::Display for EntryId {
226 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
227 hex::write(f, &self.0)
228 }
229}
230
231impl fmt::Debug for EntryId {
232 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
233 write!(f, "EntryId({self})")
234 }
235}
236
237impl FromStr for EntryId {
238 type Err = ValueError;
239
240 fn from_str(text: &str) -> Result<Self, Self::Err> {
241 hex::parse(text).map(Self)
242 }
243}
244
245impl Encode for EntryId {
246 fn encode<S: Sink>(&self, w: &mut Writer<S>) {
247 w.fixed(&self.0);
248 }
249}
250
251impl Decode for EntryId {
252 fn decode(r: &mut Reader<'_>, _field: &'static str) -> Result<Self, DecodeError> {
253 r.array().map(Self)
254 }
255}
256
257#[cfg(feature = "serde")]
258impl serde::Serialize for EntryId {
259 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
260 serializer.collect_str(self)
261 }
262}
263
264#[cfg(feature = "serde")]
265impl<'de> serde::Deserialize<'de> for EntryId {
266 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
267 super::serde_str::deserialize(deserializer)
268 }
269}
270
271#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
285#[cfg_attr(feature = "serde", derive(serde::Serialize))]
286pub struct AccountHandle(u32);
287
288impl AccountHandle {
289 pub const MAX: u32 = u32::MAX - 1;
291
292 #[must_use]
294 pub const fn new(index: u32) -> Option<Self> {
295 if index > Self::MAX {
296 None
297 } else {
298 Some(Self(index))
299 }
300 }
301
302 #[must_use]
304 pub const fn get(self) -> u32 {
305 self.0
306 }
307}
308
309impl fmt::Display for AccountHandle {
310 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
312 super::encoding::pad(f, &format!("#{}", self.0))
313 }
314}
315
316impl Encode for AccountHandle {
317 fn encode<S: Sink>(&self, w: &mut Writer<S>) {
318 w.u32(self.0);
319 }
320}
321
322impl Decode for AccountHandle {
323 fn decode(r: &mut Reader<'_>, field: &'static str) -> Result<Self, DecodeError> {
324 Self::new(r.u32()?).ok_or(DecodeError::Value {
325 field,
326 error: ValueError::OutOfRange,
327 })
328 }
329}
330
331#[cfg(feature = "serde")]
332impl<'de> serde::Deserialize<'de> for AccountHandle {
333 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
334 use serde::de::Error as _;
335 Self::new(u32::deserialize(deserializer)?)
336 .ok_or_else(|| D::Error::custom(ValueError::OutOfRange))
337 }
338}