use core::fmt;
#[derive(Debug, Clone)]
#[repr(transparent)]
pub struct Valid<T>(T);
impl<T> Valid<T>
where
T: Validate,
{
pub fn validate(value: T) -> Result<Self, ValidateError<T, <T as Validate>::Error>> {
if let Err(err) = value.is_valid() {
Err(ValidateError {
invalid_value: value,
error: err,
})
} else {
Ok(Self(value))
}
}
pub fn validate_ref(value: &T) -> Result<&Self, ValidateError<&T, <T as Validate>::Error>> {
if let Err(err) = value.is_valid() {
Err(ValidateError {
invalid_value: value,
error: err,
})
} else {
Ok(Self::from_ref_unchecked(value))
}
}
pub fn from_parts<Parts>(
parts: Parts,
) -> Result<Self, ValidateError<Parts, <T as Validate>::Error>>
where
T: ValidateFromParts<Parts>,
{
if let Err(err) = T::validate_parts(&parts) {
Err(ValidateError {
invalid_value: parts,
error: err,
})
} else {
Ok(Self(T::from_parts(parts)))
}
}
fn from_ref_unchecked(value: &T) -> &Self {
#[cfg(debug_assertions)]
#[allow(clippy::expect_used)]
value
.is_valid()
.expect("debug assertions: value is invalid, but was assumed to be valid");
unsafe { core::mem::transmute(value) }
}
}
impl<T> Valid<T> {
pub fn into_inner(self) -> T {
self.0
}
}
impl<T> AsRef<T> for Valid<T> {
fn as_ref(&self) -> &T {
&self.0
}
}
impl<T> core::ops::Deref for Valid<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T, K> AsRef<Valid<K>> for Valid<T>
where
T: Validate + AsRef<K>,
K: Validate,
{
fn as_ref(&self) -> &Valid<K> {
let sub_value = self.0.as_ref();
Valid::from_ref_unchecked(sub_value)
}
}
pub trait Validate {
type Error: fmt::Debug;
fn is_valid(&self) -> Result<(), Self::Error>;
fn validate(self) -> Result<Valid<Self>, ValidateError<Self, Self::Error>>
where
Self: Sized,
{
Valid::validate(self)
}
fn validate_ref(&self) -> Result<&Valid<Self>, Self::Error>
where
Self: Sized,
{
Valid::validate_ref(self).map_err(|err| err.into_error())
}
}
impl<T: Validate> Validate for &T {
type Error = <T as Validate>::Error;
fn is_valid(&self) -> Result<(), Self::Error> {
(*self).is_valid()
}
}
pub trait ValidateFromParts<Parts>: Validate {
fn validate_parts(parts: &Parts) -> Result<(), Self::Error>;
fn from_parts(parts: Parts) -> Self;
}
pub struct ValidateError<T, E> {
invalid_value: T,
error: E,
}
impl<T, E> ValidateError<T, E> {
pub fn invalid_value(&self) -> &T {
&self.invalid_value
}
pub fn error(&self) -> &E {
&self.error
}
pub fn into_invalid_value(self) -> T {
self.invalid_value
}
pub fn into_error(self) -> E {
self.error
}
}
impl<T, E: fmt::Debug> fmt::Debug for ValidateError<T, E> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ValidateError")
.field("error", &self.error)
.finish_non_exhaustive()
}
}
impl<T, E: fmt::Display> fmt::Display for ValidateError<T, E> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("validation error")
}
}
#[cfg(feature = "std")]
impl<T, E> std::error::Error for ValidateError<T, E>
where
E: std::error::Error + 'static,
{
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
Some(&self.error)
}
}
#[cfg(feature = "serde")]
impl<T> serde::Serialize for Valid<T>
where
T: serde::Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
(**self).serialize(serializer)
}
}
#[cfg(feature = "serde")]
impl<'de, T> serde::Deserialize<'de> for Valid<T>
where
T: Validate + serde::Deserialize<'de>,
<T as Validate>::Error: fmt::Display,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
use serde::de::Error;
let value = T::deserialize(deserializer)?;
value.validate().map_err(|err| {
D::Error::custom(format_args!(
"deserialized value is invalid: {}",
err.error()
))
})
}
}