use std::hash::{Hash, Hasher};
use chrono::{DateTime, Utc};
use ntex_bytes::{ByteString, Bytes};
use ordered_float::OrderedFloat;
use uuid::Uuid;
use crate::types::{Descriptor, List, StaticSymbol, Str, Symbol};
use crate::{protocol::Annotations, HashMap};
#[derive(Debug, Eq, PartialEq, Hash, Clone, Display, From)]
pub enum Variant {
Null,
Boolean(bool),
Ubyte(u8),
Ushort(u16),
Uint(u32),
Ulong(u64),
Byte(i8),
Short(i16),
Int(i32),
Long(i64),
Float(OrderedFloat<f32>),
Double(OrderedFloat<f64>),
Char(char),
Timestamp(DateTime<Utc>),
Uuid(Uuid),
#[display(fmt = "Binary({:?})", _0)]
Binary(Bytes),
String(Str),
Symbol(Symbol),
StaticSymbol(StaticSymbol),
#[display(fmt = "List({:?})", _0)]
List(List),
Map(VariantMap),
#[display(fmt = "Described{:?}", _0)]
Described((Descriptor, Box<Variant>)),
}
impl From<ByteString> for Variant {
fn from(s: ByteString) -> Self {
Str::from(s).into()
}
}
impl From<String> for Variant {
fn from(s: String) -> Self {
Str::from(ByteString::from(s)).into()
}
}
impl From<&'static str> for Variant {
fn from(s: &'static str) -> Self {
Str::from(s).into()
}
}
impl PartialEq<str> for Variant {
fn eq(&self, other: &str) -> bool {
match self {
Variant::String(s) => s == other,
Variant::Symbol(s) => s == other,
_ => false,
}
}
}
impl Variant {
pub fn as_str(&self) -> Option<&str> {
match self {
Variant::String(s) => Some(s.as_str()),
Variant::Symbol(s) => Some(s.as_str()),
_ => None,
}
}
pub fn as_int(&self) -> Option<i32> {
match self {
Variant::Int(v) => Some(*v),
_ => None,
}
}
pub fn as_long(&self) -> Option<i64> {
match self {
Variant::Ubyte(v) => Some(*v as i64),
Variant::Ushort(v) => Some(*v as i64),
Variant::Uint(v) => Some(*v as i64),
Variant::Ulong(v) => Some(*v as i64),
Variant::Byte(v) => Some(*v as i64),
Variant::Short(v) => Some(*v as i64),
Variant::Int(v) => Some(*v as i64),
Variant::Long(v) => Some(*v),
_ => None,
}
}
pub fn to_bytes_str(&self) -> Option<ByteString> {
match self {
Variant::String(s) => Some(s.to_bytes_str()),
Variant::Symbol(s) => Some(s.to_bytes_str()),
_ => None,
}
}
}
#[derive(PartialEq, Eq, Clone, Debug, Display)]
#[display(fmt = "{:?}", map)]
pub struct VariantMap {
pub map: HashMap<Variant, Variant>,
}
impl VariantMap {
pub fn new(map: HashMap<Variant, Variant>) -> VariantMap {
VariantMap { map }
}
}
#[allow(clippy::derive_hash_xor_eq)]
impl Hash for VariantMap {
fn hash<H: Hasher>(&self, _state: &mut H) {
unimplemented!()
}
}
#[derive(PartialEq, Eq, Clone, Debug, Display)]
#[display(fmt = "{:?}", _0)]
pub struct VecSymbolMap(pub Vec<(Symbol, Variant)>);
impl Default for VecSymbolMap {
fn default() -> Self {
VecSymbolMap(Vec::with_capacity(8))
}
}
impl From<Annotations> for VecSymbolMap {
fn from(anns: Annotations) -> VecSymbolMap {
VecSymbolMap(anns.into_iter().collect())
}
}
impl From<Vec<(Symbol, Variant)>> for VecSymbolMap {
fn from(data: Vec<(Symbol, Variant)>) -> VecSymbolMap {
VecSymbolMap(data)
}
}
impl std::ops::Deref for VecSymbolMap {
type Target = Vec<(Symbol, Variant)>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl std::ops::DerefMut for VecSymbolMap {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
#[derive(PartialEq, Eq, Clone, Debug, Display)]
#[display(fmt = "{:?}", _0)]
pub struct VecStringMap(pub Vec<(Str, Variant)>);
impl Default for VecStringMap {
fn default() -> Self {
VecStringMap(Vec::with_capacity(8))
}
}
impl From<Vec<(Str, Variant)>> for VecStringMap {
fn from(data: Vec<(Str, Variant)>) -> VecStringMap {
VecStringMap(data)
}
}
impl From<HashMap<Str, Variant>> for VecStringMap {
fn from(map: HashMap<Str, Variant>) -> VecStringMap {
VecStringMap(map.into_iter().collect())
}
}
impl std::ops::Deref for VecStringMap {
type Target = Vec<(Str, Variant)>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl std::ops::DerefMut for VecStringMap {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn bytes_eq() {
let bytes1 = Variant::Binary(Bytes::from(&b"hello"[..]));
let bytes2 = Variant::Binary(Bytes::from(&b"hello"[..]));
let bytes3 = Variant::Binary(Bytes::from(&b"world"[..]));
assert_eq!(bytes1, bytes2);
assert!(bytes1 != bytes3);
}
#[test]
fn string_eq() {
let a = Variant::String(ByteString::from("hello").into());
let b = Variant::String(ByteString::from("world!").into());
assert_eq!(Variant::String(ByteString::from("hello").into()), a);
assert!(a != b);
}
#[test]
fn symbol_eq() {
let a = Variant::Symbol(Symbol::from("hello"));
let b = Variant::Symbol(Symbol::from("world!"));
assert_eq!(Variant::Symbol(Symbol::from("hello")), a);
assert!(a != b);
}
}