use std;
use toml::Value;
use data::Container;
use enums::ExtractResult;
use item_def::ItemDef;
use item_value::ItemValue;
use toml_def::TomlDef;
use value::U16Value;
pub struct ItemU16
{
name : String,
min : Option<i64>,
max : Option<i64>,
optional : bool,
default : Option<u16>
}
impl ItemU16
{
pub fn with_name<T:AsRef<str>>(name : T) -> ItemU16
{
ItemU16 {
name : String::from(name.as_ref()),
min : None,
max : None,
optional : false,
default : None
}
}
pub fn add_to(
self,
group : &mut TomlDef
) -> U16Value
{
let notify = U16Value::new();
group.add_notify(self.name.clone(), Box::new(notify.clone()));
group.ref_add(self);
notify
}
pub fn min(
mut self,
min : u16
) -> Self
{
if let Some(max) = self.max
{
if max < min as i64
{
panic!("Minimum value [{}] is greater than the maximum value [{}]", min, max);
}
}
self.min = Some(min as i64);
self
}
pub fn max(
mut self,
max : u16
) -> Self
{
if let Some(min) = self.min
{
if min > max as i64
{
panic!("Maximum value [{}] is less than the minimum value [{}]", max, min);
}
}
self.max = Some(max as i64);
self
}
pub fn optional(
mut self,
) -> Self
{
self.optional = true;
self
}
pub fn default(
mut self,
default : u16
) -> Self
{
self.default = Some(default);
self
}
}
impl ItemDef for ItemU16
{
fn name(&self) -> &str
{
&self.name
}
fn extract(
&self,
value : &Value
) -> ExtractResult
{
if let Some(value) = value.as_integer()
{
if let Some(min) = self.min
{
if value < min as i64
{
return ExtractResult::underrun(self.min.clone(), self.max.clone())
}
}
else if value < std::u16::MIN as i64
{
return ExtractResult::underrun(Some(0), self.max.clone())
}
if let Some(max) = self.max
{
if value > max as i64
{
return ExtractResult::overrun(self.min.clone(), self.max.clone())
}
}
else if value > std::u16::MAX as i64
{
return ExtractResult::overrun(self.min.clone(), Some(std::u16::MAX as i64))
}
ExtractResult::Item(ItemValue::U16(value as u16))
}
else
{
ExtractResult::incorrect_type("number")
}
}
fn is_optional(&self) -> bool
{
self.optional
}
fn default(&self) -> Option<ItemValue>
{
self.default.map(|x|ItemValue::U16(x))
}
}
#[cfg(test)]
mod tests
{
use std;
use toml::Value;
use item_def::ItemDef;
use item_value::ItemValue;
use enums::{ExtractResult, ValidationError};
macro_rules! test {
($item:expr, $val:expr) => ($item.extract(&Value::Integer($val)))
}
#[test]
fn set()
{
super::ItemU16::with_name("a").min(12);
super::ItemU16::with_name("b").max(67);
super::ItemU16::with_name("c").default(123);
}
#[test]
fn min()
{
let test = super::ItemU16::with_name("b").min(53);
assert_underrun!(test!(test, 17), 53);
assert_u16!(test!(test, 53), 53);
assert_u16!(test!(test, 67), 67);
}
#[test]
fn max()
{
let test = super::ItemU16::with_name("b").max(24);
assert_u16!(test!(test, 3), 3);
assert_u16!(test!(test, 24), 24);
assert_overflow!(test!(test, 67), 24);
}
#[test]
fn min_max()
{
let test = super::ItemU16::with_name("b").min(11).max(17);
assert_underrun!(test!(test, 0), 11, 17);
assert_u16!(test!(test, 11), 11);
assert_u16!(test!(test, 15), 15);
assert_u16!(test!(test, 17), 17);
assert_overflow!(test!(test, 27), 11, 17)
}
#[test]
fn validate()
{
let test = super::ItemU16::with_name("b");
assert_u16!(test.extract(&Value::Integer(std::u16::MIN as i64)), std::u16::MIN);
assert_u16!(test.extract(&Value::Integer(std::u16::MAX as i64)), std::u16::MAX);
assert_underrun!(test!(test, std::u16::MIN as i64 - 1), std::u16::MIN as i64);
assert_overflow!(test!(test, std::u16::MAX as i64 + 1), std::u16::MAX as i64);
}
}