Skip to main content

sark_json/segment/document/
mod.rs

1use std::{mem, task::Poll};
2
3use o3::buffer::storage;
4
5use crate::Error;
6
7pub(super) mod admitted;
8pub(super) mod project;
9pub(super) mod release;
10pub(super) mod value;
11
12use crate::segment::{Project, Release, input::Input, state};
13use value::Value;
14
15/// Parsed field index that continues to own every original transport segment.
16pub struct Document<'d> {
17    pub(super) input: Input<'d>,
18    pub(super) fields: Vec<Option<state::Value>>,
19}
20
21impl<'d> Document<'d> {
22    pub(super) fn new(input: Input<'d>, fields: Vec<Option<state::Value>>) -> Self {
23        Self { input, fields }
24    }
25
26    /// Retires field slots and input owners within the remaining work budget.
27    pub fn retire(&mut self, budget: &mut usize) -> Poll<()> {
28        self.drain(budget).0
29    }
30
31    #[inline(always)]
32    pub(super) fn drain(&mut self, budget: &mut usize) -> (Poll<()>, super::scanner::Released) {
33        while *budget != 0 && self.fields.pop().is_some() {
34            *budget -= 1;
35        }
36        if self.fields.is_empty() {
37            self.input.release(budget)
38        } else {
39            (Poll::Pending, super::scanner::Released::new())
40        }
41    }
42
43    /// Ends projection and retains the remaining owners for bounded release.
44    pub fn release(self) -> Release<'d> {
45        Release { document: self }
46    }
47
48    /// Borrows one field and its original input after a single table lookup.
49    /// A missing field is distinct from an invalid index or a JSON null value.
50    pub fn field(&self, field: usize) -> crate::Result<Option<Value<'_, 'd>>> {
51        Ok(self
52            .fields
53            .get(field)
54            .ok_or(Error::Invalid)?
55            .as_ref()
56            .map(|value| Value::new(&self.input, value)))
57    }
58
59    pub fn u64(&self, field: usize) -> crate::Result<u64> {
60        self.value(field)?.u64()
61    }
62
63    pub fn raw(&self, field: usize) -> crate::Result<crate::Raw<storage::Shared>> {
64        self.value(field)?.raw()
65    }
66
67    /// Starts a cooperative transfer of one already-validated compound.
68    /// Selection failures retain the document until budgeted retirement finishes.
69    pub fn project(self, field: usize) -> Project<'d> {
70        Project::new(self, field)
71    }
72
73    /// Selects and projects one compound without repeating its field lookup.
74    /// A missing field returns None; a present non-compound remains invalid.
75    /// Rejection preserves this document; only a successful transfer empties it.
76    pub fn project_at(&mut self, field: usize) -> crate::Result<Option<Project<'d>>> {
77        let Some(value) = self.field(field)? else {
78            return Ok(None);
79        };
80        let parts = value.split()?;
81        Ok(Some(Project::with_parts(
82            mem::replace(self, Self::new(Input::empty(), Vec::new())),
83            parts,
84        )))
85    }
86
87    fn value(&self, field: usize) -> crate::Result<Value<'_, 'd>> {
88        self.field(field)?.ok_or(Error::Invalid)
89    }
90}