Skip to main content

rsonpath/input/
owned.rs

1//! Takes ownership of bytes of the input document.
2//!
3//! Choose this implementation if:
4//!
5//! 1. You already have the data loaded in-memory.
6//! 2. You don't want to deal with ownership and would rather have the input
7//!    take ownership of the bytes.
8//!
9//! ## Performance characteristics
10//!
11//! This is as fast as [`BorrowedBytes`](`super::BorrowedBytes`), unless
12//! the [`Borrow`] implementation of the underlying byte structure is weird
13//! and costly.
14// === Design note ===
15// This struct appears to be basically the same as BorrowedBytes, just with different
16// ownership mechanics. It appears that it should be possible to have a single struct
17// that achieves the API of both, taking either ownership or a borrow, but this leads to
18// lifetime issues around the current padding impl.
19
20use super::{
21    align_to,
22    borrowed::BorrowedBytesBlockIterator,
23    error::Infallible,
24    padding::{PaddedBlock, TwoSidesPaddedInput},
25    Input, SliceSeekable as _, MAX_BLOCK_SIZE,
26};
27use crate::{result::InputRecorder, string_pattern::StringPattern};
28use std::borrow::Borrow;
29
30/// Input wrapping a buffer borrowable as a slice of bytes.
31pub struct OwnedBytes<B> {
32    bytes: B,
33    middle_len: usize,
34    first_block: PaddedBlock,
35    last_block: PaddedBlock,
36}
37
38impl<B> OwnedBytes<B>
39where
40    B: Borrow<[u8]>,
41{
42    /// Create a new instance of [`OwnedBytes`] taking over the given buffer.
43    ///
44    /// The input will be automatically padded internally, incurring at most
45    /// two times [`MAX_BLOCK_SIZE`] of memory overhead.
46    #[inline(always)]
47    pub fn new(bytes: B) -> Self {
48        let (first, middle, last) = align_to::<MAX_BLOCK_SIZE>(bytes.borrow());
49        let first_block = PaddedBlock::pad_first_block(first);
50        let last_block = PaddedBlock::pad_last_block(last);
51
52        Self {
53            middle_len: middle.len(),
54            bytes,
55            first_block,
56            last_block,
57        }
58    }
59}
60
61impl<B> From<B> for OwnedBytes<B>
62where
63    B: Borrow<[u8]>,
64{
65    #[inline(always)]
66    fn from(value: B) -> Self {
67        Self::new(value)
68    }
69}
70
71impl From<String> for OwnedBytes<Vec<u8>> {
72    #[inline(always)]
73    fn from(value: String) -> Self {
74        Self::new(value.into_bytes())
75    }
76}
77
78impl<B> Input for OwnedBytes<B>
79where
80    B: Borrow<[u8]>,
81{
82    type BlockIterator<'i, 'r, R, const N: usize>
83        = BorrowedBytesBlockIterator<'r, TwoSidesPaddedInput<'i>, R, N>
84    where
85        Self: 'i,
86        R: InputRecorder<Self::Block<'i, N>> + 'r;
87
88    type Error = Infallible;
89
90    type Block<'i, const N: usize>
91        = &'i [u8]
92    where
93        Self: 'i;
94
95    #[inline(always)]
96    fn leading_padding_len(&self) -> usize {
97        self.first_block.padding_len()
98    }
99
100    #[inline(always)]
101    fn trailing_padding_len(&self) -> usize {
102        self.last_block.padding_len()
103    }
104
105    #[inline]
106    fn iter_blocks<'i, 'r, R, const N: usize>(&'i self, recorder: &'r R) -> Self::BlockIterator<'i, 'r, R, N>
107    where
108        R: InputRecorder<Self::Block<'i, N>>,
109    {
110        let (_, middle, _) = align_to::<MAX_BLOCK_SIZE>(self.bytes.borrow());
111        assert_eq!(
112            middle.len(),
113            self.middle_len,
114            "it is impossible for alignment to change after construction"
115        );
116
117        let padded = TwoSidesPaddedInput::new(&self.first_block, middle, &self.last_block);
118
119        BorrowedBytesBlockIterator::new(padded, recorder)
120    }
121
122    #[inline]
123    fn seek_backward(&self, from: usize, needle: u8) -> Option<usize> {
124        let offset = self.leading_padding_len();
125        let from = from.checked_sub(offset)?;
126
127        self.bytes.borrow().seek_backward(from, needle).map(|x| x + offset)
128    }
129
130    #[inline]
131    fn seek_forward<const N: usize>(&self, from: usize, needles: [u8; N]) -> Result<Option<(usize, u8)>, Self::Error> {
132        let offset = self.leading_padding_len();
133        let from = from.saturating_sub(offset);
134
135        Ok(self
136            .bytes
137            .borrow()
138            .seek_forward(from, needles)
139            .map(|(x, y)| (x + self.leading_padding_len(), y)))
140    }
141
142    #[inline]
143    fn seek_non_whitespace_forward(&self, from: usize) -> Result<Option<(usize, u8)>, Self::Error> {
144        let offset = self.leading_padding_len();
145        let from = from.saturating_sub(offset);
146
147        Ok(self
148            .bytes
149            .borrow()
150            .seek_non_whitespace_forward(from)
151            .map(|(x, y)| (x + self.leading_padding_len(), y)))
152    }
153
154    #[inline]
155    fn seek_non_whitespace_backward(&self, from: usize) -> Option<(usize, u8)> {
156        let offset = self.leading_padding_len();
157        let from = from.checked_sub(offset)?;
158
159        self.bytes
160            .borrow()
161            .seek_non_whitespace_backward(from)
162            .map(|(x, y)| (x + self.leading_padding_len(), y))
163    }
164
165    #[inline]
166    fn is_member_match(&self, from: usize, to: usize, member: &StringPattern) -> Result<bool, Self::Error> {
167        let offset = self.leading_padding_len();
168        let Some(from) = from.checked_sub(offset) else {
169            return Ok(false);
170        };
171
172        Ok(self.bytes.borrow().is_member_match(from, to - offset, member))
173    }
174}