use crate::Spanned;
use super::{AnnotationRef, Annotations};
pub trait FromAnnotation: Sized {
type Error: std::error::Error;
fn resolve(annotation: AnnotationRef<'_>) -> Result<Self, Spanned<Self::Error>>;
}
impl Annotations {
#[must_use]
pub fn resolve<T: FromAnnotation>(&self, text: &str) -> Resolved<T, T::Error> {
self.resolve_with(text, T::resolve)
}
#[must_use]
pub fn resolve_with<T, E, F>(&self, text: &str, mut resolver: F) -> Resolved<T, E>
where
F: FnMut(AnnotationRef<'_>) -> Result<T, Spanned<E>>,
{
let mut resolved = Resolved {
annotations: Annotations::default(),
errors: Vec::new(),
};
for attached in self {
match resolver(attached.annotation().with_source(text)) {
Ok(value) => resolved.annotations.attach(value, attached.target()),
Err(error) => resolved.errors.push(error),
}
}
resolved
}
}
#[derive(Debug, Clone)]
pub struct Resolved<T, E> {
annotations: Annotations<T>,
errors: Vec<Spanned<E>>,
}
impl<T, E> Resolved<T, E> {
#[must_use]
pub fn annotations(&self) -> &Annotations<T> {
&self.annotations
}
#[must_use]
pub fn errors(&self) -> &[Spanned<E>] {
&self.errors
}
#[must_use]
pub fn into_parts(self) -> (Annotations<T>, Vec<Spanned<E>>) {
(self.annotations, self.errors)
}
}