use super::{Instant, Parser};
use crate::action::Action;
#[derive(Debug, Clone, Copy)]
pub struct Builder<T, State = (), Heap = ()> {
state: State,
heap: Heap,
entry: T,
}
impl Builder<(), (), ()> {
#[inline]
pub const fn new() -> Self {
Builder {
state: (),
heap: (),
entry: (),
}
}
}
impl Default for Builder<(), (), ()> {
#[inline]
fn default() -> Self {
Self::new()
}
}
impl<T, State, Heap> Builder<T, State, Heap> {
#[inline]
pub fn state<NewState>(self, state: NewState) -> Builder<T, NewState, Heap> {
Builder {
state,
heap: self.heap,
entry: self.entry,
}
}
#[inline]
pub fn heap<NewHeap>(self, heap: NewHeap) -> Builder<T, State, NewHeap> {
Builder {
heap,
state: self.state,
entry: self.entry,
}
}
#[inline]
pub fn entry<Entry>(self, entry: Entry) -> Builder<Entry, State, Heap> {
Builder {
entry,
state: self.state,
heap: self.heap,
}
}
#[inline]
pub fn build<Text: ?Sized>(self, text: &Text) -> Parser<T>
where
T: Action<Text = Text, State = State, Heap = Heap>,
{
Parser {
state: self.state,
heap: self.heap,
entry: self.entry,
instant: Instant::new(text),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{combinator::eat, contextual};
#[test]
fn parser_builder_default() {
let mut parser = Builder::default()
.entry(eat("hello ") + "world")
.build("hello world");
let output = parser.next().unwrap();
assert_eq!(output.digested, 11);
let _: () = output.value;
assert!(parser.next().is_none());
let _: () = parser.heap;
let _: () = parser.state;
}
#[test]
fn parser_builder_with_state_heap() {
contextual!(i32, i32);
let mut parser = Builder::default()
.state(1)
.heap(1)
.entry((eat("hello ") + "world").then(|input| {
*input.state = 1;
*input.heap = 1;
}))
.build("hello world");
let output = parser.next().unwrap();
assert_eq!(output.digested, 11);
let _: () = output.value;
assert!(parser.next().is_none());
assert_eq!(parser.heap, 1);
assert_eq!(parser.state, 1);
}
#[test]
fn re_use_entry_with_ref() {
let entry = eat("hello ") + "world";
let mut p1 = Builder::default().entry(&entry).build("hello world");
let mut p2 = Builder::default().entry(&entry).build("hello");
assert!(p1.next().is_some());
assert!(p2.next().is_none());
}
}