use crate::binder::Binding;
use crate::environment::Environment;
use crate::error::{BindError, ValidationError, VariableName};
use super::raw::resolve_raw;
type U16Validator = dyn Fn(u16) -> Result<(), ValidationError> + Send + Sync + 'static;
pub struct U16Var {
name: VariableName,
default: Option<u16>,
allow_empty: bool,
sensitive: bool,
validators: Vec<Box<U16Validator>>,
}
impl U16Var {
#[must_use]
pub fn new(name: impl Into<VariableName>) -> Self {
Self {
name: name.into(),
default: None,
allow_empty: false,
sensitive: true,
validators: Vec::new(),
}
}
#[must_use]
pub fn default(mut self, value: u16) -> Self {
self.default = Some(value);
self
}
#[must_use]
pub fn allow_empty(mut self) -> Self {
self.allow_empty = true;
self
}
#[must_use]
pub fn sensitive(mut self, value: bool) -> Self {
self.sensitive = value;
self
}
#[must_use]
pub fn validate<F>(mut self, validator: F) -> Self
where
F: Fn(u16) -> Result<(), ValidationError> + Send + Sync + 'static,
{
self.validators.push(Box::new(validator));
self
}
}
impl Binding<u16> for U16Var {
fn bind<E: Environment>(&self, environment: &E) -> Result<u16, BindError> {
let name = self.name.as_ref();
let resolved = resolve_raw(environment, name, self.default.is_some(), self.allow_empty)?;
let (value, used_default) = match resolved {
Some(text) => (parse_u16(name, &text)?, false),
None => (
self.default
.ok_or_else(|| BindError::missing(name.to_owned()))?,
true,
),
};
if used_default {
return Ok(value);
}
validate_u16(
name,
value,
self.sensitive,
self.validators.iter().map(Box::as_ref),
)?;
Ok(value)
}
}
fn parse_u16(name: &str, raw: &str) -> Result<u16, BindError> {
raw.parse::<u16>()
.map_err(|_| BindError::parse(name.to_owned(), "u16"))
}
fn validate_u16<'a, I>(
name: &str,
value: u16,
sensitive: bool,
validators: I,
) -> Result<(), BindError>
where
I: IntoIterator<Item = &'a U16Validator>,
{
for validator in validators {
validator(value).map_err(|error| {
BindError::validation_with_sensitivity(name.to_owned(), error, sensitive)
})?;
}
Ok(())
}