use crate::types::Error;
use std::{convert::TryFrom, fmt};
#[derive(Clone, Debug, PartialEq)]
pub enum Value {
Bool(bool),
Int(i32),
Flt(f64),
Str(String),
}
impl fmt::Display for Value {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Value::Bool(v) => write!(f, "{}", v),
Value::Int(v) => write!(f, "{}", v),
Value::Flt(v) => write!(f, "{}", v),
Value::Str(v) => write!(f, "\"{}\"", v),
}
}
}
impl TryFrom<Value> for bool {
type Error = Error;
fn try_from(value: Value) -> Result<Self, Self::Error> {
if let Value::Bool(v) = value {
Ok(v)
} else {
Err(Error::TypeError)
}
}
}
impl From<bool> for Value {
fn from(value: bool) -> Self {
Value::Bool(value)
}
}
impl TryFrom<Value> for i32 {
type Error = Error;
fn try_from(value: Value) -> Result<Self, Self::Error> {
if let Value::Int(v) = value {
return Ok(v);
}
Err(Error::TypeError)
}
}
impl From<i32> for Value {
fn from(value: i32) -> Self {
Value::Int(value)
}
}
impl TryFrom<Value> for i16 {
type Error = Error;
fn try_from(value: Value) -> Result<Self, Self::Error> {
if let Value::Int(v) = value {
if let Ok(v) = i16::try_from(v) {
return Ok(v);
}
}
Err(Error::TypeError)
}
}
impl From<i16> for Value {
fn from(value: i16) -> Self {
Value::Int(i32::from(value))
}
}
impl TryFrom<Value> for u16 {
type Error = Error;
fn try_from(value: Value) -> Result<Self, Self::Error> {
if let Value::Int(v) = value {
if let Ok(v) = u16::try_from(v) {
return Ok(v);
}
}
Err(Error::TypeError)
}
}
impl From<u16> for Value {
fn from(value: u16) -> Self {
Value::Int(i32::from(value))
}
}
impl TryFrom<Value> for f64 {
type Error = Error;
fn try_from(value: Value) -> Result<Self, Self::Error> {
if let Value::Flt(v) = value {
Ok(v)
} else {
Err(Error::TypeError)
}
}
}
impl From<f64> for Value {
fn from(value: f64) -> Self {
Value::Flt(value)
}
}
impl TryFrom<Value> for String {
type Error = Error;
fn try_from(value: Value) -> Result<Self, Self::Error> {
if let Value::Str(v) = value {
Ok(v)
} else {
Err(Error::TypeError)
}
}
}
impl From<String> for Value {
fn from(value: String) -> Self {
Value::Str(value)
}
}
impl From<&String> for Value {
fn from(value: &String) -> Self {
Value::Str(value.clone())
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::convert::TryFrom;
#[test]
fn test_device_values_from() {
assert_eq!(Value::Bool(true), Value::from(true));
assert_eq!(Value::Bool(false), Value::from(false));
assert_eq!(Value::Int(0), Value::from(0i32));
assert_eq!(Value::Int(-1), Value::from(-1i32));
assert_eq!(Value::Int(2), Value::from(2i32));
assert_eq!(Value::Int(-3), Value::from(-3i16));
assert_eq!(Value::Int(4), Value::from(4u16));
assert_eq!(Value::Flt(5.0), Value::from(5.0f64));
assert_eq!(
Value::Str(String::from("hello")),
Value::from(String::from("hello"))
);
}
#[test]
fn test_device_values_tryfrom() {
assert_eq!(bool::try_from(Value::Bool(true)), Ok(true));
assert!(bool::try_from(Value::Int(0)).is_err());
assert!(bool::try_from(Value::Flt(0.0)).is_err());
assert!(bool::try_from(Value::Str(String::from("hello"))).is_err());
assert!(i32::try_from(Value::Bool(true)).is_err());
assert_eq!(i32::try_from(Value::Int(0x7fffffffi32)), Ok(0x7fffffffi32));
assert_eq!(
i32::try_from(Value::Int(-0x80000000i32)),
Ok(-0x80000000i32)
);
assert!(i32::try_from(Value::Flt(0.0)).is_err());
assert!(i32::try_from(Value::Str(String::from("hello"))).is_err());
assert!(i16::try_from(Value::Bool(true)).is_err());
assert_eq!(i16::try_from(Value::Int(0x7fffi32)), Ok(0x7fffi16));
assert_eq!(i16::try_from(Value::Int(-0x8000i32)), Ok(-0x8000i16));
assert!(i16::try_from(Value::Int(0x8000i32)).is_err());
assert!(i16::try_from(Value::Int(-0x8000i32 - 1i32)).is_err());
assert!(i16::try_from(Value::Flt(0.0)).is_err());
assert!(i16::try_from(Value::Str(String::from("hello"))).is_err());
assert!(u16::try_from(Value::Bool(true)).is_err());
assert_eq!(u16::try_from(Value::Int(0xffffi32)), Ok(0xffffu16));
assert_eq!(u16::try_from(Value::Int(0i32)), Ok(0u16));
assert!(u16::try_from(Value::Int(0x10000i32)).is_err());
assert!(u16::try_from(Value::Int(-1i32)).is_err());
assert!(u16::try_from(Value::Flt(0.0)).is_err());
assert!(u16::try_from(Value::Str(String::from("hello"))).is_err());
}
}