use super::*;
#[cfg(feature = "json")]
use serde_json::{Map, Number, Value};
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
pub enum Metadata {
Text(String),
Integer(usize),
Float(f32),
Array(Vec<Metadata>),
Object(HashMap<String, Metadata>),
}
impl Metadata {
pub fn match_filter(&self, filter: &Metadata) -> bool {
if let Metadata::Text(filter_text) = filter {
if let Metadata::Text(text) = self {
return text.contains(filter_text);
}
}
if let Metadata::Integer(filter_int) = filter {
if let Metadata::Integer(int) = self {
return int == filter_int;
}
}
if let Metadata::Float(filter_float) = filter {
if let Metadata::Float(float) = self {
return float == filter_float;
}
}
if let Metadata::Object(filter_object) = filter {
if let Metadata::Object(object) = self {
return Metadata::match_filter_object(object, filter_object);
}
}
false
}
fn match_filter_object(
object: &HashMap<String, Metadata>,
filter_object: &HashMap<String, Metadata>,
) -> bool {
for (key, filter) in filter_object {
let data = object.get(key);
if data.is_none() {
return false;
}
if !filter.match_filter(data.unwrap()) {
return false;
}
}
true
}
}
impl From<usize> for Metadata {
fn from(value: usize) -> Self {
Metadata::Integer(value)
}
}
impl From<f32> for Metadata {
fn from(value: f32) -> Self {
Metadata::Float(value)
}
}
impl From<String> for Metadata {
fn from(value: String) -> Self {
Metadata::Text(value)
}
}
impl From<&str> for Metadata {
fn from(value: &str) -> Self {
Metadata::Text(value.to_string())
}
}
impl<T> From<Vec<T>> for Metadata
where
Metadata: From<T>,
{
fn from(value: Vec<T>) -> Self {
let arr = value.into_iter().map(|v| v.into()).collect();
Metadata::Array(arr)
}
}
impl<T> From<HashMap<String, T>> for Metadata
where
Metadata: From<T>,
{
fn from(value: HashMap<String, T>) -> Self {
let iter = value.into_iter();
let obj = iter.map(|(k, v)| (k, v.into())).collect();
Metadata::Object(obj)
}
}
impl<T> From<HashMap<&str, T>> for Metadata
where
Metadata: From<T>,
{
fn from(value: HashMap<&str, T>) -> Self {
let iter = value.into_iter();
let obj = iter.map(|(k, v)| (k.into(), v.into())).collect();
Metadata::Object(obj)
}
}
#[cfg(feature = "json")]
impl From<Value> for Metadata {
fn from(value: Value) -> Self {
let convert_number = |number: Number| {
if number.is_f64() {
let float = number.as_f64().unwrap();
Metadata::Float(float as f32)
} else {
let int = number.as_i64().unwrap();
Metadata::Integer(int as usize)
}
};
let convert_array = |array: Vec<Value>| {
let vec = array.into_iter().map(|v| v.into()).collect();
Metadata::Array(vec)
};
let convert_object = |object: Map<String, Value>| {
let map = object
.into_iter()
.map(|(k, v)| (k, v.into()))
.collect::<HashMap<String, Metadata>>();
Metadata::Object(map)
};
match value {
Value::String(text) => Metadata::Text(text),
Value::Number(number) => convert_number(number),
Value::Array(array) => convert_array(array),
Value::Object(object) => convert_object(object),
_ => panic!("Unsupported JSON type for the metadata."),
}
}
}
#[cfg(feature = "json")]
impl From<Metadata> for Value {
fn from(metadata: Metadata) -> Self {
let convert_integer = |int: usize| {
let number = Number::from(int as i64);
Value::Number(number)
};
let convert_float = |float: f32| {
let number = Number::from_f64(float as f64).unwrap();
Value::Number(number)
};
let convert_array = |arr: Vec<Metadata>| {
let vec = arr.into_iter().map(|v| v.into()).collect();
Value::Array(vec)
};
let convert_object = |obj: HashMap<String, Metadata>| {
let map = obj
.into_iter()
.map(|(k, v)| (k, v.into()))
.collect::<Map<String, Value>>();
Value::Object(map)
};
match metadata {
Metadata::Text(text) => Value::String(text),
Metadata::Integer(int) => convert_integer(int),
Metadata::Float(float) => convert_float(float),
Metadata::Array(array) => convert_array(array),
Metadata::Object(object) => convert_object(object),
}
}
}
#[cfg(feature = "py")]
impl From<&PyAny> for Metadata {
fn from(value: &PyAny) -> Self {
if let Ok(text) = value.extract::<String>() {
return Metadata::Text(text);
}
if let Ok(int) = value.extract::<usize>() {
return Metadata::Integer(int);
}
if let Ok(float) = value.extract::<f32>() {
return Metadata::Float(float);
}
if let Ok(list) = value.extract::<Vec<&PyAny>>() {
let arr = list.into_iter().map(|v| v.into()).collect();
return Metadata::Array(arr);
}
if let Ok(dict) = value.extract::<HashMap<String, &PyAny>>() {
let obj = dict.into_iter().map(|(k, v)| (k, v.into())).collect();
return Metadata::Object(obj);
}
panic!("Unsupported type for the metadata.");
}
}
#[cfg(feature = "py")]
impl IntoPy<Py<PyAny>> for Metadata {
fn into_py(self, py: Python) -> Py<PyAny> {
let list_converter = |vec: Vec<Metadata>| {
let list = vec
.into_iter()
.map(|metadata: Metadata| metadata.into_py(py))
.collect::<Vec<Py<PyAny>>>();
list.into_py(py)
};
let dict_converter = |map: HashMap<String, Metadata>| {
let dict = map
.into_iter()
.map(|(key, value)| (key, value.into_py(py)))
.collect::<HashMap<String, Py<PyAny>>>();
dict.into_py(py)
};
match self {
Metadata::Text(text) => text.into_py(py),
Metadata::Integer(int) => int.into_py(py),
Metadata::Float(float) => float.into_py(py),
Metadata::Array(arr) => list_converter(arr),
Metadata::Object(obj) => dict_converter(obj),
}
}
}