oni_comb_parser/combinator/
recursive.rs1use alloc::boxed::Box;
2use alloc::rc::Rc;
3use core::cell::UnsafeCell;
4
5use crate::fail::PResult;
6use crate::input::Input;
7use crate::parser::Parser;
8
9type DynParser<'a, I, O, E> = dyn Parser<I, Output = O, Error = E> + 'a;
10
11struct RecursiveInner<'a, I: Input, O, E> {
12 inner: UnsafeCell<Option<Box<DynParser<'a, I, O, E>>>>,
13}
14
15pub struct Recursive<'a, I: Input, O, E> {
20 shared: Rc<RecursiveInner<'a, I, O, E>>,
21}
22
23impl<'a, I: Input, O, E> Clone for Recursive<'a, I, O, E> {
24 fn clone(&self) -> Self {
25 Recursive {
26 shared: Rc::clone(&self.shared),
27 }
28 }
29}
30
31impl<'a, I: Input, O, E> Parser<I> for Recursive<'a, I, O, E> {
32 type Error = E;
33 type Output = O;
34
35 #[inline]
36 fn parse_next(&mut self, input: &mut I) -> PResult<O, E> {
37 unsafe {
42 (*self.shared.inner.get())
43 .as_mut()
44 .expect("recursive parser not initialized")
45 .parse_next(input)
46 }
47 }
48}
49
50pub fn recursive<'a, I, O, E, F, P>(f: F) -> Recursive<'a, I, O, E>
63where
64 I: Input,
65 F: FnOnce(Recursive<'a, I, O, E>) -> P,
66 P: Parser<I, Output = O, Error = E> + 'a, {
67 let rec = Recursive {
68 shared: Rc::new(RecursiveInner {
69 inner: UnsafeCell::new(None),
70 }),
71 };
72 let parser = f(rec.clone());
73 unsafe {
74 *rec.shared.inner.get() = Some(Box::new(parser));
75 }
76 rec
77}