Skip to main content

object_rainbow/
zero_terminated.rs

1use std::{fmt::Display, str::FromStr};
2
3use crate::{with_repr::WithRepr, *};
4
5/// Zero-terminated value. Used to make [`Inline`]s out of [`Object`]s which don't contain zeroes.
6///
7/// If you can't guarantee absence of zeroes, see [`length_prefixed::Lp`].
8#[derive(Debug, Tagged, ListHashes, Topological, ParseAsInline)]
9pub struct Zt<T> {
10    inner: Arc<WithRepr<T>>,
11}
12
13impl<T> PartialEq for Zt<T> {
14    fn eq(&self, other: &Self) -> bool {
15        self.inner == other.inner
16    }
17}
18
19impl<T> Eq for Zt<T> {}
20
21impl<T: ByteOrd> PartialOrd for Zt<T> {
22    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
23        Some(self.cmp(other))
24    }
25}
26
27impl<T: ByteOrd> Ord for Zt<T> {
28    fn cmp(&self, other: &Self) -> Ordering {
29        self.inner.cmp(&other.inner)
30    }
31}
32
33impl<T: ByteOrd> ByteOrd for Zt<T> {
34    fn bytes_cmp(&self, other: &Self) -> Ordering {
35        self.cmp(other)
36    }
37}
38
39impl<T: ToOutput> Zt<T> {
40    /// Create a zero-terminated value.
41    ///
42    /// Pre-computes the output, errors if it contains a zero.
43    pub fn new(object: T) -> crate::Result<Self> {
44        let inner = WithRepr::new(object);
45        if inner.data().contains(&0) {
46            Err(Error::Zero)
47        } else {
48            Ok(Self {
49                inner: Arc::new(inner),
50            })
51        }
52    }
53}
54
55impl<T> Clone for Zt<T> {
56    fn clone(&self) -> Self {
57        Self {
58            inner: self.inner.clone(),
59        }
60    }
61}
62
63impl<T> Deref for Zt<T> {
64    type Target = T;
65
66    fn deref(&self) -> &Self::Target {
67        self.inner.object()
68    }
69}
70
71impl<T: ToOutput> ToOutput for Zt<T> {
72    fn to_output(&self, output: &mut impl Output) {
73        self.inner.to_output(output);
74        if output.is_real() {
75            output.write(&[0]);
76        }
77    }
78}
79
80impl<T: ToOutput> InlineOutput for Zt<T> {}
81
82impl<T: Parse<I>, I: ParseInput> ParseInline<I> for Zt<T> {
83    fn parse_inline(input: &mut I) -> crate::Result<Self> {
84        let inner = Arc::new(WithRepr::parse_zero_terminated(input)?);
85        Ok(Self { inner })
86    }
87}
88
89impl<T: MaybeHasNiche<MnArray = NoNiche<NicheForUnsized>>> MaybeHasNiche for Zt<T> {
90    type MnArray = NoNiche<NicheForUnsized>;
91}
92
93impl<T: FromStr<Err: 'static + Send + Sync + std::error::Error> + ToOutput> FromStr for Zt<T> {
94    type Err = Error;
95
96    fn from_str(s: &str) -> Result<Self> {
97        Self::new(s.parse().map_err(Error::parse)?)
98    }
99}
100
101impl<T: AsRef<str>> AsRef<str> for Zt<T> {
102    fn as_ref(&self) -> &str {
103        self.inner.object().as_ref()
104    }
105}
106
107impl<T: Display> Display for Zt<T> {
108    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
109        self.inner.object().fmt(f)
110    }
111}