use crate::sanitize::SanitizeWriteContext;
pub trait VisitorContext {
fn add_issue(&mut self, issue: Issue);
fn add_issue_at(&mut self, seg: PathSegment, issue: Issue);
fn sanitize_write_context(&self) -> Option<SanitizeWriteContext> {
None
}
}
impl dyn VisitorContext + '_ {
pub fn issue(&mut self, msg: impl Into<String>) {
self.add_issue(Issue::new(msg));
}
pub fn issue_at(&mut self, seg: PathSegment, msg: impl Into<String>) {
self.add_issue_at(seg, Issue::new(msg));
}
}
pub struct ScopedContext<'a> {
ctx: &'a mut dyn VisitorContext,
seg: PathSegment,
}
impl<'a> ScopedContext<'a> {
#[must_use]
pub fn new(ctx: &'a mut dyn VisitorContext, seg: PathSegment) -> Self {
Self { ctx, seg }
}
}
impl VisitorContext for ScopedContext<'_> {
fn add_issue(&mut self, issue: Issue) {
self.ctx.add_issue_at(self.seg.clone(), issue);
}
fn add_issue_at(&mut self, _seg: PathSegment, issue: Issue) {
self.ctx.add_issue_at(self.seg.clone(), issue);
}
fn sanitize_write_context(&self) -> Option<SanitizeWriteContext> {
self.ctx.sanitize_write_context()
}
}
#[derive(Clone, Debug, Default)]
pub struct Issue {
message: String,
}
impl Issue {
#[must_use]
pub fn new(message: impl Into<String>) -> Self {
Self {
message: message.into(),
}
}
#[must_use]
pub fn message(&self) -> &str {
&self.message
}
#[must_use]
pub fn into_message(self) -> String {
self.message
}
}
#[derive(Clone, Debug)]
pub enum PathSegment {
Empty,
Field(&'static str),
Index(usize),
}
impl From<&'static str> for PathSegment {
fn from(s: &'static str) -> Self {
Self::Field(s)
}
}
impl From<usize> for PathSegment {
fn from(i: usize) -> Self {
Self::Index(i)
}
}
impl From<Option<&'static str>> for PathSegment {
fn from(opt: Option<&'static str>) -> Self {
match opt {
Some(s) if !s.is_empty() => Self::Field(s),
_ => Self::Empty,
}
}
}