use std::rc::Rc;
use std::time::Instant;
use teksilo_i18n::LocalizedString;
#[derive(Debug, Clone)]
pub enum ValidationOutcome {
Valid,
Corrected {
corrected: String,
message: LocalizedString,
},
Invalid { message: LocalizedString },
}
#[derive(Debug, Clone, Default)]
pub enum ValidationFeedback {
#[default]
Pristine,
Valid,
Corrected {
message: LocalizedString,
since: Instant,
},
Invalid { message: LocalizedString },
}
impl PartialEq for ValidationOutcome {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::Valid, Self::Valid) => true,
(
Self::Corrected {
corrected: c1,
message: m1,
},
Self::Corrected {
corrected: c2,
message: m2,
},
) => c1 == c2 && m1.resolve_now() == m2.resolve_now(),
(Self::Invalid { message: m1 }, Self::Invalid { message: m2 }) => {
m1.resolve_now() == m2.resolve_now()
}
_ => false,
}
}
}
impl PartialEq for ValidationFeedback {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::Pristine, Self::Pristine) | (Self::Valid, Self::Valid) => true,
(
Self::Corrected {
message: m1,
since: s1,
},
Self::Corrected {
message: m2,
since: s2,
},
) => s1 == s2 && m1.resolve_now() == m2.resolve_now(),
(Self::Invalid { message: m1 }, Self::Invalid { message: m2 }) => {
m1.resolve_now() == m2.resolve_now()
}
_ => false,
}
}
}
impl ValidationFeedback {
pub fn is_invalid(&self) -> bool {
matches!(self, Self::Invalid { .. })
}
pub fn is_corrected(&self) -> bool {
matches!(self, Self::Corrected { .. })
}
pub fn message(&self) -> Option<String> {
match self {
Self::Corrected { message, .. } | Self::Invalid { message } => {
Some(message.resolve_now())
}
_ => None,
}
}
}
pub type ValidatorFn = Rc<dyn Fn(&str) -> ValidationOutcome>;
#[cfg(test)]
mod tests {
use super::*;
use teksilo_i18n::lit;
#[test]
fn feedback_is_invalid_helper() {
assert!(!ValidationFeedback::Pristine.is_invalid());
assert!(!ValidationFeedback::Valid.is_invalid());
assert!(
!ValidationFeedback::Corrected {
message: lit!("x"),
since: Instant::now(),
}
.is_invalid()
);
assert!(ValidationFeedback::Invalid { message: lit!("x") }.is_invalid());
}
#[test]
fn feedback_message_accessor() {
assert_eq!(ValidationFeedback::Pristine.message(), None);
assert_eq!(ValidationFeedback::Valid.message(), None);
assert_eq!(
ValidationFeedback::Invalid {
message: lit!("bad")
}
.message(),
Some("bad".to_string())
);
assert_eq!(
ValidationFeedback::Corrected {
message: lit!("fixed"),
since: Instant::now(),
}
.message(),
Some("fixed".to_string())
);
}
}