use alloc::{borrow::Cow, vec::Vec};
#[derive(Clone, Default, Debug)]
pub struct Context {
path: Vec<Location>,
}
impl Context {
pub fn new() -> Context {
Default::default()
}
pub fn push(&mut self, loc: Location) {
self.path.push(loc);
}
pub fn path(&self) -> Path<'_> {
Path(Cow::Borrowed(&self.path))
}
}
pub struct Path<'a>(Cow<'a, [Location]>);
impl<'a> Path<'a> {
pub fn into_owned(self) -> Path<'static> {
Path(Cow::Owned(self.0.into_owned()))
}
pub fn locations(&self) -> impl Iterator<Item = &Location> {
self.0.iter()
}
}
impl<'a> core::fmt::Display for Path<'a> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
for (idx, loc) in self.0.iter().enumerate() {
if idx != 0 {
f.write_str(".")?;
}
match &loc.inner {
Loc::Field(name) => f.write_str(name)?,
Loc::Index(i) => write!(f, "[{i}]")?,
Loc::Variant(name) => write!(f, "({name})")?,
}
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Location {
inner: Loc,
}
#[derive(Debug, Clone, PartialEq, Eq)]
enum Loc {
Field(Cow<'static, str>),
Index(usize),
Variant(Cow<'static, str>),
}
impl Location {
pub fn field(name: impl Into<Cow<'static, str>>) -> Self {
Location {
inner: Loc::Field(name.into()),
}
}
pub fn variant(name: impl Into<Cow<'static, str>>) -> Self {
Location {
inner: Loc::Variant(name.into()),
}
}
pub fn idx(i: usize) -> Self {
Location {
inner: Loc::Index(i),
}
}
}