use super::*;
#[derive(Debug, Clone, PartialEq)]
pub struct RdSexpr<'a> {
path: RdPath,
code: &'a str,
options: Option<RdOptionList<'a>>,
}
impl<'a> RdSexpr<'a> {
pub fn path(&self) -> &RdPath {
&self.path
}
pub fn code(&self) -> &'a str {
self.code
}
pub fn options(&self) -> Option<&RdOptionList<'a>> {
self.options.as_ref()
}
pub fn option_overrides(&self) -> RdSexprOptionOverrides {
self.options
.as_ref()
.map_or_else(RdSexprOptionOverrides::empty, RdOptionList::typed)
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct RdOpts<'a> {
path: RdPath,
options: RdOptionList<'a>,
}
impl<'a> RdOpts<'a> {
pub fn path(&self) -> &RdPath {
&self.path
}
pub fn options(&self) -> &RdOptionList<'a> {
&self.options
}
pub fn option_overrides(&self) -> RdSexprOptionOverrides {
self.options.typed()
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct RdResolvedSexpr<'a> {
view: RdSexpr<'a>,
effective: RdEffectiveSexprOptions,
}
impl<'a> RdResolvedSexpr<'a> {
pub fn view(&self) -> &RdSexpr<'a> {
&self.view
}
pub fn effective_options(&self) -> RdEffectiveSexprOptions {
self.effective
}
pub fn state(&self) -> RdDynamicMarkupState {
RdDynamicMarkupState::Unresolved {
stage: self.effective.stage,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum RdDynamicMarkupState {
Unresolved { stage: RdSexprStage },
}
#[derive(Debug, Clone, PartialEq)]
#[non_exhaustive]
pub enum RdDynamicMarkupEvent<'a> {
OptionsChanged {
view: RdOpts<'a>,
effective: RdEffectiveSexprOptions,
},
Sexpr(RdResolvedSexpr<'a>),
}
pub struct RdDynamicMarkupIter<'a> {
frames: Vec<RdTraversalFrame<'a>>,
effective: RdEffectiveSexprOptions,
}
struct RdTraversalFrame<'a> {
nodes: &'a [RdNode],
next: usize,
path: RdPath,
top_level: bool,
}
impl<'a> Iterator for RdDynamicMarkupIter<'a> {
type Item = Result<RdDynamicMarkupEvent<'a>, RdOptionError>;
fn next(&mut self) -> Option<Self::Item> {
loop {
let frame = self.frames.last_mut()?;
if frame.next == frame.nodes.len() {
self.frames.pop();
continue;
}
let index = frame.next;
frame.next += 1;
let path = if frame.top_level {
RdPath::new(vec![RdPathSegment::TopLevel(index)])
} else {
frame.path.with_child(index)
};
let node = &frame.nodes[index];
if let Some(tagged) = node.as_tagged() {
let result = match tagged.tag() {
RdTag::RdOpts => match tagged.inspect_rd_opts(&path) {
Ok(view) => {
let mut effective = self.effective;
view.option_overrides().apply_to(&mut effective);
self.effective = effective;
Ok(RdDynamicMarkupEvent::OptionsChanged { view, effective })
}
Err(error) => Err(error),
},
RdTag::Sexpr => match tagged.inspect_sexpr(&path) {
Ok(view) => {
let mut effective = self.effective;
view.option_overrides().apply_to(&mut effective);
Ok(RdDynamicMarkupEvent::Sexpr(RdResolvedSexpr {
view,
effective,
}))
}
Err(error) => Err(error),
},
_ => {
self.push_children(tagged.children(), path);
continue;
}
};
self.push_children(tagged.children(), path);
return Some(result);
}
if let RdNode::Group(group) = node {
self.push_children(group.children(), path);
}
}
}
}
impl<'a> RdDynamicMarkupIter<'a> {
fn push_children(&mut self, nodes: &'a [RdNode], path: RdPath) {
self.frames.push(RdTraversalFrame {
nodes,
next: 0,
path,
top_level: false,
});
}
}
impl RdDocument {
pub fn inspect_dynamic_markup(&self) -> RdDynamicMarkupIter<'_> {
RdDynamicMarkupIter {
frames: vec![RdTraversalFrame {
nodes: self.nodes(),
next: 0,
path: RdPath::new(vec![]),
top_level: true,
}],
effective: RdEffectiveSexprOptions::default(),
}
}
}
impl RdTagged {
pub fn inspect_sexpr<'a>(&'a self, base_path: &RdPath) -> Result<RdSexpr<'a>, RdOptionError> {
if self.tag() != &RdTag::Sexpr {
return Err(shape(
base_path.clone(),
Some(self.tag().clone()),
RdShapeErrorKind::UnexpectedNode {
expected: RdExpectedNode::Sexpr,
actual: RdNodeKind::Tagged,
},
)
.into());
}
let children = self.children();
if children.len() != 1 {
return Err(shape(
base_path.clone(),
Some(RdTag::Sexpr),
RdShapeErrorKind::WrongArity {
expected: RdArity::Exactly(1),
actual: children.len(),
},
)
.into());
}
let code = match &children[0] {
RdNode::RCode(code) => code.as_str(),
node => {
return Err(shape(
base_path.with_child(0),
Some(RdTag::Sexpr),
RdShapeErrorKind::UnexpectedContent {
actual: RdNodeKind::of(node),
},
)
.into());
}
};
let options = self
.option()
.map(|nodes| RdOptionList::parse(nodes, base_path.with_option()))
.transpose()?;
Ok(RdSexpr {
path: base_path.clone(),
code,
options,
})
}
pub fn inspect_rd_opts<'a>(&'a self, base_path: &RdPath) -> Result<RdOpts<'a>, RdOptionError> {
if self.tag() != &RdTag::RdOpts {
return Err(shape(
base_path.clone(),
Some(self.tag().clone()),
RdShapeErrorKind::UnexpectedNode {
expected: RdExpectedNode::RdOpts,
actual: RdNodeKind::Tagged,
},
)
.into());
}
if self.option().is_some() {
return Err(shape(
base_path.clone(),
Some(RdTag::RdOpts),
RdShapeErrorKind::UnexpectedOption,
)
.into());
}
let options = RdOptionList::parse(self.children(), base_path.clone())?;
Ok(RdOpts {
path: base_path.clone(),
options,
})
}
}