use std::fmt;
use crate::ast::ConstValue;
use serde::Deserialize;
use serde::de::{Deserializer, Error, SeqAccess, Visitor};
pub(crate) fn deserialize_node_array<'de, D>(
deserializer: D,
) -> Result<Vec<crate::ast::Node>, D::Error>
where
D: Deserializer<'de>,
{
#[derive(serde::Deserialize)]
#[serde(untagged)]
enum NodeOrError {
Node(Box<crate::ast::Node>),
Error(serde::de::IgnoredAny),
}
struct NodeArray;
impl<'de> Visitor<'de> for NodeArray {
type Value = Vec<crate::ast::Node>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("Vec<Node>")
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
{
let mut values = Vec::with_capacity(seq.size_hint().unwrap_or_default());
while let Some(value) = seq.next_element()? {
if let NodeOrError::Node(value) = value {
values.push(*value);
}
}
Ok(values)
}
}
deserializer.deserialize_seq(NodeArray)
}
pub(crate) fn deserialize_node_array_opt<'de, D>(
deserializer: D,
) -> Result<Option<Vec<crate::ast::Node>>, D::Error>
where
D: Deserializer<'de>,
{
struct NodeArrayOpt;
impl<'de> Visitor<'de> for NodeArrayOpt {
type Value = Option<Vec<crate::ast::Node>>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("Option<Vec<Node>>")
}
fn visit_none<E>(self) -> Result<Self::Value, E>
where
E: Error,
{
Ok(None)
}
fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: Deserializer<'de>,
{
let value = deserialize_node_array(deserializer)?;
Ok(Some(value))
}
}
deserializer.deserialize_option(NodeArrayOpt)
}
pub(crate) fn deserialize_nested_string<'de, D>(deserializer: D) -> Result<String, D::Error>
where
D: Deserializer<'de>,
{
struct NestedString;
impl<'de> Visitor<'de> for NestedString {
type Value = String;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("String")
}
fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
where
V: serde::de::MapAccess<'de>,
{
if let Some(key) = map.next_key::<String>()? {
if key.ne("sval") {
return Err(Error::missing_field("sval"));
}
let value = map.next_value::<String>()?;
Ok(value)
} else {
Err(Error::missing_field("sval"))
}
}
}
deserializer.deserialize_map(NestedString)
}
pub(crate) fn deserialize_nested_string_opt<'de, D>(
deserializer: D,
) -> Result<Option<String>, D::Error>
where
D: Deserializer<'de>,
{
struct NestedStringOpt;
impl<'de> Visitor<'de> for NestedStringOpt {
type Value = Option<String>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("Option<String>")
}
fn visit_none<E>(self) -> Result<Self::Value, E>
where
E: Error,
{
Ok(None)
}
fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: Deserializer<'de>,
{
let value = deserialize_nested_string(deserializer)?;
Ok(Some(value))
}
}
deserializer.deserialize_option(NestedStringOpt)
}
impl<'de> serde::Deserialize<'de> for ConstValue {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct ConstValueVisitor;
impl<'de> Visitor<'de> for ConstValueVisitor {
type Value = ConstValue;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("ConnectorTopics")
}
fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
where
V: serde::de::MapAccess<'de>,
{
#[derive(Deserialize)]
struct BoolValue {
#[serde(default)]
boolval: bool,
}
#[derive(Deserialize)]
struct IntValue {
#[serde(default)]
ival: i64,
}
#[derive(Deserialize)]
struct FloatValue {
fval: String,
}
#[derive(Deserialize)]
struct StringValue {
sval: String,
}
#[derive(Deserialize)]
struct BitStringValue {
bsval: String,
}
fn maybe_location<'de, V>(mut inner: V) -> Result<(), V::Error>
where
V: serde::de::MapAccess<'de>,
{
if let Some(_location) = inner.next_key::<String>()? {
let _pos = inner.next_value::<i32>()?;
}
Ok(())
}
if let Some(key) = map.next_key::<String>()? {
match key.as_str() {
"boolval" => {
let value = map.next_value::<BoolValue>()?;
maybe_location(map)?;
Ok(ConstValue::Bool(value.boolval))
}
"ival" => {
let value = map.next_value::<IntValue>()?;
maybe_location(map)?;
Ok(ConstValue::Integer(value.ival))
}
"fval" => {
let value = map.next_value::<FloatValue>()?;
maybe_location(map)?;
Ok(ConstValue::Float(value.fval))
}
"sval" => {
let value = map.next_value::<StringValue>()?;
maybe_location(map)?;
Ok(ConstValue::String(value.sval))
}
"bsval" => {
let value = map.next_value::<BitStringValue>()?;
maybe_location(map)?;
Ok(ConstValue::BitString(value.bsval))
}
"isnull" => {
let null = map.next_value::<bool>()?;
maybe_location(map)?;
if null {
Ok(ConstValue::Null)
} else {
Ok(ConstValue::NotNull)
}
}
unknown => Err(Error::unknown_field(
unknown,
&["boolval", "ival", "fval", "sval", "bsval", "isnull"],
)),
}
} else {
Err(Error::custom("expected value"))
}
}
}
deserializer.deserialize_map(ConstValueVisitor {})
}
}
#[cfg(test)]
mod tests {
use crate::ast::ConstValue;
use crate::ast::Node;
use serde::Deserialize;
#[derive(Deserialize)]
pub struct Nodes {
#[serde(deserialize_with = "crate::serde::deserialize_node_array")]
values: Vec<Node>,
}
#[derive(Deserialize)]
pub struct OptionalNodes {
#[serde(deserialize_with = "crate::serde::deserialize_node_array_opt", default)]
values: Option<Vec<Node>>,
}
#[test]
fn it_can_deserialize_a_node_array() {
let json = "{ \"values\": [{ \"A_Const\": { \"ival\": { \"ival\": 10 }, \"location\": 253 } }, {}] }";
let nodes: Nodes = serde_json::from_str(json).unwrap();
assert_eq!(1, nodes.values.len());
assert!(matches!(
nodes.values[0],
Node::A_Const(ConstValue::Integer(10))
))
}
#[test]
fn it_can_deserialize_an_optional_node_array_with_missing_property() {
let json = "{ }";
let nodes: OptionalNodes = serde_json::from_str(json).unwrap();
assert!(nodes.values.is_none());
}
#[test]
fn it_can_deserialize_an_optional_node_array_with_null() {
let json = "{ \"values\": null }";
let nodes: OptionalNodes = serde_json::from_str(json).unwrap();
assert!(nodes.values.is_none());
}
#[test]
fn it_can_deserialize_an_optional_node_array_with_some() {
let json = "{ \"values\": [{ \"Boolean\": { \"boolval\": false } }, {}] }";
let nodes: OptionalNodes = serde_json::from_str(json).unwrap();
assert!(nodes.values.is_some());
let values = nodes.values.unwrap();
assert_eq!(1, values.len());
assert!(matches!(
values[0],
Node::Boolean {
boolval: Some(false)
}
))
}
#[test]
fn it_can_deserialize_an_optional_node_array_with_some_empty_array() {
let json = "{\"values\":[{}]}";
let nodes: OptionalNodes = serde_json::from_str(json).unwrap();
assert!(nodes.values.is_some());
let values = nodes.values.unwrap();
assert_eq!(0, values.len());
}
#[test]
fn it_can_deserialize_const_with_location() {
let tests = [
(
"{ \"ival\": { \"ival\": 10 }, \"location\": 253 }",
ConstValue::Integer(10),
),
(
"{ \"boolval\": { \"boolval\": true }, \"location\": 253 }",
ConstValue::Bool(true),
),
(
"{ \"fval\": { \"fval\": \"1.23\" }, \"location\": 253 }",
ConstValue::Float("1.23".to_string()),
),
(
"{ \"sval\": { \"sval\": \"hello\" }, \"location\": 253 }",
ConstValue::String("hello".to_string()),
),
(
"{ \"bsval\": { \"bsval\": \"b123\" }, \"location\": 253 }",
ConstValue::BitString("b123".to_string()),
),
];
for (json, test) in &tests {
let deserialized: ConstValue =
serde_json::from_str(json).expect("Failed to deserialize");
assert_eq!(deserialized, *test, "Failed to deserialize: {}", json);
}
}
#[test]
fn it_can_deserialize_const_without_location() {
let tests = [
("{ \"ival\": { \"ival\": 10 } }", ConstValue::Integer(10)),
(
"{ \"boolval\": { \"boolval\": true } }",
ConstValue::Bool(true),
),
(
"{ \"fval\": { \"fval\": \"1.23\" } }",
ConstValue::Float("1.23".to_string()),
),
(
"{ \"sval\": { \"sval\": \"hello\" } }",
ConstValue::String("hello".to_string()),
),
(
"{ \"bsval\": { \"bsval\": \"b123\" } }",
ConstValue::BitString("b123".to_string()),
),
];
for (json, test) in &tests {
let deserialized: ConstValue =
serde_json::from_str(json).expect("Failed to deserialize");
assert_eq!(deserialized, *test, "Failed to deserialize: {}", json);
}
}
#[test]
fn it_can_deserialize_a_const() {
let null_json = "{ \"A_Const\": { \"isnull\": true, \"location\": 323 } }";
let null_const: Node = serde_json::from_str(null_json).expect("Failed to deserialize");
let Node::A_Const(ConstValue::Null) = null_const else {
panic!("Expected A_Const node: {:#?}", null_const);
};
let ival_json = "{ \"A_Const\": { \"ival\": { \"ival\": 1 }, \"location\": 123 } }";
let ival_const: Node = serde_json::from_str(ival_json).expect("Failed to deserialize");
let Node::A_Const(ConstValue::Integer(val)) = ival_const else {
panic!("Expected A_Const node: {:#?}", ival_const);
};
assert_eq!(val, 1);
}
#[test]
fn it_can_parse_an_empty_constant() {
let json = "{ \"A_Const\": { \"ival\": {}, \"location\": 38 } }";
let node: Node = serde_json::from_str(json).unwrap();
assert!(
matches!(node, Node::A_Const(ConstValue::Integer(0))),
"Expected integer constant to default to 0"
);
}
#[test]
fn it_can_parse_empty_nodes() {
let json = "{\"Integer\":{}}";
let node: Node = serde_json::from_str(json).unwrap();
assert!(
matches!(node, Node::Integer { ival: None }),
"Expected integer node to default to None"
);
}
#[test]
fn it_can_parse_directly_nested_strings() {
#[derive(Deserialize)]
struct Test {
#[serde(
deserialize_with = "crate::serde::deserialize_nested_string_opt",
default
)]
extname: Option<String>,
}
let json = "{\"extname\":{\"sval\":\"a\"}}";
let node: Test = serde_json::from_str(json).unwrap();
assert_eq!(node.extname, Some("a".to_string()));
let json = "{}";
let node: Test = serde_json::from_str(json).unwrap();
assert_eq!(node.extname, None);
}
}