how.rs/src/context.rs

108 lines
2.2 KiB
Rust

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<Context>),
}
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<C, F> 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<C, F> ToContext for F
where
C: IntoContext,
F: Fn() -> C,
{
#[inline(always)]
fn to_context(&self) -> Context {
self().into_context()
}
}