1use std::{
4 cmp::Ordering,
5 fmt::{self, Display, Formatter},
6 hash::{Hash, Hasher},
7 str::FromStr,
8};
9
10use serde::{Deserialize, Deserializer, Serialize, de::Error as DeError};
11
12#[cfg(test)]
13mod tests;
14
15#[derive(Clone, Copy, Debug, Eq, PartialEq)]
17pub enum PrincipalError {
18 InvalidText,
20}
21
22impl Display for PrincipalError {
23 fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
24 formatter.write_str("principal text is invalid")
25 }
26}
27
28#[derive(Clone, Copy, Debug, Eq, PartialEq)]
30pub enum PrincipalDecodeError {
31 TooLarge {
33 len: usize,
35 },
36}
37
38#[derive(Clone, Copy, Debug, Eq, PartialEq)]
40pub enum PrincipalEncodeError {
41 TooLarge {
43 len: usize,
45 max: usize,
47 },
48}
49
50#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd)]
52#[repr(transparent)]
53#[serde(transparent)]
54pub struct Principal(ic_principal::Principal);
55
56impl Principal {
57 pub const MAX_LENGTH_IN_BYTES: u32 = 29;
59
60 pub const MIN: Self = Self::from_slice(&[0x00; 29]);
62
63 pub const MAX: Self = Self::from_slice(&[0xFF; 29]);
65
66 #[must_use]
68 pub const fn anonymous() -> Self {
69 Self(ic_principal::Principal::anonymous())
70 }
71
72 pub fn from_text(text: &str) -> Result<Self, PrincipalError> {
78 ic_principal::Principal::from_text(text)
79 .map(Self)
80 .map_err(|_| PrincipalError::InvalidText)
81 }
82
83 #[must_use]
90 pub const fn from_slice(bytes: &[u8]) -> Self {
91 Self(ic_principal::Principal::from_slice(bytes))
92 }
93
94 #[must_use]
96 pub const fn as_slice(&self) -> &[u8] {
97 self.0.as_slice()
98 }
99
100 pub const fn stored_bytes(&self) -> Result<&[u8], PrincipalEncodeError> {
107 let bytes = self.as_slice();
108 if bytes.len() > Self::MAX_LENGTH_IN_BYTES as usize {
109 return Err(PrincipalEncodeError::TooLarge {
110 len: bytes.len(),
111 max: Self::MAX_LENGTH_IN_BYTES as usize,
112 });
113 }
114 Ok(bytes)
115 }
116
117 pub fn to_bytes(self) -> Result<Vec<u8>, PrincipalEncodeError> {
123 Ok(self.stored_bytes()?.to_vec())
124 }
125
126 pub const fn try_from_bytes(bytes: &[u8]) -> Result<Self, PrincipalDecodeError> {
132 if bytes.len() > Self::MAX_LENGTH_IN_BYTES as usize {
133 return Err(PrincipalDecodeError::TooLarge { len: bytes.len() });
134 }
135 Ok(Self::from_slice(bytes))
136 }
137}
138
139impl Display for Principal {
140 fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
141 Display::fmt(&self.0, formatter)
142 }
143}
144
145impl From<ic_principal::Principal> for Principal {
146 fn from(value: ic_principal::Principal) -> Self {
147 Self(value)
148 }
149}
150
151impl From<Principal> for ic_principal::Principal {
152 fn from(value: Principal) -> Self {
153 value.0
154 }
155}
156
157impl FromStr for Principal {
158 type Err = PrincipalError;
159
160 fn from_str(input: &str) -> Result<Self, Self::Err> {
161 Self::from_text(input)
162 }
163}
164
165impl Serialize for Principal {
166 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
167 where
168 S: serde::Serializer,
169 {
170 self.0.serialize(serializer)
171 }
172}
173
174impl TryFrom<&[u8]> for Principal {
175 type Error = PrincipalDecodeError;
176
177 fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
178 Self::try_from_bytes(bytes)
179 }
180}
181
182#[derive(Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
184pub struct Blob(Vec<u8>);
185
186impl Blob {
187 #[must_use]
189 pub fn as_bytes(&self) -> &[u8] {
190 &self.0
191 }
192
193 #[must_use]
195 pub fn into_bytes(self) -> Vec<u8> {
196 self.0
197 }
198
199 #[must_use]
201 pub fn to_vec(&self) -> Vec<u8> {
202 self.0.clone()
203 }
204
205 #[must_use]
207 pub const fn len(&self) -> usize {
208 self.0.len()
209 }
210
211 #[must_use]
213 pub const fn is_empty(&self) -> bool {
214 self.0.is_empty()
215 }
216}
217
218impl Display for Blob {
219 fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
220 write!(formatter, "[blob ({} bytes)]", self.len())
221 }
222}
223
224impl From<Vec<u8>> for Blob {
225 fn from(bytes: Vec<u8>) -> Self {
226 Self(bytes)
227 }
228}
229
230impl From<&[u8]> for Blob {
231 fn from(bytes: &[u8]) -> Self {
232 Self(bytes.to_vec())
233 }
234}
235
236impl<const N: usize> From<&[u8; N]> for Blob {
237 fn from(bytes: &[u8; N]) -> Self {
238 Self(bytes.to_vec())
239 }
240}
241
242impl<'de> Deserialize<'de> for Blob {
243 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
244 where
245 D: Deserializer<'de>,
246 {
247 serde_bytes::ByteBuf::deserialize(deserializer).map(|bytes| Self(bytes.into_vec()))
248 }
249}
250
251#[derive(Clone, Copy, Debug, Eq, PartialEq)]
253pub enum UlidParseError {
254 InvalidString,
256}
257
258impl Display for UlidParseError {
259 fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
260 formatter.write_str("ULID text is invalid")
261 }
262}
263
264#[derive(Clone, Copy, Debug, Eq, PartialEq)]
266pub enum UlidDecodeError {
267 InvalidSize {
269 len: usize,
271 },
272}
273
274#[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
279#[repr(transparent)]
280pub struct Ulid([u8; 16]);
281
282impl Ulid {
283 pub const STORED_SIZE: u32 = 16;
285
286 pub const MIN: Self = Self::from_bytes([0x00; 16]);
288
289 pub const MAX: Self = Self::from_bytes([0xFF; 16]);
291
292 #[must_use]
294 pub const fn nil() -> Self {
295 Self::MIN
296 }
297
298 #[must_use]
300 pub const fn from_bytes(bytes: [u8; 16]) -> Self {
301 Self(bytes)
302 }
303
304 #[must_use]
306 pub const fn from_u128(value: u128) -> Self {
307 Self::from_bytes(value.to_be_bytes())
308 }
309
310 #[must_use]
312 pub const fn to_bytes(self) -> [u8; 16] {
313 self.0
314 }
315
316 pub const fn try_from_bytes(bytes: &[u8]) -> Result<Self, UlidDecodeError> {
322 if bytes.len() != Self::STORED_SIZE as usize {
323 return Err(UlidDecodeError::InvalidSize { len: bytes.len() });
324 }
325 let mut value = [0; 16];
326 value.copy_from_slice(bytes);
327 Ok(Self::from_bytes(value))
328 }
329}
330
331impl Display for Ulid {
332 fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
333 Display::fmt(&ulid::Ulid::from_bytes(self.0), formatter)
334 }
335}
336
337impl fmt::Debug for Ulid {
338 fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
339 fmt::Debug::fmt(&self.to_string(), formatter)
340 }
341}
342
343impl FromStr for Ulid {
344 type Err = UlidParseError;
345
346 fn from_str(input: &str) -> Result<Self, Self::Err> {
347 let value = input
348 .parse::<ulid::Ulid>()
349 .map_err(|_| UlidParseError::InvalidString)?;
350 if value.to_string() != input {
351 return Err(UlidParseError::InvalidString);
352 }
353 Ok(Self::from_bytes(value.to_bytes()))
354 }
355}
356
357impl<'de> Deserialize<'de> for Ulid {
358 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
359 where
360 D: Deserializer<'de>,
361 {
362 struct UlidBytesVisitor;
365
366 impl<'de> serde::de::Visitor<'de> for UlidBytesVisitor {
367 type Value = Ulid;
368
369 fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
370 formatter.write_str("exactly 16 ULID bytes")
371 }
372
373 fn visit_seq<A: serde::de::SeqAccess<'de>>(
374 self,
375 mut sequence: A,
376 ) -> Result<Ulid, A::Error> {
377 let mut bytes = [0; 16];
378 for (index, byte) in bytes.iter_mut().enumerate() {
379 *byte = sequence
380 .next_element()?
381 .ok_or_else(|| A::Error::invalid_length(index, &self))?;
382 }
383 if sequence.next_element::<u8>()?.is_some() {
384 return Err(A::Error::invalid_length(17, &self));
385 }
386
387 Ok(Ulid::from_bytes(bytes))
388 }
389 }
390
391 if deserializer.is_human_readable() {
392 return String::deserialize(deserializer)?
393 .parse()
394 .map_err(D::Error::custom);
395 }
396
397 deserializer.deserialize_seq(UlidBytesVisitor)
398 }
399}
400
401impl Serialize for Ulid {
402 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
403 where
404 S: serde::Serializer,
405 {
406 if serializer.is_human_readable() {
407 serializer.serialize_str(&self.to_string())
408 } else {
409 serializer.serialize_bytes(&self.0)
410 }
411 }
412}
413
414impl TryFrom<&[u8]> for Ulid {
415 type Error = UlidDecodeError;
416
417 fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
418 Self::try_from_bytes(bytes)
419 }
420}
421
422#[derive(Clone, Copy, Debug, Eq, PartialEq)]
424pub enum Float32DecodeError {
425 InvalidSize {
427 len: usize,
429 },
430 NonFinite,
432}
433
434#[derive(Clone, Copy, Debug, Default)]
436#[repr(transparent)]
437pub struct Float32(f32);
438
439impl Float32 {
440 #[must_use]
442 pub fn try_new(value: f32) -> Option<Self> {
443 if !value.is_finite() {
444 return None;
445 }
446 Some(Self(if value == 0.0 { 0.0 } else { value }))
447 }
448
449 #[must_use]
451 pub const fn get(self) -> f32 {
452 self.0
453 }
454
455 #[must_use]
457 pub const fn to_be_bytes(&self) -> [u8; 4] {
458 self.0.to_bits().to_be_bytes()
459 }
460
461 pub fn try_from_bytes(bytes: &[u8]) -> Result<Self, Float32DecodeError> {
467 let bytes: [u8; 4] = bytes
468 .try_into()
469 .map_err(|_| Float32DecodeError::InvalidSize { len: bytes.len() })?;
470 Self::try_new(f32::from_bits(u32::from_be_bytes(bytes)))
471 .ok_or(Float32DecodeError::NonFinite)
472 }
473
474 #[must_use]
476 #[expect(clippy::cast_possible_truncation)]
477 pub fn try_from_f64(value: f64) -> Option<Self> {
478 if !value.is_finite() || value < f64::from(f32::MIN) || value > f64::from(f32::MAX) {
479 return None;
480 }
481 Self::try_new(value as f32)
482 }
483}
484
485impl Display for Float32 {
486 fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
487 Display::fmt(&self.0, formatter)
488 }
489}
490
491impl<'de> Deserialize<'de> for Float32 {
492 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
493 where
494 D: Deserializer<'de>,
495 {
496 Self::try_new(f32::deserialize(deserializer)?)
497 .ok_or_else(|| D::Error::custom("Float32 must be finite"))
498 }
499}
500
501impl Serialize for Float32 {
502 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
503 where
504 S: serde::Serializer,
505 {
506 serializer.serialize_f32(self.0)
507 }
508}
509
510impl Eq for Float32 {}
511
512impl From<Float32> for f32 {
513 fn from(value: Float32) -> Self {
514 value.0
515 }
516}
517
518#[expect(clippy::cast_precision_loss)]
519impl From<i32> for Float32 {
520 fn from(value: i32) -> Self {
521 Self(value as f32)
522 }
523}
524
525impl Hash for Float32 {
526 fn hash<H: Hasher>(&self, state: &mut H) {
527 state.write_u32(self.0.to_bits());
528 }
529}
530
531impl Ord for Float32 {
532 fn cmp(&self, other: &Self) -> Ordering {
533 self.0.total_cmp(&other.0)
534 }
535}
536
537impl PartialEq for Float32 {
538 fn eq(&self, other: &Self) -> bool {
539 self.0 == other.0
540 }
541}
542
543impl PartialOrd for Float32 {
544 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
545 Some(self.cmp(other))
546 }
547}
548
549impl TryFrom<&[u8]> for Float32 {
550 type Error = Float32DecodeError;
551
552 fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
553 Self::try_from_bytes(bytes)
554 }
555}
556
557#[derive(Clone, Copy, Debug, Eq, PartialEq)]
559pub enum Float64DecodeError {
560 InvalidSize {
562 len: usize,
564 },
565 NonFinite,
567}
568
569#[derive(Clone, Copy, Debug, Default)]
571#[repr(transparent)]
572pub struct Float64(f64);
573
574impl Float64 {
575 #[must_use]
577 pub fn try_new(value: f64) -> Option<Self> {
578 if !value.is_finite() {
579 return None;
580 }
581 Some(Self(if value == 0.0 { 0.0 } else { value }))
582 }
583
584 #[must_use]
586 pub const fn get(self) -> f64 {
587 self.0
588 }
589
590 #[must_use]
592 pub const fn to_be_bytes(&self) -> [u8; 8] {
593 self.0.to_bits().to_be_bytes()
594 }
595
596 pub fn try_from_bytes(bytes: &[u8]) -> Result<Self, Float64DecodeError> {
602 let bytes: [u8; 8] = bytes
603 .try_into()
604 .map_err(|_| Float64DecodeError::InvalidSize { len: bytes.len() })?;
605 Self::try_new(f64::from_bits(u64::from_be_bytes(bytes)))
606 .ok_or(Float64DecodeError::NonFinite)
607 }
608}
609
610impl Display for Float64 {
611 fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
612 Display::fmt(&self.0, formatter)
613 }
614}
615
616impl<'de> Deserialize<'de> for Float64 {
617 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
618 where
619 D: Deserializer<'de>,
620 {
621 Self::try_new(f64::deserialize(deserializer)?)
622 .ok_or_else(|| D::Error::custom("Float64 must be finite"))
623 }
624}
625
626impl Serialize for Float64 {
627 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
628 where
629 S: serde::Serializer,
630 {
631 serializer.serialize_f64(self.0)
632 }
633}
634
635impl Eq for Float64 {}
636
637impl From<Float64> for f64 {
638 fn from(value: Float64) -> Self {
639 value.0
640 }
641}
642
643impl From<i32> for Float64 {
644 fn from(value: i32) -> Self {
645 Self(f64::from(value))
646 }
647}
648
649impl Hash for Float64 {
650 fn hash<H: Hasher>(&self, state: &mut H) {
651 state.write_u64(self.0.to_bits());
652 }
653}
654
655impl Ord for Float64 {
656 fn cmp(&self, other: &Self) -> Ordering {
657 self.0.total_cmp(&other.0)
658 }
659}
660
661impl PartialEq for Float64 {
662 fn eq(&self, other: &Self) -> bool {
663 self.0 == other.0
664 }
665}
666
667impl PartialOrd for Float64 {
668 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
669 Some(self.cmp(other))
670 }
671}
672
673impl TryFrom<&[u8]> for Float64 {
674 type Error = Float64DecodeError;
675
676 fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
677 Self::try_from_bytes(bytes)
678 }
679}
680
681impl Serialize for Blob {
682 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
683 serializer.serialize_bytes(self.as_bytes())
684 }
685}
686
687pub(crate) fn deserialize_fixed_bytes<'de, D: Deserializer<'de>, const N: usize>(
690 deserializer: D,
691) -> Result<[u8; N], D::Error> {
692 struct Fixed<const N: usize>;
693 impl<'de, const N: usize> serde::de::Visitor<'de> for Fixed<N> {
694 type Value = [u8; N];
695 fn expecting(&self, f: &mut Formatter<'_>) -> fmt::Result {
696 write!(f, "exactly {N} bytes")
697 }
698 fn visit_bytes<E: serde::de::Error>(self, bytes: &[u8]) -> Result<Self::Value, E> {
699 bytes
700 .try_into()
701 .map_err(|_| E::invalid_length(bytes.len(), &self))
702 }
703 fn visit_seq<A: serde::de::SeqAccess<'de>>(
704 self,
705 mut values: A,
706 ) -> Result<Self::Value, A::Error> {
707 let mut bytes = [0; N];
708 for (index, byte) in bytes.iter_mut().enumerate() {
709 *byte = values
710 .next_element()?
711 .ok_or_else(|| A::Error::invalid_length(index, &self))?;
712 }
713 if values.next_element::<u8>()?.is_some() {
714 return Err(A::Error::invalid_length(N + 1, &self));
715 }
716 Ok(bytes)
717 }
718 }
719 deserializer.deserialize_bytes(Fixed::<N>)
720}