use std::fmt::Debug; use crate::util::form::field_error::FieldError; /** A sum type that contains a value and possibly an error. Used for form validation. This isn't exactly like a sum type like Result as even in the error case, we want to keep the value intact. It can't be just an either/or situation. For instance, when doing form validation, in most cases, we would want to preserve the value sent to us through the form, but inform the user of why it was rejected through an error message. */ pub struct FieldValue { pub value: Value, pub error: Option, } pub type StringField = FieldValue; pub type BoolField = FieldValue; pub type FloatField = FieldValue; impl FieldValue where Value: Default { pub fn new(value: Value) -> Self { Self { value, error: None } } pub fn set_error(&mut self, error: Error) { self.error = Some(error); } pub fn is_error(&self) -> bool { self.error.is_some() } pub fn invalid_if(mut self, is_invalid: I, err: Error ) -> Self where I: FnOnce(&Value) -> bool { if is_invalid(&self.value) { self.set_error(err); } self } pub fn invalid_if_then(mut self, is_invalid: I, err_if: E ) -> Self where I: FnOnce(&Value) -> bool, E: FnOnce() -> Error { if is_invalid(&self.value) { self.set_error(err_if()); } self } pub fn clear_value(mut self) -> Self { self.value = Default::default(); self } pub fn clear_value_if_error(mut self) -> Self { if self.is_error() { self.clear_value() } else { self } } pub fn map(self, f: F) -> FieldValue where F: FnOnce(Value) -> V { FieldValue:: { value: f(self.value), error: self.error, } } } impl Default for FieldValue where Value: Default, { fn default() -> Self { Self::new(Value::default()) } } impl Debug for FieldValue where Value: Debug, Error: Debug { fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { fmt.debug_struct("FieldValue") .field("value", &self.value) .field("error", &self.error) .finish() } }