diff --git a/src/rpcvalue.rs b/src/rpcvalue.rs index 39c1df4..6625b41 100644 --- a/src/rpcvalue.rs +++ b/src/rpcvalue.rs @@ -1,20 +1,19 @@ use std::collections::BTreeMap; use std::fmt; -use crate::{datetime, DateTime, Decimal}; +use crate::chainpack::ChainPackReader; +use crate::chainpack::ChainPackWriter; use crate::decimal; use crate::metamap::MetaMap; use crate::reader::Reader; -use crate::{CponReader, ReadResult}; use crate::writer::Writer; use crate::CponWriter; -use crate::chainpack::ChainPackWriter; -use crate::chainpack::ChainPackReader; +use crate::{datetime, DateTime, Decimal}; +use crate::{CponReader, ReadResult}; use std::sync::OnceLock; // see https://github.com/rhysd/tinyjson/blob/master/src/json_value.rs - const EMPTY_STR_REF: &str = ""; const EMPTY_BYTES_REF: &[u8] = EMPTY_STR_REF.as_bytes(); static EMPTY_LIST: OnceLock = OnceLock::new(); @@ -38,83 +37,167 @@ pub type IMap = BTreeMap; #[derive(Debug, Clone, PartialEq)] pub enum Value { - Null, - Int(i64), - UInt(u64), - Double(f64), - Bool(bool), - DateTime(datetime::DateTime), - Decimal(decimal::Decimal), - String(Box), - Blob(Box), - List(Box), - Map(Box), - IMap(Box), + Null, + Int(i64), + UInt(u64), + Double(f64), + Bool(bool), + DateTime(datetime::DateTime), + Decimal(decimal::Decimal), + String(Box), + Blob(Box), + List(Box), + Map(Box), + IMap(Box), } impl Value { - pub fn type_name(&self) -> &'static str { - match &self { - Value::Null => "Null", - Value::Int(_) => "Int", - Value::UInt(_) => "UInt", - Value::Double(_) => "Double", - Value::Bool(_) => "Bool", - Value::DateTime(_) => "DateTime", - Value::Decimal(_) => "Decimal", - Value::String(_) => "String", - Value::Blob(_) => "Blob", - Value::List(_) => "List", - Value::Map(_) => "Map", - Value::IMap(_) => "IMap", - } - } - pub fn is_default_value(&self) -> bool { - match &self { - Value::Null => true, - Value::Int(i) => *i == 0, - Value::UInt(u) => *u == 0, - Value::Double(d) => *d == 0.0, - Value::Bool(b) => !(*b), - Value::DateTime(dt) => dt.epoch_msec() == 0, - Value::Decimal(d) => d.mantissa() == 0, - Value::String(s) => s.is_empty(), - Value::Blob(b) => b.is_empty(), - Value::List(l) => l.is_empty(), - Value::Map(m) => m.is_empty(), - Value::IMap(m) => m.is_empty(), - } - } -} - -impl From<()> for Value { fn from(_: ()) -> Self { Value::Null }} -impl From for Value { fn from(val: bool) -> Self { Value::Bool(val) }} -impl From<&str> for Value { fn from(val: &str) -> Self { Value::String(Box::new(val.to_string())) }} -impl From for Value { fn from(val: String) -> Self { Value::String(Box::new(val)) }} -impl From<&String> for Value { fn from(val: &String) -> Self { Value::String(Box::new(val.clone())) }} -impl From> for Value { fn from(val: Vec) -> Self { Value::Blob(Box::new(val)) }} -impl From<&[u8]> for Value { fn from(val: &[u8]) -> Self { Value::Blob(Box::new(val.to_vec())) }} -impl From for Value { fn from(val: i32) -> Self { Value::Int(val.into()) }} -impl From for Value { fn from(val: i64) -> Self { Value::Int(val) }} -impl From for Value { fn from(val: isize) -> Self { Value::Int(val as i64) }} -impl From for Value { fn from(val: u32) -> Self { Value::UInt(val.into()) }} -impl From for Value { fn from(val: u64) -> Self { Value::UInt(val) }} -impl From for Value { fn from(val: usize) -> Self { Value::UInt(val as u64) }} -impl From for Value { fn from(val: f64) -> Self { Value::Double(val) }} -impl From for Value { fn from(val: Decimal) -> Self { Value::Decimal(val) }} -impl From for Value { fn from(val: List) -> Self { Value::List(Box::new(val)) }} -impl From for Value { fn from(val: Map) -> Self { Value::Map(Box::new(val)) }} -impl From for Value { fn from(val: IMap) -> Self { Value::IMap(Box::new(val)) }} -impl From for Value { fn from(val: datetime::DateTime) -> Self { Value::DateTime(val) }} -impl From for Value { fn from(val: chrono::NaiveDateTime) -> Self { Value::DateTime(DateTime::from_naive_datetime(&val)) }} -impl From> for Value { fn from(item: chrono::DateTime) -> Self { Value::DateTime(datetime::DateTime::from_datetime(&item)) }} + pub fn type_name(&self) -> &'static str { + match &self { + Value::Null => "Null", + Value::Int(_) => "Int", + Value::UInt(_) => "UInt", + Value::Double(_) => "Double", + Value::Bool(_) => "Bool", + Value::DateTime(_) => "DateTime", + Value::Decimal(_) => "Decimal", + Value::String(_) => "String", + Value::Blob(_) => "Blob", + Value::List(_) => "List", + Value::Map(_) => "Map", + Value::IMap(_) => "IMap", + } + } + pub fn is_default_value(&self) -> bool { + match &self { + Value::Null => true, + Value::Int(i) => *i == 0, + Value::UInt(u) => *u == 0, + Value::Double(d) => *d == 0.0, + Value::Bool(b) => !(*b), + Value::DateTime(dt) => dt.epoch_msec() == 0, + Value::Decimal(d) => d.mantissa() == 0, + Value::String(s) => s.is_empty(), + Value::Blob(b) => b.is_empty(), + Value::List(l) => l.is_empty(), + Value::Map(m) => m.is_empty(), + Value::IMap(m) => m.is_empty(), + } + } +} + +impl From<()> for Value { + fn from(_: ()) -> Self { + Value::Null + } +} +impl From for Value { + fn from(val: bool) -> Self { + Value::Bool(val) + } +} +impl From<&str> for Value { + fn from(val: &str) -> Self { + Value::String(Box::new(val.to_string())) + } +} +impl From for Value { + fn from(val: String) -> Self { + Value::String(Box::new(val)) + } +} +impl From<&String> for Value { + fn from(val: &String) -> Self { + Value::String(Box::new(val.clone())) + } +} +impl From> for Value { + fn from(val: Vec) -> Self { + Value::Blob(Box::new(val)) + } +} +impl From<&[u8]> for Value { + fn from(val: &[u8]) -> Self { + Value::Blob(Box::new(val.to_vec())) + } +} +impl From for Value { + fn from(val: i32) -> Self { + Value::Int(val.into()) + } +} +impl From for Value { + fn from(val: i64) -> Self { + Value::Int(val) + } +} +impl From for Value { + fn from(val: isize) -> Self { + Value::Int(val as i64) + } +} +impl From for Value { + fn from(val: u32) -> Self { + Value::UInt(val.into()) + } +} +impl From for Value { + fn from(val: u64) -> Self { + Value::UInt(val) + } +} +impl From for Value { + fn from(val: usize) -> Self { + Value::UInt(val as u64) + } +} +impl From for Value { + fn from(val: f64) -> Self { + Value::Double(val) + } +} +impl From for Value { + fn from(val: Decimal) -> Self { + Value::Decimal(val) + } +} +impl From for Value { + fn from(val: List) -> Self { + Value::List(Box::new(val)) + } +} +impl From for Value { + fn from(val: Map) -> Self { + Value::Map(Box::new(val)) + } +} +impl From for Value { + fn from(val: IMap) -> Self { + Value::IMap(Box::new(val)) + } +} +impl From for Value { + fn from(val: datetime::DateTime) -> Self { + Value::DateTime(val) + } +} +impl From for Value { + fn from(val: chrono::NaiveDateTime) -> Self { + Value::DateTime(DateTime::from_naive_datetime(&val)) + } +} +impl From> for Value { + fn from(item: chrono::DateTime) -> Self { + Value::DateTime(datetime::DateTime::from_datetime(&item)) + } +} impl> From for RpcValue { fn from(value: T) -> Self { - RpcValue { - meta: None, - value: value.into() - } + RpcValue { + meta: None, + value: value.into(), + } } } @@ -130,37 +213,37 @@ macro_rules! is_xxx { } pub enum GetKey<'a> { - Int(i32), - Str(&'a str), + Int(i32), + Str(&'a str), } pub trait GetIndex { - fn make_key(&self) -> GetKey; + fn make_key(&self) -> GetKey; } impl GetIndex for &str { - fn make_key(&self) -> GetKey { - GetKey::Str(self) - } + fn make_key(&self) -> GetKey { + GetKey::Str(self) + } } impl GetIndex for i32 { - fn make_key(&self) -> GetKey { - GetKey::Int(*self) - } + fn make_key(&self) -> GetKey { + GetKey::Int(*self) + } } impl GetIndex for u32 { - fn make_key(&self) -> GetKey { - GetKey::Int(*self as i32) - } + fn make_key(&self) -> GetKey { + GetKey::Int(*self as i32) + } } impl GetIndex for usize { - fn make_key(&self) -> GetKey { - GetKey::Int(*self as i32) - } + fn make_key(&self) -> GetKey { + GetKey::Int(*self as i32) + } } #[derive(PartialEq, Clone)] pub struct RpcValue { - meta: Option>, - value: Value + meta: Option>, + value: Value, } impl RpcValue { @@ -172,40 +255,40 @@ impl RpcValue { } pub fn new(v: Value, m: Option) -> Self { RpcValue { - meta: m.map(Box::new), + meta: m.map(Box::new), value: v, } } - /* - pub fn new(val: I) -> RpcValue - where I: FromValue - { - RpcValue { - meta: None, - value: val.chainpack_make_value(), - } - } - pub fn new_with_meta(val: I, meta: Option) -> RpcValue - where I: FromValue - { - let mm = match meta { - None => None, - Some(m) => Some(Box::new(m)), - }; - RpcValue { - meta: mm, - value: val.chainpack_make_value(), - } - } - pub fn set_meta(&mut self, m: MetaMap) { - if m.is_empty() { - self.meta = None; - } - else { - self.meta = Some(Box::new(m)); - } - } - */ + /* + pub fn new(val: I) -> RpcValue + where I: FromValue + { + RpcValue { + meta: None, + value: val.chainpack_make_value(), + } + } + pub fn new_with_meta(val: I, meta: Option) -> RpcValue + where I: FromValue + { + let mm = match meta { + None => None, + Some(m) => Some(Box::new(m)), + }; + RpcValue { + meta: mm, + value: val.chainpack_make_value(), + } + } + pub fn set_meta(&mut self, m: MetaMap) { + if m.is_empty() { + self.meta = None; + } + else { + self.meta = Some(Box::new(m)); + } + } + */ pub fn set_meta(mut self, meta: Option) -> Self { self.meta = meta.map(Box::new); self @@ -216,7 +299,8 @@ impl RpcValue { pub fn meta(&self) -> &MetaMap { self.meta.as_ref().map_or_else( || EMPTY_METAMAP.get_or_init(MetaMap::new), - >::as_ref) + >::as_ref, + ) } pub fn meta_mut(&mut self) -> Option<&mut MetaMap> { self.meta.as_mut().map(>::as_mut) @@ -264,7 +348,9 @@ impl RpcValue { _ => 0, } } - pub fn as_i32(&self) -> i32 { self.as_i64() as i32 } + pub fn as_i32(&self) -> i32 { + self.as_i64() as i32 + } pub fn as_u64(&self) -> u64 { match &self.value { Value::Int(d) => *d as u64, @@ -272,7 +358,9 @@ impl RpcValue { _ => 0, } } - pub fn as_u32(&self) -> u32 { self.as_u64() as u32 } + pub fn as_u32(&self) -> u32 { + self.as_u64() as u32 + } pub fn as_f64(&self) -> f64 { match &self.value { Value::Double(d) => *d, @@ -304,12 +392,12 @@ impl RpcValue { _ => decimal::Decimal::new(0, 0), } } - // pub fn as_str(&self) -> Result<&str, Utf8Error> { - // match &self.value { - // Value::String(b) => std::str::from_utf8(b), - // _ => std::str::from_utf8(EMPTY_BYTES_REF), - // } - // } + // pub fn as_str(&self) -> Result<&str, Utf8Error> { + // match &self.value { + // Value::String(b) => std::str::from_utf8(b), + // _ => std::str::from_utf8(EMPTY_BYTES_REF), + // } + // } pub fn as_blob(&self) -> &[u8] { match &self.value { Value::Blob(b) => b, @@ -341,37 +429,34 @@ impl RpcValue { } } pub fn get(&self, key: I) -> Option<&RpcValue> - where I: GetIndex - { - match key.make_key() { - GetKey::Int(ix) => { - match &self.value { - Value::List(lst) => lst.get(ix as usize), - Value::IMap(map) => map.get(&ix), - _ => { None } - } - } - GetKey::Str(ix) => { - match &self.value { - Value::Map(map) => map.get(ix), - _ => { None } - } - } - } + where + I: GetIndex, + { + match key.make_key() { + GetKey::Int(ix) => match &self.value { + Value::List(lst) => lst.get(ix as usize), + Value::IMap(map) => map.get(&ix), + _ => None, + }, + GetKey::Str(ix) => match &self.value { + Value::Map(map) => map.get(ix), + _ => None, + }, } - pub fn to_cpon(&self) -> String { self.to_cpon_indented("").unwrap_or("".to_string()) } - pub fn to_cpon_indented(&self, indent: &str) -> crate::Result { - let buff = self.to_cpon_bytes_indented(indent.as_bytes())?; - String::from_utf8(buff).map_err(|e| e.into()) } - pub fn to_cpon_bytes_indented(&self, indent: &[u8]) -> crate::Result> { + pub fn to_cpon(&self) -> String { + self.to_cpon_indented("") + } + pub fn to_cpon_indented(&self, indent: &str) -> String { + let buff = self.to_cpon_bytes_indented(indent.as_bytes()); + String::from_utf8(buff).map_or_else(|_| "".to_string(), |s| s) + } + pub fn to_cpon_bytes_indented(&self, indent: &[u8]) -> Vec { let mut buff: Vec = Vec::new(); let mut wr = CponWriter::new(&mut buff); wr.set_indent(indent); - match wr.write(self) { - Ok(_) => { Ok(buff) } - Err(err) => { Err(err.into()) } - } + let r = wr.write(self); + r.map_or_else(|_| Vec::new(), |_| buff) } pub fn to_chainpack(&self) -> Vec { let mut buff: Vec = Vec::new(); @@ -394,104 +479,103 @@ impl RpcValue { static NULL_RPCVALUE: OnceLock = OnceLock::new(); impl Default for &RpcValue { - fn default() -> Self { - NULL_RPCVALUE.get_or_init(RpcValue::null) - } + fn default() -> Self { + NULL_RPCVALUE.get_or_init(RpcValue::null) + } } impl fmt::Debug for RpcValue { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - //write!(f, "RpcValue {{meta: {:?} value: {:?}}}", self.meta, self.value) - write!(f, "{}", self.to_cpon()) - } + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + //write!(f, "RpcValue {{meta: {:?} value: {:?}}}", self.meta, self.value) + write!(f, "{}", self.to_cpon()) + } } impl fmt::Display for RpcValue { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.to_cpon()) - } + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.to_cpon()) + } } #[cfg(test)] mod test { - use std::collections::BTreeMap; - use std::mem::size_of; - - use chrono::Offset; - - use crate::{DateTime}; - use crate::Decimal; - use crate::metamap::MetaMap; - use crate::rpcvalue::{RpcValue, Value, Map}; - - macro_rules! show_size { - (header) => ( - log::debug!("{:<22} {:>4} ", "Type", "T"); - log::debug!("------------------------------"); - ); - ($t:ty) => ( - log::debug!("{:<22} {:4}", stringify!($t), size_of::<$t>()) - ) - } - - #[test] - fn size() { - show_size!(header); - show_size!(usize); - show_size!(MetaMap); - show_size!(Box); - show_size!(Option); - show_size!(Option>); - show_size!(Value); - show_size!(Option); - show_size!(RpcValue); - } - - #[test] - fn rpcval_new() - { - let rv = RpcValue::from(true); - assert_eq!(rv.as_bool(), true); - let rv = RpcValue::from("foo"); - assert_eq!(rv.as_str(), "foo"); - let rv = RpcValue::from(&b"bar"[..]); - assert_eq!(rv.as_blob(), b"bar"); - let rv = RpcValue::from(123); - assert_eq!(rv.as_i32(), 123); - let rv = RpcValue::from(12.3); - assert_eq!(rv.as_f64(), 12.3); - - let dt = DateTime::now(); - let rv = RpcValue::from(dt.clone()); - assert_eq!(rv.as_datetime(), dt); - - let dc = Decimal::new(123, -1); - let rv = RpcValue::from(dc.clone()); - assert_eq!(rv.as_decimal(), dc); - - let dt = chrono::offset::Utc::now(); - let rv = RpcValue::from(dt.clone()); - assert_eq!(rv.as_datetime().epoch_msec(), dt.timestamp_millis()); - - let dt = chrono::offset::Local::now(); - let rv = RpcValue::from(dt.clone()); - assert_eq!(rv.as_datetime().epoch_msec() + rv.as_datetime().utc_offset() as i64 * 1000 - , dt.timestamp_millis() + dt.offset().fix().local_minus_utc() as i64 * 1000); - - let vec1 = vec![RpcValue::from(123), RpcValue::from("foo")]; - let rv = RpcValue::from(vec1.clone()); - assert_eq!(rv.as_list(), &vec1); - - let mut m: Map = BTreeMap::new(); - m.insert("foo".to_string(), RpcValue::from(123)); - m.insert("bar".to_string(), RpcValue::from("foo")); - let rv = RpcValue::from(m.clone()); - assert_eq!(rv.as_map(), &m); - - let mut m: BTreeMap = BTreeMap::new(); - m.insert(1, RpcValue::from(123)); - m.insert(2, RpcValue::from("foo")); - let rv = RpcValue::from(m.clone()); - assert_eq!(rv.as_imap(), &m); - } + use std::collections::BTreeMap; + use std::mem::size_of; + + use chrono::Offset; + + use crate::metamap::MetaMap; + use crate::rpcvalue::{Map, RpcValue, Value}; + use crate::DateTime; + use crate::Decimal; + + macro_rules! show_size { + (header) => { + log::debug!("{:<22} {:>4} ", "Type", "T"); + log::debug!("------------------------------"); + }; + ($t:ty) => { + log::debug!("{:<22} {:4}", stringify!($t), size_of::<$t>()) + }; + } -} + #[test] + fn size() { + show_size!(header); + show_size!(usize); + show_size!(MetaMap); + show_size!(Box); + show_size!(Option); + show_size!(Option>); + show_size!(Value); + show_size!(Option); + show_size!(RpcValue); + } + #[test] + fn rpcval_new() { + let rv = RpcValue::from(true); + assert_eq!(rv.as_bool(), true); + let rv = RpcValue::from("foo"); + assert_eq!(rv.as_str(), "foo"); + let rv = RpcValue::from(&b"bar"[..]); + assert_eq!(rv.as_blob(), b"bar"); + let rv = RpcValue::from(123); + assert_eq!(rv.as_i32(), 123); + let rv = RpcValue::from(12.3); + assert_eq!(rv.as_f64(), 12.3); + + let dt = DateTime::now(); + let rv = RpcValue::from(dt.clone()); + assert_eq!(rv.as_datetime(), dt); + + let dc = Decimal::new(123, -1); + let rv = RpcValue::from(dc.clone()); + assert_eq!(rv.as_decimal(), dc); + + let dt = chrono::offset::Utc::now(); + let rv = RpcValue::from(dt.clone()); + assert_eq!(rv.as_datetime().epoch_msec(), dt.timestamp_millis()); + + let dt = chrono::offset::Local::now(); + let rv = RpcValue::from(dt.clone()); + assert_eq!( + rv.as_datetime().epoch_msec() + rv.as_datetime().utc_offset() as i64 * 1000, + dt.timestamp_millis() + dt.offset().fix().local_minus_utc() as i64 * 1000 + ); + + let vec1 = vec![RpcValue::from(123), RpcValue::from("foo")]; + let rv = RpcValue::from(vec1.clone()); + assert_eq!(rv.as_list(), &vec1); + + let mut m: Map = BTreeMap::new(); + m.insert("foo".to_string(), RpcValue::from(123)); + m.insert("bar".to_string(), RpcValue::from("foo")); + let rv = RpcValue::from(m.clone()); + assert_eq!(rv.as_map(), &m); + + let mut m: BTreeMap = BTreeMap::new(); + m.insert(1, RpcValue::from(123)); + m.insert(2, RpcValue::from("foo")); + let rv = RpcValue::from(m.clone()); + assert_eq!(rv.as_imap(), &m); + } +}