Skip to main content

sark_json/segment/frames/
mod.rs

1use std::{
2    marker,
3    num::NonZero,
4    ops::{self, ControlFlow},
5    task::Poll,
6};
7
8use o3::{
9    alloc,
10    buffer::{resident, storage},
11};
12use sark_http::request;
13
14use crate::{
15    Error, Nesting, Plain, Raw, Text,
16    input::Taken,
17    segment::{self, Atom, Cursor, End, Outcome, cursor::Replay, input::Input, is_delimiter},
18    source::string::Scan,
19};
20
21mod context;
22mod sealed;
23pub(super) use context::Context;
24pub(super) use sealed::Sealed;
25
26/// Representation of each element in a retained JSON array.
27#[derive(Clone, Copy, Eq, PartialEq)]
28pub enum Mode {
29    Frame,
30    Plain,
31    Raw,
32}
33
34/// Bytes admitted by this array's selected grammar, before owner binding.
35#[repr(transparent)]
36pub struct Captured<F> {
37    bytes: storage::Shared,
38    marker: marker::PhantomData<F>,
39}
40
41/// The admitted byte domain selected for each array element.
42pub trait Capture<C: Context>: Sealed + Sized {
43    type Value;
44    const MODE: Mode;
45    fn bind(context: C, bytes: Captured<Self>) -> Self::Value;
46}
47
48impl Capture<()> for Text<storage::Shared> {
49    type Value = Self;
50    const MODE: Mode = Mode::Frame;
51    fn bind(_: (), bytes: Captured<Self>) -> Self::Value {
52        Self::admitted(bytes.bytes)
53    }
54}
55
56impl<'d> Capture<request::Id<'d>> for Text<storage::Shared> {
57    type Value = Text<request::Bytes<'d>>;
58    const MODE: Mode = Mode::Frame;
59    fn bind(context: request::Id<'d>, bytes: Captured<Self>) -> Self::Value {
60        Self::admitted(bytes.bytes).into_request(context)
61    }
62}
63
64impl Capture<()> for Plain<storage::Shared> {
65    type Value = Self;
66    const MODE: Mode = Mode::Plain;
67    fn bind(_: (), bytes: Captured<Self>) -> Self::Value {
68        Self::admitted(bytes.bytes)
69    }
70}
71
72impl<'d> Capture<request::Id<'d>> for Plain<storage::Shared> {
73    type Value = Plain<request::Bytes<'d>>;
74    const MODE: Mode = Mode::Plain;
75    fn bind(context: request::Id<'d>, bytes: Captured<Self>) -> Self::Value {
76        Self::admitted(bytes.bytes).into_request(context)
77    }
78}
79
80impl Capture<()> for Raw<storage::Shared> {
81    type Value = Self;
82    const MODE: Mode = Mode::Raw;
83    fn bind(_: (), bytes: Captured<Self>) -> Self::Value {
84        Self::admitted(bytes.bytes)
85    }
86}
87
88impl<'d> Capture<request::Id<'d>> for Raw<storage::Shared> {
89    type Value = Raw<request::Bytes<'d>>;
90    const MODE: Mode = Mode::Raw;
91    fn bind(context: request::Id<'d>, bytes: Captured<Self>) -> Self::Value {
92        Self::admitted(bytes.bytes).into_request(context)
93    }
94}
95
96/// Cooperative materialization of a retained JSON array.
97/// Copy states replay only a completed string's content in this same immutable
98/// input. Their cursor and end stay with that input across budget yields.
99pub struct Frames<'d, C: Context = (), F: Capture<C> = Text<storage::Shared>> {
100    input: Input<'d>,
101    cursor: Cursor,
102    state: State,
103    values: Vec<F::Value>,
104    context: C,
105    marker: marker::PhantomData<F>,
106}
107
108enum State {
109    Leading,
110    Element { end: End },
111    String { start: usize, string: Scan },
112    Atom { start: usize, atom: Atom },
113    Compound { start: usize, nesting: Nesting },
114    Copy(Replay),
115    Delimiter,
116    Trailing,
117    Release,
118    Failed(Option<crate::Error>),
119}
120
121impl<'d> Frames<'d> {
122    pub fn from_scoped(input: Vec<resident::Shared<'d>>) -> crate::Result<Self> {
123        Ok(Self::with_input(Input::new(input)?, ()))
124    }
125}
126
127impl<'d, C: Context, F: Capture<C>> Frames<'d, C, F> {
128    pub fn admitted(input: segment::Admitted<'d>, context: C) -> Self {
129        Self::with_input(input.input, context)
130    }
131
132    fn with_input(input: Input<'d>, context: C) -> Self {
133        Self {
134            input,
135            cursor: Cursor::new(),
136            state: State::Leading,
137            values: Vec::new(),
138            context,
139            marker: marker::PhantomData,
140        }
141    }
142
143    fn capture(&mut self, range: ops::Range<usize>, removed: usize) -> crate::Result<()> {
144        alloc::VecExt::try_reserve(&mut self.values, 1).map_err(Error::Allocation)?;
145        let owned = if removed == 0 {
146            self.input.try_own(range.clone())?
147        } else {
148            None
149        };
150        if let Some(shared) = owned {
151            self.store(shared);
152        } else {
153            let output =
154                alloc::VecExt::try_new(range.len() - removed).map_err(Error::Allocation)?;
155            let cursor = Cursor::at(&self.input, range.start).ok_or(Error::Invalid)?;
156            self.state = State::Copy(Replay::new(cursor, range.end, output, removed != 0));
157        }
158        Ok(())
159    }
160
161    fn store(&mut self, bytes: storage::Shared) {
162        // SAFETY: capture reserved this slot; copying preserves the exclusive values table.
163        unsafe { alloc::raw::VecExt::vacancy(&mut self.values) }.insert(F::bind(
164            self.context,
165            Captured {
166                bytes,
167                marker: marker::PhantomData,
168            },
169        ));
170        self.state = State::Delimiter;
171    }
172
173    pub fn release(&mut self, budget: &mut usize) -> Poll<()> {
174        if !matches!(self.state, State::Failed(_)) {
175            self.state = State::Failed(None);
176        }
177        while !self.values.is_empty() {
178            if *budget == 0 {
179                return Poll::Pending;
180            }
181            drop(self.values.pop());
182            *budget -= 1;
183        }
184        self.input.release(budget).0
185    }
186
187    pub fn step(mut self, budget: NonZero<usize>) -> Outcome<'d, Self, Vec<F::Value>> {
188        if matches!(self.state, State::Failed(_)) {
189            let mut left = budget.get();
190            if self.release(&mut left).is_pending() {
191                return Outcome::Pending(self);
192            }
193            if let State::Failed(Some(error)) = self.state {
194                return Outcome::Failed(error.into());
195            }
196            return Outcome::Pending(self);
197        }
198        match self.try_step(budget) {
199            Ok(ControlFlow::Continue(())) => Outcome::Pending(self),
200            Ok(ControlFlow::Break(values)) => Outcome::Ready(values),
201            Err(error) => {
202                self.state = State::Failed(Some(error));
203                Outcome::Pending(self)
204            }
205        }
206    }
207
208    fn try_step(&mut self, budget: NonZero<usize>) -> crate::Result<ControlFlow<Vec<F::Value>>> {
209        let mut left = budget.get();
210        while let Some(budget) = NonZero::new(left) {
211            let input = &self.input;
212            match &mut self.state {
213                State::Failed(_) => break,
214                State::Leading => {
215                    if self.cursor.take_ws(input) == Taken::Yes {
216                        left -= 1;
217                    } else {
218                        if self.cursor.take(input, b'[') == Taken::No {
219                            return Err(Error::Invalid);
220                        }
221                        left -= 1;
222                        self.state = State::Element { end: End::Allowed };
223                    }
224                }
225                State::Element { end } => {
226                    if self.cursor.take_ws(input) == Taken::Yes {
227                        left -= 1;
228                    } else if *end == End::Allowed && self.cursor.take(input, b']') == Taken::Yes {
229                        left -= 1;
230                        self.state = State::Trailing;
231                    } else {
232                        let (byte, advance) = self.cursor.read(input).ok_or(Error::Invalid)?;
233                        if byte == b'"' {
234                            self.cursor.advance(advance);
235                            left -= 1;
236                            self.state = State::String {
237                                start: self.cursor.absolute,
238                                string: Scan::new(input.is_admitted()),
239                            };
240                        } else if F::MODE != Mode::Raw {
241                            return Err(Error::Invalid);
242                        } else if matches!(byte, b'{' | b'[') {
243                            let nesting = if input.is_admitted() {
244                                Nesting::admitted()
245                            } else {
246                                Nesting::start(byte)?
247                            };
248                            let start = self.cursor.absolute;
249                            self.cursor.advance(advance);
250                            left -= 1;
251                            self.state = State::Compound { start, nesting };
252                        } else {
253                            let atom = Atom::new(byte, false)?;
254                            self.state = State::Atom {
255                                start: self.cursor.absolute,
256                                atom,
257                            };
258                        }
259                    }
260                }
261                State::String { start, string } => {
262                    let (byte, advance) = self.cursor.read(input).ok_or(Error::Invalid)?;
263                    let decoded = string.step(byte)?;
264                    if decoded.is_none() {
265                        let (range, removed) = match F::MODE {
266                            Mode::Raw => (*start - 1..self.cursor.absolute + 1, 0),
267                            Mode::Plain if string.removed() != 0 => {
268                                return Err(Error::Invalid);
269                            }
270                            Mode::Plain | Mode::Frame => {
271                                (*start..self.cursor.absolute, string.removed())
272                            }
273                        };
274                        self.cursor.advance(advance);
275                        left -= 1;
276                        self.capture(range, removed)?;
277                    } else {
278                        self.cursor.advance(advance);
279                        left -= 1;
280                    }
281                }
282                State::Atom { start, atom } => {
283                    let (byte, advance) = self.cursor.read(input).ok_or(Error::Invalid)?;
284                    if is_delimiter(byte) {
285                        atom.finish()?;
286                        let range = *start..self.cursor.absolute;
287                        self.capture(range, 0)?;
288                    } else {
289                        *atom = atom.step(byte)?;
290                        self.cursor.advance(advance);
291                        left -= 1;
292                    }
293                }
294                State::Compound { start, nesting } => {
295                    let (byte, advance) = self.cursor.read(input).ok_or(Error::Invalid)?;
296                    let done = nesting.step(byte)?;
297                    self.cursor.advance(advance);
298                    left -= 1;
299                    if done {
300                        let range = *start..self.cursor.absolute;
301                        self.capture(range, 0)?;
302                    }
303                }
304                State::Copy(replay) => {
305                    if replay.is_done() {
306                        let shared = replay.try_finish()?;
307                        self.store(shared);
308                    } else {
309                        let copied = replay.try_copy(input, budget)?;
310                        left -= copied.get();
311                    }
312                }
313                State::Delimiter => {
314                    if self.cursor.take_ws(input) == Taken::Yes {
315                        left -= 1;
316                    } else if self.cursor.take(input, b',') == Taken::Yes {
317                        left -= 1;
318                        self.state = State::Element {
319                            end: End::Forbidden,
320                        };
321                    } else if self.cursor.take(input, b']') == Taken::Yes {
322                        left -= 1;
323                        self.state = State::Trailing;
324                    } else {
325                        return Err(Error::Invalid);
326                    }
327                }
328                State::Trailing => {
329                    if self.cursor.take_ws(input) == Taken::Yes {
330                        left -= 1;
331                    } else if self.cursor.absolute == input.len() {
332                        self.state = State::Release;
333                    } else {
334                        return Err(Error::Invalid);
335                    }
336                }
337                State::Release => {
338                    if self.input.release(&mut left).0.is_ready() {
339                        return Ok(ControlFlow::Break(std::mem::take(&mut self.values)));
340                    }
341                }
342            }
343        }
344        Ok(ControlFlow::Continue(()))
345    }
346}