use std::borrow::Cow; use crate::{Report, ReportFmt}; #[derive(Debug, Clone)] pub struct Context(ContextInner); impl Context { pub fn chain(mut self, other: impl IntoContext) -> Self { if let ContextInner::Compound(ref mut vec) = self.0 { vec.push(other.into_context()); } else { self = Context(ContextInner::Compound(vec![self, other.into_context()])) } self } } impl Report for Context { fn fmt(&self, f: &mut std::fmt::Formatter<'_>, opts: &ReportFmt) -> std::fmt::Result { use std::fmt::Write; match self.0 { ContextInner::String(ref s) => s.fmt(f, opts)?, ContextInner::Compound(ref ctxs) => { let mut opts = *opts; for ctx in ctxs { ctx.fmt(f, &opts)?; f.write_char('\n')?; opts = opts.next(); } } } Ok(()) } } #[derive(Debug, Clone)] enum ContextInner { String(Cow<'static, str>), Compound(Vec), } pub trait IntoContext { fn into_context(self) -> Context; #[inline] fn chain(self, other: impl IntoContext) -> Context where Self: Sized, { self.into_context().chain(other) } } impl IntoContext for Context { #[inline(always)] fn into_context(self) -> Context { self } } impl IntoContext for String { #[inline] fn into_context(self) -> Context { Context(ContextInner::String(self.into())) } } impl IntoContext for &'static str { #[inline] fn into_context(self) -> Context { Context(ContextInner::String(self.into())) } } impl IntoContext for Cow<'static, str> { #[inline] fn into_context(self) -> Context { Context(ContextInner::String(self)) } } impl IntoContext for F where C: IntoContext, F: FnOnce() -> C, { #[inline(always)] fn into_context(self) -> Context { self().into_context() } } pub trait ToContext { fn to_context(&self) -> Context; } impl ToContext for F where C: IntoContext, F: Fn() -> C, { #[inline(always)] fn to_context(&self) -> Context { self().into_context() } }