dangerous/input/
span.rs

1use core::ops::Range;
2use core::ptr::NonNull;
3use core::slice;
4
5use crate::display::InputDisplay;
6use crate::fmt;
7use crate::input::{Input, MaybeString};
8
9/// Range of [`Input`].
10///
11/// Spans are specific to the input chain they were created in as the range is
12/// stored as raw start and end pointers.
13///
14/// You can create a span from either [`Input::span()`] or from a raw slice via
15/// [`Span::from()`].
16///
17/// [`Input`]: crate::Input  
18/// [`Input::span()`]: crate::Input::span()
19#[must_use]
20#[derive(Copy, Clone, Eq, PartialEq, Hash)]
21pub struct Span {
22    start: NonNull<u8>,
23    end: NonNull<u8>,
24}
25
26impl Span {
27    /// Returns the number of bytes spanned.
28    #[must_use]
29    #[inline(always)]
30    pub fn len(self) -> usize {
31        self.end.as_ptr() as usize - self.start.as_ptr() as usize
32    }
33
34    /// Returns `true` if no bytes are spanned.
35    #[must_use]
36    #[inline(always)]
37    pub fn is_empty(self) -> bool {
38        self.start == self.end
39    }
40
41    /// Returns `true` if the span is completely within the bounds of the
42    /// specified parent.
43    ///
44    /// # Examples
45    ///
46    /// ```
47    /// use dangerous::Span;
48    ///
49    /// let bytes = [0_u8; 64];
50    ///
51    /// // Within
52    /// let parent = Span::from(&bytes[16..32]);
53    /// let child = Span::from(&bytes[20..24]);
54    /// assert!(child.is_within(parent));
55    /// assert!(parent.is_within(parent));
56    ///
57    /// // Left out of bound
58    /// let parent = Span::from(&bytes[16..32]);
59    /// let child = Span::from(&bytes[15..24]);
60    /// assert!(!child.is_within(parent));
61    ///
62    /// // Right out of bound
63    /// let parent = Span::from(&bytes[16..32]);
64    /// let child = Span::from(&bytes[20..33]);
65    /// assert!(!child.is_within(parent));
66    ///
67    /// // Both out of bound
68    /// let parent = Span::from(&bytes[16..32]);
69    /// let child = Span::from(&bytes[15..33]);
70    /// assert!(!child.is_within(parent));
71    /// ```
72    #[must_use]
73    #[inline(always)]
74    pub fn is_within(self, other: Span) -> bool {
75        other.start <= self.start && other.end >= self.end
76    }
77
78    /// Returns `true` if `self` points to the start of `other`, spanning no bytes.
79    ///
80    /// # Example
81    ///
82    /// ```
83    /// use dangerous::Span;
84    ///
85    /// let bytes = &[1, 2, 3, 4][..];
86    /// let span = Span::from(bytes);
87    ///
88    /// assert!(span.start().is_start_of(span));
89    /// assert!(!span.is_start_of(span));
90    /// ```
91    #[must_use]
92    #[inline(always)]
93    pub fn is_start_of(self, other: Span) -> bool {
94        self.is_empty() && other.start == self.start
95    }
96
97    /// Returns `true` if `self` points to the end of `other`, spanning no bytes.
98    ///
99    /// # Example
100    ///
101    /// ```
102    /// use dangerous::Span;
103    ///
104    /// let bytes = &[1, 2, 3, 4][..];
105    /// let span = Span::from(bytes);
106    ///
107    /// assert!(span.end().is_end_of(span));
108    /// assert!(!span.is_end_of(span));
109    /// ```
110    #[must_use]
111    #[inline(always)]
112    pub fn is_end_of(self, other: Span) -> bool {
113        self.is_empty() && other.end == self.end
114    }
115
116    /// Returns `true` if `self` overlaps the start of `other`.
117    ///
118    /// # Example
119    ///
120    /// ```
121    /// use dangerous::Span;
122    ///
123    /// let all = b"0123456789";
124    /// let a = Span::from(&all[0..9]);
125    /// let b = Span::from(&all[6..9]);
126    ///
127    /// assert!(a.is_overlapping_start_of(b));
128    ///
129    /// ```
130    #[must_use]
131    #[inline(always)]
132    pub fn is_overlapping_start_of(self, other: Span) -> bool {
133        other.start > self.start
134    }
135
136    /// Returns `true` if `self` overlaps the end of `other`.
137    #[must_use]
138    #[inline(always)]
139    pub fn is_overlapping_end_of(self, other: Span) -> bool {
140        other.end < self.end
141    }
142
143    /// Returns `true` if `self`'s start is within `other`.
144    #[must_use]
145    #[inline(always)]
146    #[allow(clippy::suspicious_operation_groupings)]
147    pub fn is_start_within(self, other: Span) -> bool {
148        self.start >= other.start && self.start < other.end
149    }
150
151    /// Returns `true` if `self`'s end is within `other`.
152    #[must_use]
153    #[inline(always)]
154    #[allow(clippy::suspicious_operation_groupings)]
155    pub fn is_end_within(self, other: Span) -> bool {
156        self.end >= other.start && self.end < other.end
157    }
158
159    /// Returns a span pointing to the start of self, spanning no bytes.
160    pub fn start(self) -> Self {
161        Self {
162            start: self.start,
163            end: self.start,
164        }
165    }
166
167    /// Returns a span pointing to the end of self, spanning no bytes.
168    pub fn end(self) -> Self {
169        Self {
170            start: self.end,
171            end: self.end,
172        }
173    }
174
175    /// Returns the sub slice of the provided parent `self` refers to or `None`
176    /// if `self` is not within the parent or does not align with start and end
177    /// token boundaries.
178    ///
179    /// You can get a span of [`Input`], `&str` or `&[u8]`.
180    ///
181    /// # Example
182    ///
183    /// ```
184    /// use dangerous::Span;
185    ///
186    /// let parent = &[1, 2, 3, 4][..];
187    /// let sub = &parent[1..2];
188    /// assert_eq!(Span::from(sub).of(parent), Some(sub));
189    ///
190    /// let non_span = Span::from(&[1, 2, 2, 4][..]);
191    /// assert_eq!(non_span.of(parent), None);
192    /// ```
193    #[must_use]
194    pub fn of<P>(self, parent: P) -> Option<P>
195    where
196        P: Parent,
197    {
198        parent.extract(self)
199    }
200
201    /// Returns `Some(Range)` with the `start` and `end` offsets of `self`
202    /// within the `parent`. `None` is returned if `self` is not within in the
203    /// `parent`.
204    ///
205    /// # Example
206    ///
207    /// ```
208    /// use dangerous::Span;
209    ///
210    /// let parent = &[1, 2, 3, 4][..];
211    /// let sub_range = 1..2;
212    /// let sub = &parent[sub_range.clone()];
213    ///
214    /// assert_eq!(Span::from(sub).range_of(parent.into()), Some(sub_range))
215    /// ```
216    #[must_use]
217    #[inline(always)]
218    pub fn range_of(self, parent: Span) -> Option<Range<usize>> {
219        if self.is_within(parent) {
220            let start_offset = self.start.as_ptr() as usize - parent.start.as_ptr() as usize;
221            let end_offset = self.end.as_ptr() as usize - parent.start.as_ptr() as usize;
222            Some(start_offset..end_offset)
223        } else {
224            None
225        }
226    }
227
228    /// Returns `None` if the span is empty, `Some(Self)` if not.
229    ///
230    /// # Example
231    ///
232    /// ```
233    /// use dangerous::Span;
234    ///
235    /// let bytes = &[0][..];
236    /// assert!(Span::from(bytes).non_empty().is_some());
237    ///
238    /// let bytes = &[][..];
239    /// assert!(Span::from(bytes).non_empty().is_none());
240    /// ```
241    #[must_use]
242    #[inline(always)]
243    pub fn non_empty(self) -> Option<Self> {
244        if self.is_empty() {
245            None
246        } else {
247            Some(self)
248        }
249    }
250
251    /// Wraps the span with improved debugging support given the containing
252    /// input.
253    #[inline(always)]
254    #[allow(clippy::needless_pass_by_value)]
255    pub fn debug_for(self, input: MaybeString<'_>) -> DebugFor<'_> {
256        DebugFor {
257            bytes: input.as_dangerous_bytes(),
258            str_hint: input.is_string(),
259            span: self,
260        }
261    }
262}
263
264impl fmt::DisplayBase for Span {
265    fn fmt(&self, w: &mut dyn fmt::Write) -> fmt::Result {
266        w.write_str("(ptr: ")?;
267        w.write_usize(self.start.as_ptr() as usize)?;
268        w.write_str(", len: ")?;
269        w.write_usize(self.len())?;
270        w.write_char(')')
271    }
272}
273
274impl From<&[u8]> for Span {
275    #[inline(always)]
276    fn from(value: &[u8]) -> Self {
277        let range = value.as_ptr_range();
278        // SAFETY: it is invalid for a slice ptr to be null.
279        // See: https://doc.rust-lang.org/std/slice/fn.from_raw_parts.html
280        unsafe {
281            Self {
282                start: NonNull::new_unchecked(range.start as _),
283                end: NonNull::new_unchecked(range.end as _),
284            }
285        }
286    }
287}
288
289impl From<&str> for Span {
290    #[inline(always)]
291    fn from(value: &str) -> Self {
292        Self::from(value.as_bytes())
293    }
294}
295
296impl fmt::Debug for Span {
297    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
298        f.debug_struct("Span")
299            .field("ptr", &self.start)
300            .field("len", &self.len())
301            .finish()
302    }
303}
304
305// SAFETY: Span can only dereference the data pointed to if the data is present
306// and passed as a parent. This makes the internal pointers safe to alias across
307// threads as the parent data enforces the aliasing rules.
308unsafe impl Send for Span {}
309
310// SAFETY: Span can only dereference the data pointed to if the data is present
311// and passed as a parent. This makes the internal pointers safe to alias across
312// threads as the parent data enforces the aliasing rules.
313unsafe impl Sync for Span {}
314
315#[must_use]
316pub struct DebugFor<'a> {
317    span: Span,
318    str_hint: bool,
319    bytes: &'a [u8],
320}
321
322impl<'a> fmt::Debug for DebugFor<'a> {
323    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
324        match self.span.of(self.bytes) {
325            Some(valid) => {
326                let display = InputDisplay::from_bytes(valid).with_formatter(f);
327                let display = if self.str_hint {
328                    display.str_hint()
329                } else {
330                    display
331                };
332                f.debug_tuple("Span").field(&display).finish()
333            }
334            None => fmt::Debug::fmt(&self.span, f),
335        }
336    }
337}
338
339pub trait Parent: Sized {
340    fn extract(self, span: Span) -> Option<Self>;
341}
342
343impl Parent for &[u8] {
344    #[inline(always)]
345    fn extract(self, span: Span) -> Option<Self> {
346        if span.is_within(self.into()) {
347            // SAFETY: we have checked that the slice is valid within the
348            // parent, so we can create a slice from our bounds.
349            unsafe { Some(slice::from_raw_parts(span.start.as_ptr(), span.len())) }
350        } else {
351            None
352        }
353    }
354}
355
356impl Parent for &str {
357    #[inline]
358    fn extract(self, span: Span) -> Option<Self> {
359        span.range_of(self.into()).and_then(|range| {
360            if self.is_char_boundary(range.start) && self.is_char_boundary(range.end) {
361                Some(&self[range])
362            } else {
363                None
364            }
365        })
366    }
367}
368
369impl<'i, T> Parent for T
370where
371    T: Input<'i>,
372{
373    #[inline]
374    fn extract(self, span: Span) -> Option<Self> {
375        span.range_of(self.span()).and_then(|range| {
376            if self.verify_token_boundary(range.start).is_ok()
377                && self.verify_token_boundary(range.end).is_ok()
378            {
379                // SAFETY: we have checked that the range start and end are
380                // valid boundary indexes within the parent, so we can split
381                // with them.
382                let sub = unsafe {
383                    let (_, tail) = self.split_at_byte_unchecked(range.start);
384                    let (sub, _) = tail.split_at_byte_unchecked(range.end - range.start);
385                    sub
386                };
387                Some(sub)
388            } else {
389                None
390            }
391        })
392    }
393}