#![doc = include_str!("../README.md")]
#![cfg_attr(not(any(test, feature = "std")), no_std)]
#![warn(
clippy::pedantic,
clippy::print_stdout,
clippy::print_stderr,
clippy::panic
)]
#![allow(
clippy::new_without_default,
clippy::wildcard_imports,
clippy::enum_glob_use
)]
#![cfg_attr(test, allow(non_upper_case_globals))]
pub mod error;
pub mod options;
#[doc(hidden)]
#[cfg(all(not(feature = "std"), feature = "alloc"))]
pub extern crate alloc;
#[cfg(feature = "alloc")]
use alloc::{string::String, vec::Vec};
use core::{future::Future, prelude::rust_2021::*};
#[doc(hidden)]
#[cfg(feature = "std")]
pub use std as alloc;
use error::Path;
pub use error::{Error, Report};
pub use options::rule::{length::Length, range::Compare};
#[cfg(feature = "derive")]
pub use wary_derive::*;
#[doc(hidden)]
pub mod internal {
#[cfg(all(feature = "regex", feature = "std"))]
#[macro_export]
macro_rules! init_regex {
(static $id:ident = $s:expr) => {
#[allow(non_upper_case_globals)]
static $id: $crate::alloc::sync::LazyLock<$crate::options::rule::regex::Regex> =
$crate::alloc::sync::LazyLock::new(|| {
$crate::options::rule::regex::Regex::new($s).unwrap()
});
};
}
#[cfg(all(feature = "regex", not(feature = "std")))]
#[macro_export]
macro_rules! init_regex {
(static $id:ident = $s:expr) => {
#[allow(non_upper_case_globals)]
static $id: once_cell::sync::Lazy<$crate::options::rule::regex::Regex> =
once_cell::sync::Lazy::new(|| $crate::options::rule::regex::Regex::new($s).unwrap());
};
}
#[cfg(feature = "regex")]
pub use init_regex;
}
pub mod toolbox {
#[allow(unused_imports)]
pub mod rule {
pub use core::{marker::PhantomData, prelude::rust_2021::*};
#[cfg(feature = "alloc")]
pub(crate) use crate::alloc::{
borrow::Cow,
boxed::Box,
format,
string::{String, ToString},
vec,
vec::Vec,
};
pub use crate::{options::Unset, AsMut, AsRef, AsSlice, Error, Report};
#[allow(missing_docs)]
pub type Result<T> = core::result::Result<T, Error>;
}
#[allow(unused_imports)]
pub mod test {
pub use crate::{
toolbox::rule::*, AsyncRule, AsyncTransform, AsyncTransformer, AsyncValidate, Rule,
Transform, Transformer, Validate, Wary,
};
}
}
pub trait Wary<C>: Validate<Context = C> + Transform<Context = C> {
fn wary(&mut self, ctx: &C) -> Result<(), Report> {
self.validate(ctx)?;
self.transform(ctx);
Ok(())
}
}
impl<T, C> Wary<C> for T where T: Validate<Context = C> + Transform<Context = C> {}
pub trait AsyncWary<C>: AsyncValidate<Context = C> + AsyncTransform<Context = C> {
fn wary_async(&mut self, ctx: &C) -> impl Future<Output = Result<(), Report>> + Send;
}
impl<T, C> AsyncWary<C> for T
where
T: AsyncValidate<Context = C> + AsyncTransform<Context = C> + Send + Sync,
C: Sync,
{
async fn wary_async(&mut self, ctx: &C) -> Result<(), Report> {
let mut report = Report::default();
self
.validate_into_async(ctx, &Path::default(), &mut report)
.await;
if report.is_empty() {
self.transform_async(ctx).await;
Ok(())
} else {
Err(report)
}
}
}
pub trait Transformer<I: ?Sized> {
type Context;
fn transform(&self, ctx: &Self::Context, item: &mut I);
}
pub trait AsyncTransformer<I: ?Sized> {
type Context: Send;
fn transform_async(&self, ctx: &Self::Context, item: &mut I) -> impl Future<Output = ()> + Send;
}
pub trait Transform {
type Context;
fn transform(&mut self, ctx: &Self::Context);
}
pub trait AsyncTransform {
type Context: Send;
fn transform_async(&mut self, ctx: &Self::Context) -> impl Future<Output = ()> + Send;
}
pub trait Rule<I: ?Sized> {
type Context;
fn validate(&self, ctx: &Self::Context, item: &I) -> Result<(), Error>;
}
pub trait AsyncRule<I: ?Sized> {
type Context: Send;
fn validate_async(
&self,
ctx: &Self::Context,
item: &I,
) -> impl Future<Output = Result<(), Error>> + Send;
}
pub trait Validate {
type Context;
fn validate_into(&self, ctx: &Self::Context, parent: &Path, report: &mut Report);
fn validate(&self, ctx: &Self::Context) -> Result<(), Report> {
let mut report = Report::default();
self.validate_into(ctx, &Path::default(), &mut report);
if report.is_empty() {
Ok(())
} else {
Err(report)
}
}
}
pub trait AsyncValidate {
type Context: Send;
fn validate_into_async(
&self,
ctx: &Self::Context,
parent: &Path,
report: &mut Report,
) -> impl Future<Output = ()> + Send;
fn validate_async(&self, ctx: &Self::Context) -> impl Future<Output = Result<(), Report>> + Send
where
Self: Sync,
Self::Context: Sync,
{
let mut report = Report::default();
async move {
self
.validate_into_async(ctx, &Path::default(), &mut report)
.await;
if report.is_empty() {
Ok(())
} else {
Err(report)
}
}
}
}
impl<T> Validate for Option<T>
where
T: Validate,
{
type Context = T::Context;
#[inline]
fn validate_into(&self, ctx: &Self::Context, parent: &Path, report: &mut Report) {
if let Some(inner) = self {
inner.validate_into(ctx, parent, report);
}
}
}
impl<T: ?Sized> Validate for &T
where
T: Validate,
{
type Context = T::Context;
#[inline]
fn validate_into(&self, ctx: &Self::Context, parent: &Path, report: &mut Report) {
(*self).validate_into(ctx, parent, report);
}
}
pub trait AsRef<T: ?Sized> {
fn as_ref(&self) -> &T;
}
impl<To: ?Sized, From: core::convert::AsRef<To> + ?Sized> AsRef<To> for From {
#[inline]
fn as_ref(&self) -> &To {
self.as_ref()
}
}
pub trait AsMut<T: ?Sized> {
fn as_mut(&mut self) -> &mut T;
}
impl<To: ?Sized, From: core::convert::AsMut<To> + ?Sized> AsMut<To> for From {
#[inline]
fn as_mut(&mut self) -> &mut To {
self.as_mut()
}
}
pub trait AsSlice {
type Item;
fn as_slice(&self) -> &[Self::Item];
}
impl<T: ?Sized> AsSlice for &T
where
T: AsSlice,
{
type Item = T::Item;
#[inline]
fn as_slice(&self) -> &[Self::Item] {
(**self).as_slice()
}
}
impl<T> AsSlice for &mut T
where
T: AsSlice + ?Sized,
{
type Item = T::Item;
#[inline]
fn as_slice(&self) -> &[Self::Item] {
(**self).as_slice()
}
}
impl<T> AsSlice for Option<T> {
type Item = T;
#[inline]
fn as_slice(&self) -> &[Self::Item] {
self.as_slice()
}
}
#[cfg(feature = "alloc")]
impl<T> AsSlice for Vec<T> {
type Item = T;
#[inline]
fn as_slice(&self) -> &[Self::Item] {
self
}
}
impl<T> AsSlice for [T] {
type Item = T;
#[inline]
fn as_slice(&self) -> &[Self::Item] {
self
}
}
impl<const N: usize, T> AsSlice for [T; N] {
type Item = T;
#[inline]
fn as_slice(&self) -> &[Self::Item] {
self
}
}
impl AsSlice for str {
type Item = u8;
#[inline]
fn as_slice(&self) -> &[Self::Item] {
self.as_bytes()
}
}
#[cfg(feature = "alloc")]
impl AsSlice for String {
type Item = u8;
#[inline]
fn as_slice(&self) -> &[Self::Item] {
self.as_bytes()
}
}
pub trait AsMutSlice: AsSlice {
fn as_mut_slice(&mut self) -> &mut [Self::Item];
}
impl<T> AsMutSlice for &mut T
where
T: AsMutSlice,
{
#[inline]
fn as_mut_slice(&mut self) -> &mut [Self::Item] {
(**self).as_mut_slice()
}
}
impl<T> AsMutSlice for Option<T> {
#[inline]
fn as_mut_slice(&mut self) -> &mut [Self::Item] {
self.as_mut_slice()
}
}
#[cfg(feature = "alloc")]
impl<T> AsMutSlice for Vec<T> {
#[inline]
fn as_mut_slice(&mut self) -> &mut [Self::Item] {
self
}
}
impl<T> AsMutSlice for [T] {
#[inline]
fn as_mut_slice(&mut self) -> &mut [Self::Item] {
self
}
}
impl<const N: usize, T> AsMutSlice for [T; N] {
#[inline]
fn as_mut_slice(&mut self) -> &mut [Self::Item] {
self
}
}