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)]
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 dyn crate::Output) {
31        let data = self.0.vec();
32        let len = data.len();
33        let len = len as u64;
34        assert_ne!(len, u64::MAX);
35        let prefix = Le::<u64>(len);
36        prefix.to_output(output);
37        data.to_output(output);
38    }
39}
40
41impl<T: ToOutput> InlineOutput for Lp<T> {}
42
43impl<T: Size> Size for Lp<T>
44where
45    U8: Add<T::Size, Output: Unsigned>,
46{
47    type Size = Sum<U8, T::Size>;
48}
49
50impl<T: Size> MaybeHasNiche for Lp<T>
51where
52    U8: Add<T::Size, Output: ArrayLength>,
53{
54    type MnArray = tarr![SomeNiche<OneNiche<U8>>, NoNiche<ZeroNoNiche<T::Size>>];
55}
56
57impl<T: Parse<I>, I: ParseInput> ParseInline<I> for Lp<T> {
58    fn parse_inline(input: &mut I) -> crate::Result<Self> {
59        let prefix: Le<u64> = input.parse_inline()?;
60        let len = prefix.0;
61        let len = len.try_into().map_err(|_| Error::UnsupportedLength)?;
62        Ok(Self(input.parse_ahead(len)?))
63    }
64}
65
66#[test]
67fn prefixed() {
68    let a = Lp(vec![0, 1, 2]);
69    let data = a.vec();
70    let b = Lp::<Vec<u8>>::parse_slice_refless(&data).unwrap();
71    assert_eq!(*a, *b);
72}
73
74/// Length-prefixed [`Vec<u8>`]
75#[derive(Debug, Clone, ParseAsInline, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
76#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
77pub struct LpBytes(pub Vec<u8>);
78
79impl Deref for LpBytes {
80    type Target = Vec<u8>;
81
82    fn deref(&self) -> &Self::Target {
83        &self.0
84    }
85}
86
87impl DerefMut for LpBytes {
88    fn deref_mut(&mut self) -> &mut Self::Target {
89        &mut self.0
90    }
91}
92
93impl ToOutput for LpBytes {
94    fn to_output(&self, output: &mut dyn crate::Output) {
95        let data = &self.0;
96        let len = data.len();
97        let len = len as u64;
98        assert_ne!(len, u64::MAX);
99        let prefix = Le::<u64>(len);
100        prefix.to_output(output);
101        data.to_output(output);
102    }
103}
104
105impl InlineOutput for LpBytes {}
106
107impl<I: ParseInput> ParseInline<I> for LpBytes {
108    fn parse_inline(input: &mut I) -> crate::Result<Self> {
109        let prefix: Le<u64> = input.parse_inline()?;
110        let len = prefix.0;
111        let len = len.try_into().map_err(|_| Error::UnsupportedLength)?;
112        Ok(Self(input.parse_n(len)?.into()))
113    }
114}
115
116impl Tagged for LpBytes {}
117impl ListHashes for LpBytes {}
118impl Topological for LpBytes {}
119
120/// Length-prefixed [`String`].
121#[derive(Debug, Clone, ParseAsInline, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
122#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
123pub struct LpString(pub String);
124
125impl Deref for LpString {
126    type Target = String;
127
128    fn deref(&self) -> &Self::Target {
129        &self.0
130    }
131}
132
133impl DerefMut for LpString {
134    fn deref_mut(&mut self) -> &mut Self::Target {
135        &mut self.0
136    }
137}
138
139impl ToOutput for LpString {
140    fn to_output(&self, output: &mut dyn crate::Output) {
141        let data = self.0.as_bytes();
142        let len = data.len();
143        let len = len as u64;
144        assert_ne!(len, u64::MAX);
145        let prefix = Le::<u64>(len);
146        prefix.to_output(output);
147        data.to_output(output);
148    }
149}
150
151impl InlineOutput for LpString {}
152
153impl<I: ParseInput> ParseInline<I> for LpString {
154    fn parse_inline(input: &mut I) -> crate::Result<Self> {
155        String::from_utf8(input.parse_inline::<LpBytes>()?.0)
156            .map_err(Error::Utf8)
157            .map(Self)
158    }
159}
160
161impl Tagged for LpString {}
162impl ListHashes for LpString {}
163impl Topological for LpString {}