Skip to main content

object_rainbow/
length_prefixed.rs

1use std::ops::{Add, Deref, DerefMut};
2
3use generic_array::ArrayLength;
4use typenum::{Sum, U8, Unsigned, tarr};
5
6use crate::{numeric::Le, *};
7
8/// Length-prefixed value. Used to make [`Inline`]s out of arbitrary [`Object`]s.
9///
10/// If you can guarantee absence of zeroes, see [`zero_terminated::Zt`].
11#[derive(ListHashes, Topological, Tagged, ParseAsInline, Default, Clone, PartialEq, Eq)]
12#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
13pub struct Lp<T>(pub T);
14
15impl<T> Deref for Lp<T> {
16    type Target = T;
17
18    fn deref(&self) -> &Self::Target {
19        &self.0
20    }
21}
22
23impl<T> DerefMut for Lp<T> {
24    fn deref_mut(&mut self) -> &mut Self::Target {
25        &mut self.0
26    }
27}
28
29impl<T: ToOutput> ToOutput for Lp<T> {
30    fn to_output(&self, output: &mut impl Output) {
31        if output.is_mangling() {
32            self.0.to_output(output);
33        }
34        if output.is_real() {
35            let data = self.0.vec();
36            let len = data.len();
37            let len = len as u64;
38            assert_ne!(len, u64::MAX);
39            let prefix = Le::<u64>(len);
40            prefix.to_output(output);
41            data.to_output(output);
42        }
43    }
44}
45
46impl<T: ToOutput> InlineOutput for Lp<T> {}
47
48impl<T: Size> Size for Lp<T>
49where
50    U8: Add<T::Size, Output: Unsigned>,
51{
52    type Size = Sum<U8, T::Size>;
53}
54
55impl<T: Size> MaybeHasNiche for Lp<T>
56where
57    U8: Add<T::Size, Output: ArrayLength>,
58{
59    type MnArray = tarr![SomeNiche<OneNiche<U8>>, NoNiche<ZeroNoNiche<T::Size>>];
60}
61
62impl<T: Parse<I>, I: ParseInput> ParseInline<I> for Lp<T> {
63    fn parse_inline(input: &mut I) -> crate::Result<Self> {
64        let prefix: Le<u64> = input.parse_inline()?;
65        let len = prefix.0;
66        let len = len.try_into().map_err(|_| Error::UnsupportedLength)?;
67        Ok(Self(input.parse_ahead(len)?))
68    }
69}
70
71#[test]
72fn prefixed() {
73    let a = Lp(vec![0, 1, 2]);
74    let data = a.vec();
75    let b = Lp::<Vec<u8>>::parse_slice_refless(&data).unwrap();
76    assert_eq!(*a, *b);
77}
78
79/// Length-prefixed [`Vec<u8>`]
80#[derive(Debug, Clone, ParseAsInline, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
81#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
82pub struct LpBytes(pub Vec<u8>);
83
84impl Deref for LpBytes {
85    type Target = Vec<u8>;
86
87    fn deref(&self) -> &Self::Target {
88        &self.0
89    }
90}
91
92impl DerefMut for LpBytes {
93    fn deref_mut(&mut self) -> &mut Self::Target {
94        &mut self.0
95    }
96}
97
98impl ToOutput for LpBytes {
99    fn to_output(&self, output: &mut impl Output) {
100        if output.is_real() {
101            let data = &self.0;
102            let len = data.len();
103            let len = len as u64;
104            assert_ne!(len, u64::MAX);
105            let prefix = Le::<u64>(len);
106            prefix.to_output(output);
107            data.to_output(output);
108        }
109    }
110}
111
112impl InlineOutput for LpBytes {}
113
114impl<I: ParseInput> ParseInline<I> for LpBytes {
115    fn parse_inline(input: &mut I) -> crate::Result<Self> {
116        let prefix: Le<u64> = input.parse_inline()?;
117        let len = prefix.0;
118        let len = len.try_into().map_err(|_| Error::UnsupportedLength)?;
119        Ok(Self(input.parse_n(len)?.into()))
120    }
121}
122
123impl Tagged for LpBytes {}
124impl ListHashes for LpBytes {}
125impl Topological for LpBytes {}
126
127/// Length-prefixed [`String`].
128#[derive(Debug, Clone, ParseAsInline, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
129#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
130pub struct LpString(pub String);
131
132impl Deref for LpString {
133    type Target = String;
134
135    fn deref(&self) -> &Self::Target {
136        &self.0
137    }
138}
139
140impl DerefMut for LpString {
141    fn deref_mut(&mut self) -> &mut Self::Target {
142        &mut self.0
143    }
144}
145
146impl ToOutput for LpString {
147    fn to_output(&self, output: &mut impl Output) {
148        if output.is_real() {
149            let data = self.0.as_bytes();
150            let len = data.len();
151            let len = len as u64;
152            assert_ne!(len, u64::MAX);
153            let prefix = Le::<u64>(len);
154            prefix.to_output(output);
155            data.to_output(output);
156        }
157    }
158}
159
160impl InlineOutput for LpString {}
161
162impl<I: ParseInput> ParseInline<I> for LpString {
163    fn parse_inline(input: &mut I) -> crate::Result<Self> {
164        String::from_utf8(input.parse_inline::<LpBytes>()?.0)
165            .map_err(Error::Utf8)
166            .map(Self)
167    }
168}
169
170impl Tagged for LpString {}
171impl ListHashes for LpString {}
172impl Topological for LpString {}