pub use brane_shr::input::NoValidator;
use dialoguer::InputValidator;
#[derive(Default)]
pub struct NotEmptyValidator;
impl InputValidator<String> for NotEmptyValidator {
type Err = String;
fn validate(&mut self, input: &String) -> Result<(), Self::Err> {
if input.is_empty() { Err(String::from("Value may not be empty")) } else { Ok(()) }
}
}
#[derive(Default)]
pub struct PortValidator;
impl InputValidator<String> for PortValidator {
type Err = String;
fn validate(&mut self, input: &String) -> Result<(), Self::Err> {
match input.parse::<u16>() {
Ok(_) => Ok(()),
Err(err) => Err(format!("Entered port is not valid: {err}")),
}
}
}
pub struct RangeValidator<V>
where
V: InputValidator<String>,
{
pub separator: String,
pub segment_validator: V,
pub allow_empty: bool,
}
impl<V> Default for RangeValidator<V>
where
V: Default,
V: dialoguer::InputValidator<String>,
{
fn default() -> Self { Self { separator: String::from("-"), segment_validator: Default::default(), allow_empty: false } }
}
impl<V> InputValidator<String> for RangeValidator<V>
where
V: InputValidator<String>,
V::Err: ToString,
{
type Err = String;
fn validate(&mut self, input: &String) -> Result<(), Self::Err> {
if self.allow_empty && input.trim().is_empty() {
return Ok(());
}
let Some((start, end)) = input.split_once(&self.separator) else {
return Err(format!("No range separator {} found", self.separator));
};
self.segment_validator.validate(&String::from(start.trim())).map_err(|err| err.to_string())?;
self.segment_validator.validate(&String::from(end.trim())).map_err(|err| err.to_string())?;
Ok(())
}
}
pub struct MapValidator<V1, V2>
where
V1: InputValidator<String>,
V2: InputValidator<String>,
{
pub separator: String,
pub left_validator: V1,
pub right_validator: V2,
pub allow_empty: bool,
}
impl<V1, V2> Default for MapValidator<V1, V2>
where
V1: Default,
V1: dialoguer::InputValidator<String>,
V2: Default,
V2: dialoguer::InputValidator<String>,
{
fn default() -> Self {
Self { separator: String::from(":"), left_validator: Default::default(), right_validator: Default::default(), allow_empty: false }
}
}
impl<V1, V2> InputValidator<String> for MapValidator<V1, V2>
where
V1: InputValidator<String>,
V1::Err: ToString,
V2: InputValidator<String>,
V2::Err: ToString,
{
type Err = String;
fn validate(&mut self, input: &String) -> Result<(), Self::Err> {
if self.allow_empty && input.is_empty() {
return Ok(());
}
let Some((left, right)) = input.split_once(&self.separator) else {
return Err(format!("No separator {} found", self.separator));
};
self.left_validator.validate(&String::from(left.trim())).map_err(|err| err.to_string())?;
self.right_validator.validate(&String::from(right.trim())).map_err(|err| err.to_string())?;
Ok(())
}
}
pub struct FromStrValidator<T>
where
T: std::str::FromStr,
{
pub field_name: &'static str,
_fd: std::marker::PhantomData<T>,
}
impl<T> Default for FromStrValidator<T>
where
T: std::str::FromStr,
{
fn default() -> Self {
let field_name_raw = std::any::type_name::<T>();
let field_name = match field_name_raw.rsplit_once("::") {
Some((_, segment)) => segment,
None => field_name_raw,
};
Self { _fd: std::marker::PhantomData, field_name }
}
}
impl<T> InputValidator<String> for FromStrValidator<T>
where
T: std::str::FromStr,
<T as std::str::FromStr>::Err: std::fmt::Display,
{
type Err = String;
fn validate(&mut self, input: &String) -> Result<(), Self::Err> {
match T::from_str(input) {
Ok(_) => Ok(()),
Err(err) => Err(format!("Input is not a legal {}: {err}", self.field_name)),
}
}
}