1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
//! Module with constraint configs to apply to inputs
//!
//! This module provides various constraints that can be applied to user inputs,
//! including constraints for strings and numbers. These constraints help ensure that
//! input data meets specific criteria before it is accepted.
//!
//! # Example
//!
//! ```
//! use constrained_inputs::constraints::{StringConstraint, NumberConstraint, Constraint};
//!
//! fn main() {
//! let string_constraint = StringConstraint {
//! max_len: Some(10),
//! min_len: Some(5),
//! blacklist_chars: vec!['a', 'e', 'i', 'o', 'u'],
//! };
//!
//! let result = string_constraint.validate(&"hello");
//! assert_eq!(result, ConstraintResult::Err(ConstraintError::BlacklistedChar));
//!
//! let number_constraint = NumberConstraint {
//! max: Some(100),
//! min: Some(10),
//! };
//!
//! let result = number_constraint.validate(&50);
//! assert_eq!(result, ConstraintResult::Valid);
//! }
//! ```
/// Result type for constraints
#[derive(Debug, PartialEq)]
pub enum ConstraintResult {
Valid,
Err(ConstraintError),
}
/// Error types for constraints
#[derive(Debug, PartialEq)]
pub enum ConstraintError {
InvalidConstraint,
TooLarge,
TooSmall,
BlacklistedChar,
TooLong,
TooShort,
}
/// Constraint trait
pub trait Constraint<T> {
/// Validates data to make sure it follows constraints
fn validate(&self, data: &T) -> ConstraintResult;
}
/// String constraint config for applying constraints to what a string can be
pub struct StringConstraint {
pub max_len: Option<usize>,
pub min_len: Option<usize>,
pub blacklist_chars: Vec<char>,
}
/// Implementing method to apply constraints on strings
impl<T> Constraint<T> for StringConstraint
where
T: AsRef<str>,
{
fn validate(&self, data: &T) -> ConstraintResult {
let data = data.as_ref();
if let Some(max_len) = self.max_len {
if data.len() > max_len {
return ConstraintResult::Err(ConstraintError::TooLong);
}
}
if let Some(min_len) = self.min_len {
if data.len() < min_len {
return ConstraintResult::Err(ConstraintError::TooShort);
}
}
for ch in data.chars() {
if self.blacklist_chars.contains(&ch) {
return ConstraintResult::Err(ConstraintError::BlacklistedChar);
}
}
ConstraintResult::Valid
}
}
/// Number constraint config for applying constraints onto some number
pub struct NumberConstraint {
pub max: Option<i32>,
pub min: Option<i32>,
}
/// Implementing method to apply constraints on numbers
impl<T> Constraint<T> for NumberConstraint
where
T: Into<i32> + Clone + PartialOrd,
{
fn validate(&self, data: &T) -> ConstraintResult {
let res = i32::try_from(data.clone()).map_err(|_| ConstraintError::InvalidConstraint);
if let Err(err) = res {
return ConstraintResult::Err(err);
}
let data = res.unwrap();
if let Some(max) = self.max {
if data > max {
return ConstraintResult::Err(ConstraintError::TooLarge);
}
}
if let Some(min) = self.min {
if data < min {
return ConstraintResult::Err(ConstraintError::TooSmall);
}
}
ConstraintResult::Valid
}
}