use super::{Predicate, Refined};
pub type ValidationEffect<T, P, Env> = crate::effect::combinators::FromFn<
Box<dyn FnOnce(&Env) -> Result<Refined<T, P>, <P as Predicate<T>>::Error> + Send>,
Env,
>;
impl<T, P> Refined<T, P>
where
T: Send + 'static,
P: Predicate<T>,
P::Error: Send + 'static,
{
pub fn validate_effect<Env>(value: T) -> ValidationEffect<T, P, Env>
where
Env: Clone + Send + Sync,
{
crate::from_fn(Box::new(move |_env: &Env| Self::new(value))
as Box<dyn FnOnce(&Env) -> Result<Self, P::Error> + Send>)
}
}
pub fn refine<T, P, Env>(value: T) -> ValidationEffect<T, P, Env>
where
T: Send + 'static,
P: Predicate<T>,
P::Error: Send + 'static,
Env: Clone + Send + Sync,
{
crate::from_fn(Box::new(move |_env: &Env| Refined::new(value))
as Box<dyn FnOnce(&Env) -> Result<Refined<T, P>, P::Error> + Send>)
}
pub fn pure_refined<T, P, E, Env>(
refined: Refined<T, P>,
) -> crate::effect::combinators::Pure<Refined<T, P>, E, Env>
where
T: Send + 'static,
P: Predicate<T>,
E: Send + 'static,
Env: Clone + Send + Sync,
{
crate::pure(refined)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::effect::prelude::*;
use crate::refined::predicates::numeric::Positive;
use crate::refined::predicates::string::NonEmpty;
type PositiveI32 = Refined<i32, Positive>;
#[tokio::test]
async fn test_validate_effect_success() {
let effect = PositiveI32::validate_effect::<()>(42);
let result = effect.run(&()).await;
assert!(result.is_ok());
assert_eq!(*result.unwrap().get(), 42);
}
#[tokio::test]
async fn test_validate_effect_failure() {
let effect = PositiveI32::validate_effect::<()>(-5);
let result = effect.run(&()).await;
assert!(result.is_err());
}
#[tokio::test]
async fn test_refine_success() {
let effect = refine::<_, NonEmpty, ()>("hello".to_string());
let result = effect.run(&()).await;
assert!(result.is_ok());
}
#[tokio::test]
async fn test_refine_failure() {
let effect = refine::<_, NonEmpty, ()>("".to_string());
let result = effect.run(&()).await;
assert!(result.is_err());
}
#[tokio::test]
async fn test_pure_refined() {
let n = PositiveI32::new(42).unwrap();
let effect = pure_refined::<_, _, String, ()>(n);
let result = effect.run(&()).await;
assert!(result.is_ok());
assert_eq!(*result.unwrap().get(), 42);
}
#[tokio::test]
async fn test_effect_chain() {
let effect = pure::<_, &str, ()>("hello".to_string())
.and_then(|s| refine::<_, NonEmpty, ()>(s))
.map(|refined| refined.get().len());
let result = effect.run(&()).await;
assert_eq!(result, Ok(5));
}
#[tokio::test]
async fn test_effect_chain_failure() {
let effect = pure::<_, &str, ()>("".to_string())
.and_then(|s| refine::<_, NonEmpty, ()>(s))
.map(|refined| refined.get().len());
let result = effect.run(&()).await;
assert!(result.is_err());
}
}