Skip to main content

netgauze_locate/
lib.rs

1#[cfg(test)]
2mod tests;
3
4use nom::{AsBytes, Compare, CompareResult, InputIter, InputLength, InputTake, Offset, Slice};
5use std::ops::{RangeFrom, RangeTo};
6
7/// Cloned from the crate `nom_locate` but with the omission of computing
8/// the line & column number since we don't care about them in binary protocols,
9/// and they do make using the `LocateSpan` slower.
10#[derive(Debug, Clone, Copy)]
11pub struct BinarySpan<T> {
12    offset: usize,
13    fragment: T,
14}
15
16impl<T> BinarySpan<T> {
17    pub const fn new(buffer: T) -> Self {
18        Self {
19            offset: 0,
20            fragment: buffer,
21        }
22    }
23
24    /// Similar to `new_extra`, but allows overriding offset.
25    /// # Safety
26    /// This is unsafe, because giving an offset too large may result in
27    /// undefined behavior, as some methods move back along the fragment
28    /// assuming any negative index within the offset is valid.
29    pub const unsafe fn new_from_raw_offset(offset: usize, fragment: T) -> Self {
30        Self { offset, fragment }
31    }
32
33    pub const fn new_extra(program: T) -> BinarySpan<T> {
34        BinarySpan {
35            offset: 0,
36            fragment: program,
37        }
38    }
39
40    #[inline]
41    pub const fn location_offset(&self) -> usize {
42        self.offset
43    }
44
45    #[inline]
46    pub const fn fragment(&self) -> &T {
47        &self.fragment
48    }
49}
50
51impl<T, R> Slice<R> for BinarySpan<T>
52where
53    T: Slice<R> + Offset + AsBytes + Slice<RangeTo<usize>>,
54{
55    #[inline]
56    fn slice(&self, range: R) -> Self {
57        let next_fragment = self.fragment.slice(range);
58        let consumed_len = self.fragment.offset(&next_fragment);
59        if consumed_len == 0 {
60            return BinarySpan {
61                offset: self.offset,
62                fragment: next_fragment,
63            };
64        }
65
66        BinarySpan {
67            offset: self.offset + consumed_len,
68            fragment: next_fragment,
69        }
70    }
71}
72
73impl<T> InputIter for BinarySpan<T>
74where
75    T: InputIter,
76{
77    type Item = T::Item;
78    type Iter = T::Iter;
79    type IterElem = T::IterElem;
80    #[inline]
81    fn iter_indices(&self) -> Self::Iter {
82        self.fragment.iter_indices()
83    }
84    #[inline]
85    fn iter_elements(&self) -> Self::IterElem {
86        self.fragment.iter_elements()
87    }
88    #[inline]
89    fn position<P>(&self, predicate: P) -> Option<usize>
90    where
91        P: Fn(Self::Item) -> bool,
92    {
93        self.fragment.position(predicate)
94    }
95    #[inline]
96    fn slice_index(&self, count: usize) -> Result<usize, nom::Needed> {
97        self.fragment.slice_index(count)
98    }
99}
100
101impl<T: InputLength> InputLength for BinarySpan<T> {
102    #[inline]
103    fn input_len(&self) -> usize {
104        self.fragment.input_len()
105    }
106}
107
108impl<T> InputTake for BinarySpan<T>
109where
110    Self: Slice<RangeFrom<usize>> + Slice<RangeTo<usize>>,
111{
112    #[inline]
113    fn take(&self, count: usize) -> Self {
114        self.slice(..count)
115    }
116
117    #[inline]
118    fn take_split(&self, count: usize) -> (Self, Self) {
119        (self.slice(count..), self.slice(..count))
120    }
121}
122
123impl<T> core::ops::Deref for BinarySpan<T> {
124    type Target = T;
125    fn deref(&self) -> &Self::Target {
126        &self.fragment
127    }
128}
129
130impl<T, U> AsRef<U> for BinarySpan<&T>
131where
132    T: ?Sized + AsRef<U>,
133    U: ?Sized,
134{
135    fn as_ref(&self) -> &U {
136        self.fragment.as_ref()
137    }
138}
139
140impl<T: AsBytes> AsBytes for BinarySpan<T> {
141    #[inline]
142    fn as_bytes(&self) -> &[u8] {
143        self.fragment.as_bytes()
144    }
145}
146
147impl<T: AsBytes + PartialEq> PartialEq for BinarySpan<T> {
148    #[inline]
149    fn eq(&self, other: &Self) -> bool {
150        self.offset == other.offset && self.fragment == other.fragment
151    }
152}
153
154impl<T: AsBytes + Eq> Eq for BinarySpan<T> {}
155
156impl<A: Compare<B>, B: Into<BinarySpan<B>>> Compare<B> for BinarySpan<A> {
157    #[inline(always)]
158    fn compare(&self, t: B) -> CompareResult {
159        self.fragment.compare(t.into().fragment)
160    }
161
162    #[inline(always)]
163    fn compare_no_case(&self, t: B) -> CompareResult {
164        self.fragment.compare_no_case(t.into().fragment)
165    }
166}
167
168impl<T: AsBytes> From<T> for BinarySpan<T> {
169    #[inline]
170    fn from(i: T) -> Self {
171        Self::new_extra(i)
172    }
173}
174
175#[test]
176fn it_should_implement_as_ref_for_the_underlying_type() {
177    fn function_accepting_u8_slice<B: AsRef<[u8]>>(_data: B) {}
178    let bytes_data = BinarySpan::new(b"some binary data");
179    function_accepting_u8_slice(bytes_data);
180}