Skip to main content

sark_json/segment/document/
project.rs

1use std::{num::NonZero, task::Poll};
2
3use crate::segment::{Admitted, Document, Outcome, input::Split};
4
5/// Retains the source document until its admitted child transfer completes.
6pub struct Project<'d> {
7    pub(in crate::segment) doc: Document<'d>,
8    parts: Option<Split<'d>>,
9    field: usize,
10    error: Option<Result<(), crate::parsing::Error<'d>>>,
11}
12
13impl<'d> Project<'d> {
14    pub(in crate::segment) fn new(doc: Document<'d>, field: usize) -> Self {
15        Self {
16            doc,
17            parts: None,
18            field,
19            error: None,
20        }
21    }
22
23    pub(in crate::segment) fn with_parts(doc: Document<'d>, parts: Split<'d>) -> Self {
24        Self {
25            doc,
26            parts: Some(parts),
27            field: 0,
28            error: None,
29        }
30    }
31
32    pub fn release(&mut self, budget: &mut usize) -> Poll<()> {
33        self.error.get_or_insert(Ok(()));
34        if let Some(parts) = &mut self.parts
35            && parts.release(budget).is_pending()
36        {
37            return Poll::Pending;
38        }
39        self.doc.retire(budget)
40    }
41
42    pub fn step(
43        mut self,
44        budget: NonZero<usize>,
45    ) -> Outcome<'d, Self, (Document<'d>, Admitted<'d>)> {
46        let mut left = budget.get();
47        if self.error.is_some() {
48            if self.release(&mut left).is_pending() {
49                return Outcome::Pending(self);
50            }
51            if let Some(Err(error)) = self.error {
52                return Outcome::Failed(error);
53            }
54            return Outcome::Pending(self);
55        }
56        match self.try_step(&mut left) {
57            Ok(None) => Outcome::Pending(self),
58            Ok(Some(input)) => Outcome::Ready((self.doc, Admitted { input })),
59            Err(error) => {
60                self.error = Some(Err(error.into()));
61                Outcome::Pending(self)
62            }
63        }
64    }
65
66    fn try_step(
67        &mut self,
68        budget: &mut usize,
69    ) -> crate::Result<Option<super::super::input::Input<'d>>> {
70        if self.parts.is_none() {
71            let value = self.doc.field(self.field)?.ok_or(crate::Error::Invalid)?;
72            self.parts = Some(value.split()?);
73        }
74        match &mut self.parts {
75            Some(parts) => parts.step(&self.doc.input, budget),
76            None => Ok(None),
77        }
78    }
79}