use crate::{
cenum,
types::{
serde::{
builder::BoltPathBuilder,
element::{ElementDataDeserializer, ElementDataKey},
BoltKind,
},
BoltList, BoltPath, BoltType,
},
DeError, Indices, Nodes, Path, Relationships,
};
use std::{fmt, result::Result};
use serde::{
de::{
value::{MapDeserializer, SeqDeserializer},
DeserializeSeed, Deserializer, EnumAccess, Error, IntoDeserializer, Visitor,
},
forward_to_deserialize_any, Deserialize,
};
impl<'de> Deserialize<'de> for Path {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
BoltPath::deserialize(deserializer).map(Path::new)
}
}
impl BoltPath {
pub(crate) fn to<'this, T>(&'this self) -> Result<T, DeError>
where
T: Deserialize<'this>,
{
T::deserialize(self.into_deserializer())
}
}
cenum!(Fields {
Nodes,
Relationships,
Indices,
});
impl<'de> Deserialize<'de> for BoltPath {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
const FIELDS: &[&str] = &["nodes", "relationships", "indices"];
struct BoltPathVisitor;
impl<'de> Visitor<'de> for BoltPathVisitor {
type Value = BoltPath;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("struct BoltPath")
}
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
where
A: ::serde::de::MapAccess<'de>,
{
let mut path = BoltPathBuilder::default();
while let Some(key) = map.next_key::<&str>()? {
match key {
"nodes" => path.nodes(|| {
Ok(BoltList {
value: map.next_value::<Nodes<BoltType>>()?.0,
})
})?,
"relationships" => path.relations(|| {
Ok(BoltList {
value: map.next_value::<Relationships<BoltType>>()?.0,
})
})?,
"indices" => path.indices(|| {
Ok(BoltList {
value: map.next_value::<Indices<BoltType>>()?.0,
})
})?,
otherwise => return Err(Error::unknown_field(otherwise, FIELDS)),
}
}
path.build()
}
}
deserializer.deserialize_struct("BoltPath", FIELDS, BoltPathVisitor)
}
}
pub struct BoltPathVisitor;
impl<'de> Visitor<'de> for BoltPathVisitor {
type Value = BoltPath;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("struct BoltPath")
}
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
where
A: ::serde::de::MapAccess<'de>,
{
let mut path = BoltPathBuilder::default();
while let Some(key) = map.next_key::<ElementDataKey>()? {
match key {
ElementDataKey::Nodes => path.nodes(|| map.next_value())?,
ElementDataKey::Relationships => path.relations(|| map.next_value())?,
ElementDataKey::Indices => path.indices(|| map.next_value())?,
otherwise => {
return Err(Error::unknown_field(
otherwise.name(),
&["nodes", "relationships", "indices"],
))
}
}
}
path.build()
}
}
pub struct BoltPathDeserializer<'de>(&'de BoltPath);
impl<'de> BoltPathDeserializer<'de> {
fn new(node: &'de BoltPath) -> Self {
Self(node)
}
}
impl<'de> IntoDeserializer<'de, DeError> for &'de BoltList {
type Deserializer = SeqDeserializer<std::slice::Iter<'de, BoltType>, DeError>;
fn into_deserializer(self) -> Self::Deserializer {
SeqDeserializer::new(self.value.iter())
}
}
impl<'de> Deserializer<'de> for BoltPathDeserializer<'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(
[
("nodes", &self.0.nodes),
("relationships", &self.0.rels),
("indices", &self.0.indices),
]
.into_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 BoltPathDeserializer<'de> {
type Error = DeError;
type Variant = ElementDataDeserializer<'de, &'de BoltPath>;
fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error>
where
V: DeserializeSeed<'de>,
{
let kind = BoltKind::Path;
let val = seed.deserialize(kind.into_deserializer())?;
Ok((val, ElementDataDeserializer::new(self.0)))
}
}
impl<'de> IntoDeserializer<'de, DeError> for &'de BoltPath {
type Deserializer = BoltPathDeserializer<'de>;
fn into_deserializer(self) -> Self::Deserializer {
BoltPathDeserializer::new(self)
}
}
#[cfg(test)]
mod tests {
use std::fmt::Debug;
use crate::{
types::{BoltInteger, BoltNode, BoltString, BoltType, BoltUnboundedRelation},
Node, UnboundedRelation,
};
use super::*;
fn test_path() -> BoltPath {
let alice = BoltNode::new(
BoltInteger::new(42),
BoltList::from(vec![BoltType::from("Person")]),
[("name".into(), "Alice".into()), ("age".into(), 42.into())]
.into_iter()
.collect(),
);
let bob = BoltNode::new(
BoltInteger::new(1337),
BoltList::from(vec![BoltType::from("Person")]),
[("name".into(), "Bob".into()), ("age".into(), 84.into())]
.into_iter()
.collect(),
);
let rel = BoltUnboundedRelation::new(
BoltInteger::new(84),
BoltString::from("KNOWS"),
[("since".into(), 2017.into())].into_iter().collect(),
);
BoltPath {
nodes: BoltList::from(vec![BoltType::Node(alice), BoltType::Node(bob)]),
rels: BoltList::from(vec![BoltType::UnboundedRelation(rel)]),
indices: BoltList::from(vec![BoltType::from(1), BoltType::from(1)]),
}
}
#[test]
fn path_nodes() {
#[derive(Clone, Debug, PartialEq, Eq, Deserialize)]
struct Person {
name: String,
age: u8,
}
test_extract_path(Nodes(vec![
Person {
name: "Alice".into(),
age: 42,
},
Person {
name: "Bob".into(),
age: 84,
},
]));
}
#[test]
fn path_rels() {
#[derive(Clone, Debug, PartialEq, Eq, Deserialize)]
struct Knows {
since: u16,
}
test_extract_path(Relationships(vec![Knows { since: 2017 }]));
}
#[test]
fn path_indices() {
test_extract_path(Indices(vec![1, 1]));
}
#[test]
fn path_all() {
#[derive(Clone, Debug, PartialEq, Eq, Deserialize)]
struct Person {
name: String,
age: u8,
}
#[derive(Clone, Debug, PartialEq, Eq, Deserialize)]
struct Knows {
since: u16,
}
#[derive(Clone, Debug, PartialEq, Eq, Deserialize)]
struct Path {
nodes: Nodes<Person>,
rels: Relationships<Knows>,
indices: Indices,
}
test_extract_path(Path {
nodes: Nodes(vec![
Person {
name: "Alice".into(),
age: 42,
},
Person {
name: "Bob".into(),
age: 84,
},
]),
rels: Relationships(vec![Knows { since: 2017 }]),
indices: Indices(vec![1, 1]),
});
}
fn test_extract_path<T: Debug + PartialEq + for<'a> Deserialize<'a>>(expected: T) {
let path = test_path();
let actual = path.to::<T>().unwrap();
assert_eq!(actual, expected);
}
#[test]
fn path_to_bolt_type() {
let path = test_path();
let actual = path.to::<BoltType>().unwrap();
assert_eq!(actual, BoltType::Path(path));
}
#[test]
fn path_to_bolt_path() {
let path = test_path();
let actual = path.to::<BoltPath>().unwrap();
assert_eq!(actual, path);
}
#[test]
fn path_to_path() {
let path = test_path();
let actual = path.to::<Path>().unwrap();
let nodes = path.nodes().into_iter().map(Node::new).collect::<Vec<_>>();
let relationships = path
.rels()
.into_iter()
.map(UnboundedRelation::new)
.collect::<Vec<_>>();
assert_eq!(actual.nodes(), nodes);
assert_eq!(actual.rels(), relationships);
assert_eq!(actual.indices(), vec![1, 1]);
}
}