Skip to main content

ic_wire/bounded/borrowed/
mod.rs

1//! Input-backed finite byte and text values. Deserializers must lend their input.
2use super::{Bytes, Text};
3use crate::Error;
4use core::fmt;
5use serde::{Deserialize, Deserializer, Serialize, Serializer, de};
6
7/// Opaque bytes bounded in length, borrowing their backing storage.
8/// Decoding accepts borrowed input only; the value cannot outlive that input.
9#[derive(Clone, Copy, Debug, Eq, PartialEq)]
10pub struct BytesRef<'a, const N: usize>(&'a [u8]);
11impl<'a, const N: usize> BytesRef<'a, N> {
12    /// Admit a borrowed slice without copying or allocating.
13    pub fn new(bytes: &'a [u8]) -> Result<Self, Error> {
14        if bytes.len() > N {
15            Err(Error::Limit)
16        } else {
17            Ok(Self(bytes))
18        }
19    }
20    /// Borrow the admitted bytes for their original storage lifetime.
21    pub fn as_slice(&self) -> &'a [u8] {
22        self.0
23    }
24    pub(super) fn from_owned(bytes: &'a Bytes<N>) -> Self {
25        Self(bytes.as_slice())
26    }
27}
28impl<const N: usize> Serialize for BytesRef<'_, N> {
29    fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
30        s.serialize_bytes(self.0)
31    }
32}
33impl<'de: 'a, 'a, const N: usize> Deserialize<'de> for BytesRef<'a, N> {
34    fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
35        struct Visitor<const N: usize>;
36        impl<'de, const N: usize> de::Visitor<'de> for Visitor<N> {
37            type Value = BytesRef<'de, N>;
38            fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39                f.write_str("bounded borrowed bytes")
40            }
41            fn visit_borrowed_bytes<E: de::Error>(
42                self,
43                bytes: &'de [u8],
44            ) -> Result<Self::Value, E> {
45                BytesRef::new(bytes).map_err(|_| E::custom("byte limit"))
46            }
47        }
48        d.deserialize_bytes(Visitor::<N>)
49    }
50}
51
52/// UTF-8 text bounded in bytes, borrowing its backing storage.
53/// Decoding accepts borrowed input only, without an owned fallback.
54#[derive(Clone, Copy, Debug, Eq, PartialEq)]
55pub struct TextRef<'a, const N: usize>(&'a str);
56impl<'a, const N: usize> TextRef<'a, N> {
57    /// Admit borrowed text without copying or allocating.
58    pub fn new(text: &'a str) -> Result<Self, Error> {
59        if text.len() > N {
60            Err(Error::Limit)
61        } else {
62            Ok(Self(text))
63        }
64    }
65    /// Borrow the admitted text for its original storage lifetime.
66    pub fn as_str(&self) -> &'a str {
67        self.0
68    }
69    pub(super) fn from_owned(text: &'a Text<N>) -> Self {
70        Self(text.as_str())
71    }
72}
73impl<const N: usize> Serialize for TextRef<'_, N> {
74    fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
75        s.serialize_str(self.0)
76    }
77}
78impl<'de: 'a, 'a, const N: usize> Deserialize<'de> for TextRef<'a, N> {
79    fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
80        struct Visitor<const N: usize>;
81        impl<'de, const N: usize> de::Visitor<'de> for Visitor<N> {
82            type Value = TextRef<'de, N>;
83            fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
84                f.write_str("bounded borrowed UTF-8 text")
85            }
86            fn visit_borrowed_str<E: de::Error>(self, text: &'de str) -> Result<Self::Value, E> {
87                TextRef::new(text).map_err(|_| E::custom("text limit"))
88            }
89        }
90        d.deserialize_str(Visitor::<N>)
91    }
92}