use crate::*;
use std::fmt;
struct Errors<'a>(&'a [Error]);
impl<'a> fmt::Display for Errors<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for error in self.0 {
f.write_str("\n\nError: ")?;
fmt::Display::fmt(error, f)?;
}
Ok(())
}
}
impl<'a> fmt::Debug for Errors<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_list().entries(self.0).finish()
}
}
error_chain! {
errors {
ValidationFailed(field: String, msg: String) {
description("validation failed")
display("validation failed for field {} with message: {}", field, msg)
}
MultipleErrors(errors: Vec<Error>) {
description("validation failed")
display("multiple validators failed: {}", Errors(errors))
}
}
}
impl Error {
pub fn validation_failed<S1: Into<String>, S2: Into<String>>(field: S1, msg: S2) -> Self {
Self::from(ErrorKind::ValidationFailed(field.into(), msg.into()))
}
#[doc(hidden)]
pub fn append_to(self, errors: &mut Vec<Error>) {
match self.0 {
ErrorKind::MultipleErrors(e) => errors.extend(e),
_ => errors.push(self),
}
}
}
impl From<Vec<Error>> for Error {
fn from(mut inner: Vec<Error>) -> Self {
if inner.len() == 0 {
panic!("From<Vec<Error>> should not be called on empty vec's");
} else if inner.len() == 1 {
inner.remove(0)
} else {
ErrorKind::MultipleErrors(inner).into()
}
}
}
pub trait ValidationResult {
fn into_result(self) -> Result<()>;
}
impl ValidationResult for Result<()> {
fn into_result(self) -> Result<()> {
self
}
}
impl ValidationResult for () {
fn into_result(self) -> Result<()> {
Ok(())
}
}
impl<E: Into<Error>> ValidationResult for E {
fn into_result(self) -> Result<()> {
Err(self.into())
}
}
pub trait Options {
fn bind_config<C: Configuration>(&mut self, config: &C) -> Result<()>;
fn validate(&self) -> Result<()>;
fn bind<C: Configuration>(&mut self, config: &C) -> Result<()> {
self.bind_config(config)?;
self.validate()
}
}
pub trait ValidateOptions {
fn validate(&self) -> Result<()> {
Ok(())
}
}
pub trait FromConfig: Sized {
fn from_config<C: Configuration>(config: &C) -> Result<Self>;
}
pub trait ConfigProxy<T> {
fn bind_proxy<C: Configuration>(value: &mut T, config: &C) -> Result<()>;
}
impl<T> FromConfig for T
where
T: Options + Default + Sized,
{
fn from_config<C: Configuration>(config: &C) -> Result<Self> {
let mut ret = Self::default();
ret.bind(config)?;
Ok(ret)
}
}
impl<P, T> ConfigProxy<T> for P
where
P: Options + Into<T>,
T: Clone + Into<P>,
{
fn bind_proxy<C: Configuration>(value: &mut T, config: &C) -> Result<()> {
let mut proxy = value.clone().into();
Options::bind(&mut proxy, config)?;
std::mem::replace(value, proxy.into());
Ok(())
}
}
impl Options for String {
fn bind_config<C: Configuration>(&mut self, config: &C) -> Result<()> {
if let Some(val) = config.value() {
*self = val.to_owned();
}
Ok(())
}
fn validate(&self) -> Result<()> {
Ok(())
}
}