use std::collections::HashMap;
use super::dynamic::DynamicMessage;
#[derive(Clone, Debug, PartialEq)]
pub enum Value {
F64(f64),
F32(f32),
I32(i32),
I64(i64),
U32(u32),
U64(u64),
Bool(bool),
String(String),
Bytes(Vec<u8>),
EnumNumber(i32),
Message(Box<DynamicMessage>),
List(Vec<Value>),
Map(HashMap<MapKey, Value>),
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum MapKey {
String(String),
I32(i32),
I64(i64),
U32(u32),
U64(u64),
Bool(bool),
}
impl Value {
pub fn is_default(&self) -> bool {
match self {
Value::F64(v) => *v == 0.0,
Value::F32(v) => *v == 0.0,
Value::I32(v) => *v == 0,
Value::I64(v) => *v == 0,
Value::U32(v) => *v == 0,
Value::U64(v) => *v == 0,
Value::Bool(v) => !*v,
Value::String(s) => s.is_empty(),
Value::Bytes(b) => b.is_empty(),
Value::EnumNumber(n) => *n == 0,
Value::Message(_) => false,
Value::List(l) => l.is_empty(),
Value::Map(m) => m.is_empty(),
}
}
pub fn as_f64(&self) -> Option<f64> {
match self {
Value::F64(v) => Some(*v),
_ => None,
}
}
pub fn as_f32(&self) -> Option<f32> {
match self {
Value::F32(v) => Some(*v),
_ => None,
}
}
pub fn as_i32(&self) -> Option<i32> {
match self {
Value::I32(v) => Some(*v),
_ => None,
}
}
pub fn as_i64(&self) -> Option<i64> {
match self {
Value::I64(v) => Some(*v),
_ => None,
}
}
pub fn as_u32(&self) -> Option<u32> {
match self {
Value::U32(v) => Some(*v),
_ => None,
}
}
pub fn as_u64(&self) -> Option<u64> {
match self {
Value::U64(v) => Some(*v),
_ => None,
}
}
pub fn as_bool(&self) -> Option<bool> {
match self {
Value::Bool(v) => Some(*v),
_ => None,
}
}
pub fn as_str(&self) -> Option<&str> {
match self {
Value::String(s) => Some(s.as_str()),
_ => None,
}
}
pub fn as_bytes(&self) -> Option<&[u8]> {
match self {
Value::Bytes(b) => Some(b.as_slice()),
_ => None,
}
}
pub fn as_enum_number(&self) -> Option<i32> {
match self {
Value::EnumNumber(n) => Some(*n),
_ => None,
}
}
pub fn as_message(&self) -> Option<&DynamicMessage> {
match self {
Value::Message(m) => Some(m.as_ref()),
_ => None,
}
}
pub fn as_list(&self) -> Option<&[Value]> {
match self {
Value::List(l) => Some(l.as_slice()),
_ => None,
}
}
pub fn as_map(&self) -> Option<&HashMap<MapKey, Value>> {
match self {
Value::Map(m) => Some(m),
_ => None,
}
}
}
impl MapKey {
pub fn to_value(&self) -> Value {
match self {
MapKey::String(s) => Value::String(s.clone()),
MapKey::I32(v) => Value::I32(*v),
MapKey::I64(v) => Value::I64(*v),
MapKey::U32(v) => Value::U32(*v),
MapKey::U64(v) => Value::U64(*v),
MapKey::Bool(v) => Value::Bool(*v),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn is_default_scalars() {
assert!(Value::I32(0).is_default());
assert!(!Value::I32(1).is_default());
assert!(Value::Bool(false).is_default());
assert!(!Value::Bool(true).is_default());
assert!(Value::String(String::new()).is_default());
assert!(!Value::String("x".to_owned()).is_default());
assert!(Value::Bytes(Vec::new()).is_default());
assert!(Value::F64(0.0).is_default());
assert!(Value::EnumNumber(0).is_default());
assert!(Value::List(Vec::new()).is_default());
}
#[test]
fn accessors() {
assert_eq!(Value::I32(7).as_i32(), Some(7));
assert_eq!(Value::I32(7).as_i64(), None);
assert_eq!(Value::String("hi".to_owned()).as_str(), Some("hi"));
assert_eq!(Value::Bytes(vec![1, 2]).as_bytes(), Some(&[1u8, 2][..]));
assert_eq!(Value::Bool(true).as_bool(), Some(true));
assert_eq!(Value::EnumNumber(3).as_enum_number(), Some(3));
}
#[test]
fn map_key_to_value() {
assert_eq!(
MapKey::String("k".to_owned()).to_value(),
Value::String("k".to_owned())
);
assert_eq!(MapKey::I64(5).to_value(), Value::I64(5));
assert_eq!(MapKey::Bool(true).to_value(), Value::Bool(true));
}
}