use crate::{
types::{
serde::{
builder::{BoltNodeBuilder, Id},
element::{ElementDataDeserializer, ElementDataKey},
BoltKind,
},
BoltList, BoltNode, BoltString,
},
DeError, Labels, Node,
};
use std::{fmt, result::Result};
use serde::{
de::{
value::MapDeserializer, DeserializeSeed, Deserializer, EnumAccess, Error, IntoDeserializer,
Visitor,
},
forward_to_deserialize_any, Deserialize,
};
impl<'de> Deserialize<'de> for Node {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
BoltNode::deserialize(deserializer).map(Node::new)
}
}
impl BoltNode {
pub(crate) fn to<'this, T>(&'this self) -> Result<T, DeError>
where
T: Deserialize<'this>,
{
T::deserialize(self.into_deserializer())
}
}
impl<'de> Deserialize<'de> for BoltNode {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
const ID: &str = "42.<id>";
const LABELS: &str = "42.<labels>";
struct BoltNodeVisitor;
impl<'de> Visitor<'de> for BoltNodeVisitor {
type Value = BoltNode;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("struct BoltNode")
}
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
where
A: ::serde::de::MapAccess<'de>,
{
let mut builder = BoltNodeBuilder::default();
while let Some(key) = map.next_key::<&str>()? {
match key {
ID => builder.id(|| map.next_value::<Id>().map(|i| i.0))?,
LABELS => {
builder.labels(|| map.next_value::<Labels<BoltList>>().map(|l| l.0))?
}
otherwise => builder
.insert(|| Ok((BoltString::from(otherwise), map.next_value()?)))?,
}
}
let node = builder.build()?;
Ok(node)
}
}
deserializer.deserialize_struct("BoltNode", &[ID, LABELS], BoltNodeVisitor)
}
}
pub struct BoltNodeVisitor;
impl<'de> Visitor<'de> for BoltNodeVisitor {
type Value = BoltNode;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("struct BoltNode")
}
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
where
A: ::serde::de::MapAccess<'de>,
{
let mut builder = BoltNodeBuilder::default();
while let Some(key) = map.next_key::<ElementDataKey>()? {
match key {
ElementDataKey::Id => builder.id(|| map.next_value())?,
ElementDataKey::Labels => builder.labels(|| map.next_value())?,
ElementDataKey::Properties => builder.properties(|| map.next_value())?,
otherwise => {
return Err(Error::unknown_field(
otherwise.name(),
&["Id", "Labels", "Properties"],
))
}
}
}
let node = builder.build()?;
Ok(node)
}
}
pub struct BoltNodeDeserializer<'de>(&'de BoltNode);
impl<'de> BoltNodeDeserializer<'de> {
fn new(node: &'de BoltNode) -> Self {
Self(node)
}
}
impl<'de> Deserializer<'de> for BoltNodeDeserializer<'de> {
type Error = DeError;
fn deserialize_map<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_map(MapDeserializer::new(self.0.properties.value.iter()))
}
fn deserialize_struct<V>(
self,
_name: &'static str,
fields: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
ElementDataDeserializer::new(self.0).deserialize_outer_struct(fields, visitor)
}
fn deserialize_newtype_struct<V>(
self,
name: &'static str,
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
ElementDataDeserializer::new(self.0).deserialize_newtype_struct(name, visitor)
}
fn deserialize_enum<V>(
self,
_name: &'static str,
_variants: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_enum(self)
}
fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
visitor.visit_unit()
}
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: Visitor<'de>,
{
self.deserialize_map(visitor)
}
forward_to_deserialize_any! {
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
bytes byte_buf option unit unit_struct seq tuple tuple_struct identifier
}
}
impl<'de> EnumAccess<'de> for BoltNodeDeserializer<'de> {
type Error = DeError;
type Variant = ElementDataDeserializer<'de, &'de BoltNode>;
fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error>
where
V: DeserializeSeed<'de>,
{
let kind = BoltKind::Node;
let val = seed.deserialize(kind.into_deserializer())?;
Ok((val, ElementDataDeserializer::new(self.0)))
}
}
impl<'de> IntoDeserializer<'de, DeError> for &'de BoltNode {
type Deserializer = BoltNodeDeserializer<'de>;
fn into_deserializer(self) -> Self::Deserializer {
BoltNodeDeserializer::new(self)
}
}
#[cfg(test)]
mod tests {
use std::{
collections::HashSet,
fmt::Debug,
marker::PhantomData,
sync::atomic::{AtomicU32, Ordering},
};
use crate::{
types::{BoltInteger, BoltType},
Id, Keys,
};
use super::*;
use tap::Tap;
fn test_node() -> BoltNode {
let id = BoltInteger::new(1337);
let labels = vec!["Person".into()].into();
let properties = vec![
("name".into(), "Alice".into()),
("age".into(), 42_u16.into()),
]
.into_iter()
.collect();
BoltNode {
id,
labels,
properties,
}
}
#[test]
fn node() {
#[derive(Clone, Debug, PartialEq, Eq, Deserialize)]
struct Person {
name: String,
age: u8,
}
test_extract_node(Person {
name: "Alice".into(),
age: 42,
});
}
#[test]
fn extract_node_with_unit_types() {
#[derive(Clone, Debug, PartialEq, Eq, Deserialize)]
struct Person<T> {
name: String,
age: u8,
_t: PhantomData<T>,
_u: (),
}
test_extract_node(Person {
name: "Alice".to_owned(),
age: 42,
_t: PhantomData::<i32>,
_u: (),
});
}
#[test]
fn extract_missing_properties_with_option() {
#[derive(Clone, Debug, PartialEq, Eq, Deserialize)]
struct Person {
favorite_rust_crate: Option<String>,
}
test_extract_node(Person {
favorite_rust_crate: None,
});
}
#[test]
fn extract_missing_properties_with_default() {
fn favorite_rust_crate() -> String {
"graph".to_owned()
}
#[derive(Clone, Debug, PartialEq, Eq, Deserialize)]
struct Person {
#[serde(default = "favorite_rust_crate")]
favorite_rust_crate: String,
}
let node = test_node();
let actual = node.to::<Person>().unwrap_err();
assert!(matches!(actual, DeError::PropertyMissingButRequired));
}
#[test]
fn extract_node_id() {
test_extract_node_extra(Id(1337));
}
#[test]
fn extract_node_id_with_custom_newtype() {
#[derive(Clone, Debug, PartialEq, Eq, Deserialize)]
struct Id(i16);
test_extract_node_extra(Id(1337));
}
#[test]
fn extract_node_id_with_custom_struct() {
#[derive(Debug, Deserialize)]
struct Id {
id: AtomicU32,
}
impl PartialEq for Id {
fn eq(&self, other: &Self) -> bool {
self.id.load(Ordering::SeqCst) == other.id.load(Ordering::SeqCst)
}
}
test_extract_node_extra(Id { id: 1337.into() });
}
#[test]
fn extract_node_labels() {
test_extract_node_extra(Labels(vec!["Person".to_owned()]));
}
#[test]
fn extract_node_property_custom_labels_collection() {
test_extract_node_extra(Labels([String::from("Person")]));
}
#[test]
fn extract_node_labels_with_custom_newtype() {
#[derive(Clone, Debug, PartialEq, Eq, Deserialize)]
struct Labels([String; 1]);
test_extract_node_extra(Labels(["Person".to_owned()]));
}
#[test]
fn extract_node_labels_with_custom_struct() {
#[derive(Debug, PartialEq, Deserialize)]
struct Labels {
labels: Vec<String>,
}
test_extract_node_extra(Labels {
labels: vec!["Person".to_owned()],
});
}
#[test]
fn extract_node_labels_borrowed() {
#[derive(Clone, Debug, PartialEq, Eq, Deserialize)]
struct Labels<'a>(#[serde(borrow)] Vec<&'a str>);
#[derive(Clone, Debug, PartialEq, Eq, Deserialize)]
struct Person<'a> {
#[serde(borrow)]
labels: Labels<'a>,
name: String,
age: u8,
}
let expected = Person {
labels: Labels(vec!["Person"]),
name: "Alice".to_owned(),
age: 42,
};
let node = test_node();
let actual = node.to::<Person>().unwrap();
assert_eq!(actual, expected);
}
#[test]
fn extract_node_property_keys() {
#[derive(Clone, Debug, PartialEq, Eq, Deserialize)]
struct Person {
keys: Keys,
}
let expected = Person {
keys: Keys(["name".to_owned(), "age".to_owned()].into()),
};
test_extract_node(expected);
}
#[test]
fn extract_node_property_keys_custom_vec() {
#[derive(Clone, Debug, Eq, Deserialize)]
#[serde(transparent)]
struct UnorderedVec(Vec<String>);
impl PartialEq for UnorderedVec {
fn eq(&self, other: &Self) -> bool {
let mut lhs = self.0.clone();
lhs.sort();
let mut rhs = other.0.clone();
rhs.sort();
lhs == rhs
}
}
#[derive(Clone, Debug, PartialEq, Eq, Deserialize)]
struct Person {
keys: Keys<UnorderedVec>,
}
let expected = Person {
keys: Keys(UnorderedVec(vec!["name".to_owned(), "age".to_owned()])),
};
test_extract_node(expected);
}
#[test]
fn extract_node_property_keys_custom_struct() {
#[derive(Clone, Debug, Eq, Deserialize)]
struct Keys {
keys: Vec<String>,
}
impl PartialEq for Keys {
fn eq(&self, other: &Self) -> bool {
let mut lhs = self.keys.clone();
lhs.sort();
let mut rhs = other.keys.clone();
rhs.sort();
lhs == rhs
}
}
#[derive(Clone, Debug, PartialEq, Eq, Deserialize)]
struct Person {
property_keys: Keys,
}
let expected = Person {
property_keys: Keys {
keys: vec!["name".to_owned(), "age".to_owned()],
},
};
test_extract_node(expected);
}
#[test]
fn extract_node_property_keys_borrowed() {
#[derive(Clone, Debug, PartialEq, Eq, Deserialize)]
struct Keys<'a>(#[serde(borrow)] HashSet<&'a str>);
#[derive(Clone, Debug, PartialEq, Eq, Deserialize)]
struct Person<'a> {
#[serde(borrow)]
keys: Keys<'a>,
}
let expected = Person {
keys: Keys(["age", "name"].into()),
};
let node = test_node();
let actual = node.to::<Person>().unwrap();
assert_eq!(actual, expected);
}
fn test_extract_node_extra<T: Debug + PartialEq + for<'a> Deserialize<'a>>(expected: T) {
#[derive(Clone, Debug, PartialEq, Eq, Deserialize)]
struct Person<T> {
extra: T,
name: String,
age: u8,
}
let expected = Person {
extra: expected,
name: "Alice".to_owned(),
age: 42,
};
test_extract_node(expected);
}
fn test_extract_node<Person: Debug + PartialEq + for<'a> Deserialize<'a>>(expected: Person) {
let node = test_node();
let actual = node.to::<Person>().unwrap();
assert_eq!(actual, expected);
}
#[test]
fn test_just_extract_node_extra() {
let node = test_node();
let id = node.to::<Id>().unwrap();
let labels = node.to::<Labels>().unwrap();
let keys = node.to::<Keys>().unwrap();
assert_eq!(id, Id(1337));
assert_eq!(labels, Labels(vec!["Person".to_owned()]));
assert_eq!(keys, Keys(["name".to_owned(), "age".to_owned()].into()));
}
#[test]
fn node_to_bolt_type() {
let node = test_node();
let actual = node.to::<BoltType>().unwrap();
assert_eq!(actual, BoltType::Node(node));
}
#[test]
fn node_to_bolt_node() {
let node = test_node();
let actual = node.to::<BoltNode>().unwrap();
assert_eq!(actual, node);
}
#[test]
fn node_to_node() {
let node = test_node();
let actual = node.to::<Node>().unwrap();
assert_eq!(actual.id(), node.id.value);
assert_eq!(
actual.labels().tap_mut(|v| v.sort_unstable()),
node.labels
.iter()
.map(|l| l.to_string())
.collect::<Vec<_>>()
.tap_mut(|v| v.sort_unstable())
);
assert_eq!(
actual.keys().tap_mut(|v| v.sort_unstable()),
node.properties
.value
.keys()
.map(|k| k.to_string())
.collect::<Vec<_>>()
.tap_mut(|v| v.sort_unstable())
);
}
}