use std::{collections::HashSet, hash::{Hash, Hasher}};
use anyhow::Result;
use serde::{Deserialize, Serialize};
#[derive(Clone, Serialize, Deserialize)]
#[serde(transparent)]
pub struct TagDescriptor {
pub json: serde_json::Value,
}
#[derive(Clone, Serialize, Deserialize)]
pub struct ObjectDescriptor {
pub tags: HashSet<TagDescriptor>,
pub json: serde_json::Value,
}
impl ObjectDescriptor {
pub fn new<Q: Into<TagDescriptor>, S: IntoIterator<Item = Q>, T: Into<serde_json::value::Value>>(tags: S, json: T) -> ObjectDescriptor {
let json: serde_json::value::Value = json.into();
ObjectDescriptor { tags: tags.into_iter().map(|descriptor| descriptor.into()).collect(), json }
}
pub fn json_to_string(&self) -> String {
self.json.to_string()
}
pub fn tags_to_strings(&self) -> Vec<String> {
self.tags.iter().map(|tag| tag.json_to_string()).collect()
}
pub fn from_json_strings(tags: Vec<String>, json: String) -> Result<ObjectDescriptor> {
let tags: HashSet<TagDescriptor> = tags.into_iter().map(TagDescriptor::from_json_string).collect::<Result<_, anyhow::Error>>()?;
let json: serde_json::value::Value = serde_json::from_str(json.as_str())?;
Ok(ObjectDescriptor { tags, json })
}
}
impl TagDescriptor {
pub fn new<T: Into<serde_json::value::Value>>(value: T) -> TagDescriptor {
let json: serde_json::value::Value = value.into();
TagDescriptor { json }
}
pub fn json_to_string(&self) -> String {
self.json.to_string()
}
pub fn from_json_string(json: String) -> Result<TagDescriptor> {
let json: serde_json::value::Value = serde_json::from_str(json.as_str())?;
Ok(TagDescriptor { json })
}
}
use itertools::Itertools;
pub(crate) fn hash_serde_json_value<H: Hasher>(value: &serde_json::Value, state: &mut H) {
match value {
serde_json::Value::Null => {
state.write_u8(0);
}
serde_json::Value::Bool(value) => {
state.write_u8(1);
state.write_u8(u8::from(*value));
}
serde_json::Value::Number(value) => {
if value.is_f64() {
state.write_u8(2);
state.write_u64(value.as_f64().unwrap() as u64); } else if value.is_i64() {
state.write_u8(3);
state.write_i64(value.as_i64().unwrap());
} else if value.is_u64() {
state.write_u8(4);
state.write_u64(value.as_u64().unwrap());
} else {
panic!()
};
}
serde_json::Value::String(value) => {
state.write_u8(5);
state.write(value.as_bytes());
}
serde_json::Value::Array(value) => {
state.write_u8(6);
for value in value {
hash_serde_json_value(value, state);
}
}
serde_json::Value::Object(value) => {
state.write_u8(7);
for key in value.keys().cloned().sorted() {
state.write(key.as_bytes());
hash_serde_json_value(value.get(&key).unwrap(), state);
}
}
}
}
impl<T: Into<serde_json::value::Value>> From<T> for TagDescriptor {
fn from(value: T) -> Self {
let json: serde_json::value::Value = value.into();
TagDescriptor { json }
}
}
impl<Q: Into<serde_json::value::Value>, S: IntoIterator<Item = Q>, T: Into<serde_json::value::Value>> From<(S, T)> for ObjectDescriptor {
fn from(value: (S, T)) -> Self {
let json: serde_json::value::Value = value.1.into();
ObjectDescriptor { tags: value.0.into_iter().map(|descriptor| TagDescriptor { json: descriptor.into() }).collect(), json }
}
}
impl<T: Into<serde_json::value::Value>> From<(T,)> for ObjectDescriptor {
fn from(value: (T,)) -> Self {
let json: serde_json::value::Value = value.0.into();
ObjectDescriptor { tags: HashSet::new(), json }
}
}
impl From<serde_json::value::Value> for ObjectDescriptor {
fn from(value: serde_json::value::Value) -> Self {
ObjectDescriptor { tags: HashSet::new(), json: value }
}
}
impl PartialEq for TagDescriptor {
fn eq(&self, other: &Self) -> bool {
self.json == other.json
}
}
impl PartialEq for ObjectDescriptor {
fn eq(&self, other: &Self) -> bool {
self.json == other.json && self.tags.symmetric_difference(&other.tags).count() == 0
}
}
impl Eq for ObjectDescriptor {}
impl Eq for TagDescriptor {}
impl Hash for ObjectDescriptor {
fn hash<H: Hasher>(&self, state: &mut H) {
hash_serde_json_value(&self.json, state);
}
}
impl Hash for TagDescriptor {
fn hash<H: Hasher>(&self, state: &mut H) {
hash_serde_json_value(&self.json, state);
}
}
impl std::fmt::Debug for ObjectDescriptor {
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if fmt.alternate() {
fmt.write_str("ObjectDescriptor:")?;
}
fmt.write_str("[")?;
for (i, tag) in self.tags.iter().enumerate() {
tag.fmt(fmt)?;
if i < self.tags.len() - 1 {
fmt.write_str(",")?;
}
}
fmt.write_str("]:")?;
fmt.write_fmt(format_args!("{}", self.json))
}
}
impl std::fmt::Display for ObjectDescriptor {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
f.write_fmt(format_args!("{}", self.json))
}
}
impl std::fmt::Debug for TagDescriptor {
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if fmt.alternate() {
fmt.write_str("TagDescriptor:")?;
}
fmt.write_fmt(format_args!("{}", self.json))
}
}
impl std::fmt::Display for TagDescriptor {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
f.write_fmt(format_args!("{}", self.json))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn tag_descriptor_can_be_serialized_and_deserialized_with_json() {
let serialized1 = b"{}";
let descriptor = serde_json::from_slice::<TagDescriptor>(serialized1).unwrap();
let mut serialized2: Vec<u8> = vec![];
descriptor.serialize(&mut serde_json::Serializer::new(&mut serialized2)).unwrap();
assert_eq!(serialized2, serialized1);
}
#[test]
fn tag_descriptor_can_be_constructed_from_whatever_is_convertible_to_json() {
let _x: TagDescriptor = "aoeu".to_string().into();
let _y: TagDescriptor = serde_json::json!({"aaa": 123}).to_string().into();
}
#[test]
fn object_descriptor_can_be_serialized_and_deserialized_with_json() {
let serialized1 = b"{\"tags\":[\"bbbb\",\"aaa\"],\"json\":\"{}\"}";
let descriptor = serde_json::from_slice::<ObjectDescriptor>(serialized1).unwrap();
let mut serialized2: Vec<u8> = vec![];
descriptor.serialize(&mut serde_json::Serializer::new(&mut serialized2)).unwrap();
let descriptor2 = serde_json::from_slice::<ObjectDescriptor>(serialized2.as_slice()).unwrap();
assert_eq!(descriptor, descriptor2);
}
}