use std::{error, fmt, ops::Deref};
pub trait With<Input, Output = Self> {
fn with(self, input: Input) -> Output;
}
impl<T, W: Default + With<T>> With<T, W> for () {
fn with(self, input: T) -> W {
W::default().with(input)
}
}
pub trait WithIterator<Input> {
fn with_iter<I: IntoIterator<Item = Input>>(self, iter: I) -> Self;
}
impl<Input, W: With<Input>> WithIterator<Input> for W {
fn with_iter<I: IntoIterator<Item = Input>>(self, iter: I) -> Self {
iter.into_iter().fold(self, |w, i| w.with(i))
}
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct WithContext<O, C> {
pub object: O,
pub context: C,
}
impl<O, C> Deref for WithContext<O, C> {
type Target = O;
fn deref(&self) -> &Self::Target {
&self.object
}
}
impl<O: fmt::Display, C: fmt::Display> fmt::Display for WithContext<O, C> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} ({})", self.object, self.context)
}
}
pub trait WithoutContext: Sized {
fn with<C>(self, context: C) -> WithContext<Self, C> {
WithContext {
object: self,
context: context,
}
}
}
impl<'a, O> WithoutContext for &'a O {}
pub trait Ready<Output>: Sized {
type Error: error::Error;
fn build(self) -> Output {
self.try_build().unwrap()
}
fn try_build(self) -> Result<Output, Self::Error>;
}
#[cfg(test)]
mod tests {
use super::*;
impl WithoutContext for String {}
impl WithoutContext for WithContext<String, i64> {}
#[test]
fn test_with_context() {
let x = "Hello world".to_string();
let y: WithContext<String, i64> = x.with(5);
println!("x with context = {}", y);
println!("x = {}", *y);
println!("y with context = {}", y.with("Cool"));
}
}