use std::str::FromStr;
use std::sync::Arc;
use super::Selection;
use crate::Data;
pub trait Formatter<T> {
fn format(&self, value: &T) -> String;
fn format_for_editing(&self, value: &T) -> String {
self.format(value)
}
fn validate_partial_input(&self, input: &str, sel: &Selection) -> Validation;
fn value(&self, input: &str) -> Result<T, ValidationError>;
}
pub struct Validation {
result: Result<(), ValidationError>,
pub selection_change: Option<Selection>,
pub text_change: Option<String>,
}
#[derive(Debug, Clone, Data)]
pub struct ValidationError {
inner: Arc<dyn std::error::Error>,
}
#[non_exhaustive]
pub struct ParseFormatter<T> {
fmt_fn: Box<dyn Fn(&T) -> String>,
}
impl Validation {
pub fn success() -> Self {
Validation {
result: Ok(()),
selection_change: None,
text_change: None,
}
}
pub fn failure(err: impl std::error::Error + 'static) -> Self {
Validation {
result: Err(ValidationError::new(err)),
..Validation::success()
}
}
pub fn change_text(mut self, text: String) -> Self {
self.text_change = Some(text);
self
}
pub fn change_selection(mut self, sel: Selection) -> Self {
self.selection_change = Some(sel);
self
}
pub fn is_err(&self) -> bool {
self.result.is_err()
}
pub fn error(&self) -> Option<&ValidationError> {
self.result.as_ref().err()
}
}
impl ValidationError {
pub fn new(e: impl std::error::Error + 'static) -> Self {
ValidationError { inner: Arc::new(e) }
}
}
impl<T: std::fmt::Display> ParseFormatter<T> {
pub fn new() -> Self {
ParseFormatter {
fmt_fn: Box::new(|val| val.to_string()),
}
}
}
impl<T> ParseFormatter<T> {
pub fn with_format_fn(f: impl Fn(&T) -> String + 'static) -> Self {
ParseFormatter {
fmt_fn: Box::new(f),
}
}
}
impl<T> Formatter<T> for ParseFormatter<T>
where
T: FromStr,
<T as FromStr>::Err: std::error::Error + 'static,
{
fn format(&self, value: &T) -> String {
(self.fmt_fn)(value)
}
fn validate_partial_input(&self, input: &str, _sel: &Selection) -> Validation {
match input.parse::<T>() {
Ok(_) => Validation::success(),
Err(e) => Validation::failure(e),
}
}
fn value(&self, input: &str) -> Result<T, ValidationError> {
input.parse().map_err(ValidationError::new)
}
}
impl std::fmt::Display for ValidationError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}", &self.inner)
}
}
impl std::error::Error for ValidationError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
Some(&*self.inner)
}
}
impl<T: std::fmt::Display> Default for ParseFormatter<T> {
fn default() -> Self {
ParseFormatter::new()
}
}