use std::{
borrow::Cow,
str::from_utf8,
};
use byteorder::{ByteOrder, NativeEndian};
use ordered_float::OrderedFloat;
use serde::{Serialize, Deserialize};
use super::{KeyType, Result, ResultWrap, Value};
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[serde(untagged)]
pub enum KeyData {
Int(i64),
#[serde(with = "float")]
Float(OrderedFloat<f64>),
String(String),
Binary(Vec<u8>),
Bool(bool),
}
mod float {
use super::OrderedFloat;
use serde::{Deserialize, Deserializer, Serializer};
#[allow(clippy::trivially_copy_pass_by_ref)]
pub fn serialize<S: Serializer>(
OrderedFloat(val): &OrderedFloat<f64>,
serializer: S,
) -> Result<S::Ok, S::Error> {
serializer.serialize_f64(*val)
}
pub fn deserialize<'de, D: Deserializer<'de>>(
deserializer: D,
) -> Result<OrderedFloat<f64>, D::Error> {
f64::deserialize(deserializer).map(OrderedFloat)
}
}
impl KeyData {
pub fn from_raw(typ: KeyType, raw: &[u8]) -> Result<Self> {
use self::KeyData::*;
Ok(match typ {
KeyType::Int => {
if raw.len() != 8 {
return Err("Int key must be 8 bytes length".into());
}
Int(NativeEndian::read_i64(raw))
}
KeyType::Float => {
if raw.len() != 8 {
return Err("Float key must be 8 bytes length".into());
}
Float(OrderedFloat(NativeEndian::read_f64(raw)))
}
KeyType::String => String(from_utf8(raw).wrap_err()?.into()),
KeyType::Binary => Binary(Vec::from(raw)),
KeyType::Bool => {
if raw.len() != 1 {
return Err("Bool key must be 1 byte length".into());
}
Bool(raw[0] != 0)
}
})
}
pub fn as_raw(&self) -> &[u8] {
use self::KeyData::*;
match self {
Int(val) => unsafe { &*(val as *const i64 as *const [u8; 8]) },
Float(val) => unsafe { &*(val as *const ordered_float::OrderedFloat<f64> as *const [u8; 8]) },
String(val) => if val.is_empty() {
b"\0"
} else {
val.as_bytes()
},
Binary(val) => if val.is_empty() {
&[0u8]
} else {
val.as_slice()
},
Bool(val) => unsafe { &*(val as *const bool as *const [u8; 1]) },
}
}
pub fn from_val(val: &Value) -> Option<Self> {
use serde_cbor::Value::*;
Some(match val {
Integer(val) => KeyData::Int(*val as i64),
Float(val) => KeyData::Float(OrderedFloat(*val)),
Bytes(val) => KeyData::Binary(val.clone()),
Text(val) => KeyData::String(val.clone()),
Bool(val) => KeyData::Bool(*val),
_ => return None,
})
}
pub fn is_empty(&self) -> bool {
use self::KeyData::*;
match self {
String(val) => val.is_empty(),
Binary(val) => val.is_empty(),
_ => false,
}
}
pub fn as_type(&self, typ: KeyType) -> Option<&KeyData> {
use self::KeyData::*;
Some(match (typ, self) {
(KeyType::Int, Int(..))
| (KeyType::Float, Float(..))
| (KeyType::Binary, Binary(..))
| (KeyType::String, String(..))
| (KeyType::Bool, Bool(..)) => self,
_ => return None,
})
}
pub fn to_type(&self, typ: KeyType) -> Option<Cow<'_, KeyData>> {
use self::KeyData::*;
Some(if let Some(v) = self.as_type(typ) {
Cow::Borrowed(v)
} else {
Cow::Owned(match (typ, self) {
(KeyType::Float, Int(v)) => Float(OrderedFloat(*v as f64)),
(KeyType::Int, Float(v)) => Int(v.round() as i64),
(KeyType::String, Int(v)) => String(v.to_string()),
(KeyType::String, Float(v)) => String(v.to_string()),
(KeyType::String, Bool(v)) => String(v.to_string()),
(KeyType::Int, String(v)) => Int(if let Ok(v) = v.parse() {
v
} else {
return None;
}),
(KeyType::Float, String(v)) => Float(if let Ok(v) = v.parse() {
OrderedFloat(v)
} else {
return None;
}),
(KeyType::Bool, String(v)) => Bool(if let Ok(v) = v.parse() {
v
} else {
return None;
}),
_ => return None,
})
})
}
pub fn get_type(&self) -> KeyType {
use self::KeyData::*;
match self {
Int(..) => KeyType::Int,
Float(..) => KeyType::Float,
String(..) => KeyType::String,
Binary(..) => KeyType::Binary,
Bool(..) => KeyType::Bool,
}
}
}
impl<'a> From<&'a i64> for KeyData {
fn from(v: &'a i64) -> Self {
KeyData::Int(*v)
}
}
impl From<i64> for KeyData {
fn from(v: i64) -> Self {
KeyData::Int(v)
}
}
impl<'a> From<&'a f64> for KeyData {
fn from(v: &'a f64) -> Self {
KeyData::Float(OrderedFloat(*v))
}
}
impl From<f64> for KeyData {
fn from(v: f64) -> Self {
KeyData::Float(OrderedFloat(v))
}
}
impl<'a> From<&'a String> for KeyData {
fn from(v: &'a String) -> Self {
KeyData::String(v.clone())
}
}
impl From<String> for KeyData {
fn from(v: String) -> Self {
KeyData::String(v)
}
}
impl<'a> From<&'a str> for KeyData {
fn from(v: &str) -> Self {
KeyData::String(v.into())
}
}
impl<'a> From<&'a [u8]> for KeyData {
fn from(v: &[u8]) -> Self {
KeyData::Binary(v.into())
}
}
impl<'a> From<&'a Vec<u8>> for KeyData {
fn from(v: &'a Vec<u8>) -> Self {
KeyData::Binary(v.clone())
}
}
impl From<Vec<u8>> for KeyData {
fn from(v: Vec<u8>) -> Self {
KeyData::Binary(v)
}
}
impl<'a> From<&'a bool> for KeyData {
fn from(v: &'a bool) -> Self {
KeyData::Bool(*v)
}
}
impl From<bool> for KeyData {
fn from(v: bool) -> Self {
KeyData::Bool(v)
}
}
#[cfg(test)]
mod test {
use super::{KeyData, KeyType};
#[test]
fn get_type() {
assert_eq!(KeyData::from(123).get_type(), KeyType::Int);
assert_eq!(KeyData::from(12.3).get_type(), KeyType::Float);
assert_eq!(KeyData::from("abc").get_type(), KeyType::String);
assert_eq!(KeyData::from(vec![1u8, 2, 3]).get_type(), KeyType::Binary);
assert_eq!(KeyData::from(true).get_type(), KeyType::Bool);
}
#[test]
fn as_type() {
assert_eq!(
KeyData::from("abc")
.as_type(KeyType::String)
.unwrap()
.get_type(),
KeyType::String
);
assert_eq!(KeyData::from("abc").as_type(KeyType::Int), None);
assert_eq!(
KeyData::from(123).as_type(KeyType::Int).unwrap().get_type(),
KeyType::Int
);
assert_eq!(KeyData::from(123).as_type(KeyType::Float), None);
assert_eq!(
KeyData::from(12.3)
.as_type(KeyType::Float)
.unwrap()
.get_type(),
KeyType::Float
);
assert_eq!(KeyData::from(12.3).as_type(KeyType::Int), None);
assert_eq!(
KeyData::from(true)
.as_type(KeyType::Bool)
.unwrap()
.get_type(),
KeyType::Bool
);
assert_eq!(KeyData::from(true).as_type(KeyType::String), None);
}
#[test]
fn into_type() {
assert_eq!(
KeyData::from("abc")
.to_type(KeyType::String)
.unwrap()
.get_type(),
KeyType::String
);
assert_eq!(KeyData::from("abc").to_type(KeyType::Int), None);
assert_eq!(
KeyData::from("123")
.to_type(KeyType::Int)
.unwrap()
.into_owned(),
KeyData::from(123)
);
assert_eq!(
KeyData::from("12.3")
.to_type(KeyType::Float)
.unwrap()
.into_owned(),
KeyData::from(12.3)
);
assert_eq!(KeyData::from("12.3").to_type(KeyType::Int), None);
assert_eq!(
KeyData::from(123)
.to_type(KeyType::Int)
.unwrap()
.get_type(),
KeyType::Int
);
assert_eq!(
KeyData::from(123)
.to_type(KeyType::Float)
.unwrap()
.into_owned(),
KeyData::from(123.0)
);
assert_eq!(
KeyData::from(123)
.to_type(KeyType::String)
.unwrap()
.into_owned(),
KeyData::from("123")
);
assert_eq!(
KeyData::from(12.3)
.to_type(KeyType::Float)
.unwrap()
.into_owned(),
KeyData::from(12.3)
);
assert_eq!(
KeyData::from(12.3)
.to_type(KeyType::Int)
.unwrap()
.into_owned(),
KeyData::from(12)
);
assert_eq!(
KeyData::from(12.5)
.to_type(KeyType::Int)
.unwrap()
.into_owned(),
KeyData::from(13)
);
assert_eq!(
KeyData::from(12.3)
.to_type(KeyType::String)
.unwrap()
.into_owned(),
KeyData::from("12.3")
);
assert_eq!(
KeyData::from(true)
.to_type(KeyType::Bool)
.unwrap()
.get_type(),
KeyType::Bool
);
assert_eq!(
KeyData::from(true)
.to_type(KeyType::String)
.unwrap()
.into_owned(),
KeyData::from("true")
);
}
}