From 4de024a6423782885c1c3bc6c3a9b790f32d799e Mon Sep 17 00:00:00 2001 From: Gareth Johnson Date: Fri, 23 Feb 2024 11:03:59 +0000 Subject: [PATCH 1/5] Update dis_macro and add ref dis injectiond --- .../encoding/decode_ref_dis_factory.rs | 65 +++++++++++++++++++ src/haystack/encoding/json/decode.rs | 41 +++++++++--- src/haystack/encoding/mod.rs | 2 + src/haystack/val/dict.rs | 6 +- src/haystack/val/dis_macro.rs | 13 ++-- 5 files changed, 111 insertions(+), 16 deletions(-) create mode 100644 src/haystack/encoding/decode_ref_dis_factory.rs diff --git a/src/haystack/encoding/decode_ref_dis_factory.rs b/src/haystack/encoding/decode_ref_dis_factory.rs new file mode 100644 index 0000000..a15c835 --- /dev/null +++ b/src/haystack/encoding/decode_ref_dis_factory.rs @@ -0,0 +1,65 @@ +// Copyright (C) 2020 - 2024, J2 Innovations + +use std::borrow::Cow; +use std::sync::RwLock; + +/// Enables display values to be injected into decoded Ref objects. +/// +/// This is used to handle the case whereby pre-calculated display +/// names for Refs need to be utilized when encoding/decoding haystack data. +/// +/// Please note, the return type is a `Cow`. At some point we'll make `Ref` a little +/// more flexible regarding how it holds its display data and hence its usage. +type RefDisFactoryFunc<'a> = Box) -> Option> + Send + Sync>; + +/// Holds the Ref factory function used for creating Refs. +static REF_DIS_FACTORY_FUNC: RwLock> = RwLock::new(None); + +/// Get a ref's display name value from any registered factory. +pub fn get_ref_dis_from_factory<'a>(val: &str, dis: Option<&'a str>) -> Option> { + if let Some(func) = REF_DIS_FACTORY_FUNC.read().unwrap().as_ref() { + func(val, dis) + } else { + dis.map(Cow::Borrowed) + } +} + +/// Set the factory function for getting ref display name values. +pub fn set_ref_dis_factory(factory_fn: Option>) { + *REF_DIS_FACTORY_FUNC.write().unwrap() = factory_fn; +} + +#[cfg(test)] +mod test { + use std::{borrow::Cow, sync::Mutex}; + + use super::{get_ref_dis_from_factory, set_ref_dis_factory}; + + // Use a mutex to prevent unit tests from interfering with each other. One of the tests + // sets some global data so they can overlap. + static MUTEX: Mutex<()> = Mutex::new(()); + + #[test] + fn make_ref_returns_ref() { + let _ = MUTEX.lock(); + + let dis = get_ref_dis_from_factory("a", Some("c")); + + assert_eq!(dis, Some(Cow::Borrowed("c"))); + } + + #[test] + fn make_ref_from_factory_returns_ref() { + let _ = MUTEX.lock(); + + let factory_fn = Box::new(|_: &str, _: Option<&str>| Some(Cow::Owned(String::from("c")))); + + set_ref_dis_factory(Some(factory_fn)); + + let dis = get_ref_dis_from_factory("a", Some("b")); + + assert_eq!(dis, Some(Cow::Borrowed("c"))); + + set_ref_dis_factory(None); + } +} diff --git a/src/haystack/encoding/json/decode.rs b/src/haystack/encoding/json/decode.rs index 7f789e2..0bbdb20 100644 --- a/src/haystack/encoding/json/decode.rs +++ b/src/haystack/encoding/json/decode.rs @@ -3,6 +3,7 @@ //! //! Implement Hayson decoding //! +use crate::encoding::decode_ref_dis_factory::get_ref_dis_from_factory; use crate::haystack::val::{ Column, Coord, Date, DateTime, Dict, Grid, HaystackDict, List, Marker, Na, Number, Ref, Remove, Str, Symbol, Time, Uri, Value as HVal, XStr, @@ -103,7 +104,19 @@ impl<'de> Deserialize<'de> for Ref { fn deserialize>(deserializer: D) -> Result { let val = deserializer.deserialize_any(HValVisitor)?; match val { - HVal::Ref(val) => Ok(val), + HVal::Ref(val) => { + let dis = get_ref_dis_from_factory(val.value.as_str(), val.dis.as_deref()) + .map(|v| v.to_string()); + + Ok(if dis == val.dis { + val + } else { + Ref { + value: val.value, + dis, + } + }) + } _ => Err(D::Error::custom("Invalid Hayson Ref")), } } @@ -377,16 +390,26 @@ fn parse_number(dict: &Dict) -> Result { fn parse_ref(dict: &Dict) -> Result { match dict.get_str("val") { Some(val) => match dict.get_str("dis") { - Some(dis) => Ok(Ref { - value: val.value.clone(), - dis: Some(dis.value.clone()), + Some(dis) => { + let dis = get_ref_dis_from_factory(val.value.as_str(), Some(dis.as_str())) + .map(|val| val.to_string()); + + Ok(Ref { + value: val.value.clone(), + dis, + } + .into()) } - .into()), - None => Ok(Ref { - value: val.value.clone(), - dis: None, + None => { + let dis = + get_ref_dis_from_factory(val.value.as_str(), None).map(|val| val.to_string()); + + Ok(Ref { + value: val.value.clone(), + dis, + } + .into()) } - .into()), }, None => Err(JsonErr::custom("Missing or invalid 'val'")), } diff --git a/src/haystack/encoding/mod.rs b/src/haystack/encoding/mod.rs index eeb7bac..6a32bb0 100644 --- a/src/haystack/encoding/mod.rs +++ b/src/haystack/encoding/mod.rs @@ -7,3 +7,5 @@ pub mod json; #[cfg(feature = "zinc")] pub mod zinc; + +pub mod decode_ref_dis_factory; diff --git a/src/haystack/val/dict.rs b/src/haystack/val/dict.rs index e27e729..9ebd99b 100644 --- a/src/haystack/val/dict.rs +++ b/src/haystack/val/dict.rs @@ -386,7 +386,11 @@ where if let Some(val) = dict.get("disMacro") { return if let Value::Str(val) = val { - dis_macro(&val.value, |val| dict.get(val), get_localized) + dis_macro( + &val.value, + |val| dict.get(val).map(Cow::Borrowed), + get_localized, + ) } else { decode_str_from_value(val) }; diff --git a/src/haystack/val/dis_macro.rs b/src/haystack/val/dis_macro.rs index 6e3ed07..32ce63a 100644 --- a/src/haystack/val/dis_macro.rs +++ b/src/haystack/val/dis_macro.rs @@ -9,7 +9,7 @@ use regex::{Captures, Regex, Replacer}; /// values in a display macro string. struct DisReplacer<'a, 'b, GetValueFunc, GetLocalizedFunc> where - GetValueFunc: Fn(&str) -> Option<&'a Value>, + GetValueFunc: Fn(&str) -> Option>, GetLocalizedFunc: Fn(&str) -> Option>, { get_value: &'b GetValueFunc, @@ -20,7 +20,7 @@ where impl<'a, 'b, GetValueFunc, GetLocalizedFunc> Replacer for DisReplacer<'a, 'b, GetValueFunc, GetLocalizedFunc> where - GetValueFunc: Fn(&str) -> Option<&'a Value>, + GetValueFunc: Fn(&str) -> Option>, GetLocalizedFunc: Fn(&str) -> Option>, { fn replace_append(&mut self, caps: &Captures<'_>, dst: &mut String) { @@ -29,9 +29,9 @@ where // Replace $tag or ${tag} if let Some(cap_match) = caps.get(2).or_else(|| caps.get(4)) { if let Some(value) = (self.get_value)(cap_match.as_str()) { - if let Value::Ref(val) = value { + if let Value::Ref(val) = value.as_ref() { dst.push_str(val.dis.as_ref().unwrap_or(&val.value)); - } else if let Value::Str(val) = value { + } else if let Value::Str(val) = value.as_ref() { dst.push_str(&val.value); } else { dst.push_str(&value.to_string()); @@ -70,7 +70,7 @@ pub fn dis_macro<'a, GetValueFunc, GetLocalizedFunc>( get_localized: GetLocalizedFunc, ) -> Cow<'a, str> where - GetValueFunc: Fn(&str) -> Option<&'a Value>, + GetValueFunc: Fn(&str) -> Option>, GetLocalizedFunc: Fn(&str) -> Option>, { // Cache the regular expression in memory so it doesn't need to compile on each invocation. @@ -103,7 +103,7 @@ mod test { static DICT: OnceLock = OnceLock::new(); - fn dict_cb<'a>(name: &str) -> Option<&'a Value> { + fn dict_cb<'a>(name: &str) -> Option> { DICT.get_or_init(|| { dict![ "equipRef" => Value::make_ref("ref"), @@ -114,6 +114,7 @@ mod test { ] }) .get(name) + .map(|val| Cow::Borrowed(val)) } fn i18n_cb<'a>(name: &str) -> Option> { From 52a30cff4c8f3afa1877bbdc5afe30f07ec6dc45 Mon Sep 17 00:00:00 2001 From: Gareth Johnson Date: Fri, 23 Feb 2024 11:11:12 +0000 Subject: [PATCH 2/5] Update comments --- src/haystack/encoding/decode_ref_dis_factory.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/haystack/encoding/decode_ref_dis_factory.rs b/src/haystack/encoding/decode_ref_dis_factory.rs index a15c835..a27e139 100644 --- a/src/haystack/encoding/decode_ref_dis_factory.rs +++ b/src/haystack/encoding/decode_ref_dis_factory.rs @@ -6,10 +6,10 @@ use std::sync::RwLock; /// Enables display values to be injected into decoded Ref objects. /// /// This is used to handle the case whereby pre-calculated display -/// names for Refs need to be utilized when encoding/decoding haystack data. +/// names for Refs need to be utilized when decoding haystack data. /// /// Please note, the return type is a `Cow`. At some point we'll make `Ref` a little -/// more flexible regarding how it holds its display data and hence its usage. +/// more flexible regarding how it holds its display data. type RefDisFactoryFunc<'a> = Box) -> Option> + Send + Sync>; /// Holds the Ref factory function used for creating Refs. From c5405848aaa11c0be388220a9dd97646de85bb25 Mon Sep 17 00:00:00 2001 From: Gareth Johnson Date: Fri, 23 Feb 2024 11:56:47 +0000 Subject: [PATCH 3/5] Add to encoder --- src/haystack/encoding/decode_ref_dis_factory.rs | 4 ++-- src/haystack/encoding/json/encode.rs | 17 ++++++++++++----- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/haystack/encoding/decode_ref_dis_factory.rs b/src/haystack/encoding/decode_ref_dis_factory.rs index a27e139..221bded 100644 --- a/src/haystack/encoding/decode_ref_dis_factory.rs +++ b/src/haystack/encoding/decode_ref_dis_factory.rs @@ -3,10 +3,10 @@ use std::borrow::Cow; use std::sync::RwLock; -/// Enables display values to be injected into decoded Ref objects. +/// Enables display values to be injected into encoded/decoded Ref objects. /// /// This is used to handle the case whereby pre-calculated display -/// names for Refs need to be utilized when decoding haystack data. +/// names for Refs need to be utilized when encoding/decoding haystack data. /// /// Please note, the return type is a `Cow`. At some point we'll make `Ref` a little /// more flexible regarding how it holds its display data. diff --git a/src/haystack/encoding/json/encode.rs b/src/haystack/encoding/json/encode.rs index c232635..84f9818 100644 --- a/src/haystack/encoding/json/encode.rs +++ b/src/haystack/encoding/json/encode.rs @@ -6,9 +6,12 @@ use chrono::SecondsFormat; -use crate::haystack::val::{ - Column, Coord, Date, DateTime, Dict, Grid, Marker, Na, Number, Ref, Remove, Symbol, Time, Uri, - Value as HVal, XStr, +use crate::{ + encoding::decode_ref_dis_factory::get_ref_dis_from_factory, + haystack::val::{ + Column, Coord, Date, DateTime, Dict, Grid, Marker, Na, Number, Ref, Remove, Symbol, Time, + Uri, Value as HVal, XStr, + }, }; use serde::ser::{Serialize, SerializeMap, SerializeSeq, Serializer}; @@ -54,8 +57,12 @@ impl Serialize for Ref { let mut map = serializer.serialize_map(Some(if self.dis.is_none() { 2 } else { 3 }))?; map.serialize_entry("_kind", "ref")?; map.serialize_entry("val", &self.value)?; - if self.dis.is_some() { - let dis = self.dis.clone(); + + let dis = get_ref_dis_from_factory(self.value.as_str(), self.dis.as_deref()) + .map(|v| v.to_string()) + .or_else(|| self.dis.clone()); + + if dis.is_some() { map.serialize_entry("dis", &dis)?; } map.end() From 9d9de257ae075d0e9976cf110ef2f5049bed76de Mon Sep 17 00:00:00 2001 From: Gareth Johnson Date: Sat, 24 Feb 2024 10:49:04 +0000 Subject: [PATCH 4/5] PR feedback --- src/haystack/encoding/json/decode.rs | 41 +++++++++------------------- src/haystack/encoding/json/encode.rs | 2 +- 2 files changed, 14 insertions(+), 29 deletions(-) diff --git a/src/haystack/encoding/json/decode.rs b/src/haystack/encoding/json/decode.rs index 0bbdb20..d7d558c 100644 --- a/src/haystack/encoding/json/decode.rs +++ b/src/haystack/encoding/json/decode.rs @@ -105,15 +105,14 @@ impl<'de> Deserialize<'de> for Ref { let val = deserializer.deserialize_any(HValVisitor)?; match val { HVal::Ref(val) => { - let dis = get_ref_dis_from_factory(val.value.as_str(), val.dis.as_deref()) - .map(|v| v.to_string()); + let dis = get_ref_dis_from_factory(val.value.as_str(), val.dis.as_deref()); - Ok(if dis == val.dis { + Ok(if dis.as_deref() == val.dis.as_deref() { val } else { Ref { value: val.value, - dis, + dis: dis.map(|d| d.into_owned()), } }) } @@ -388,31 +387,17 @@ fn parse_number(dict: &Dict) -> Result { } fn parse_ref(dict: &Dict) -> Result { - match dict.get_str("val") { - Some(val) => match dict.get_str("dis") { - Some(dis) => { - let dis = get_ref_dis_from_factory(val.value.as_str(), Some(dis.as_str())) - .map(|val| val.to_string()); - - Ok(Ref { - value: val.value.clone(), - dis, - } - .into()) - } - None => { - let dis = - get_ref_dis_from_factory(val.value.as_str(), None).map(|val| val.to_string()); - - Ok(Ref { - value: val.value.clone(), - dis, - } - .into()) + dict.get_str("val") + .map(|val| { + let dis_str = dict.get_str("dis").map(|d| d.as_str()); + let dis = get_ref_dis_from_factory(&val.value, dis_str).map(|val| val.into_owned()); + Ref { + value: val.value.clone(), + dis, } - }, - None => Err(JsonErr::custom("Missing or invalid 'val'")), - } + .into() + }) + .ok_or_else(|| JsonErr::custom("Missing or invalid 'val'")) } fn parse_symbol(dict: &Dict) -> Result { diff --git a/src/haystack/encoding/json/encode.rs b/src/haystack/encoding/json/encode.rs index 84f9818..105cf93 100644 --- a/src/haystack/encoding/json/encode.rs +++ b/src/haystack/encoding/json/encode.rs @@ -59,7 +59,7 @@ impl Serialize for Ref { map.serialize_entry("val", &self.value)?; let dis = get_ref_dis_from_factory(self.value.as_str(), self.dis.as_deref()) - .map(|v| v.to_string()) + .map(|v| v.into_owned()) .or_else(|| self.dis.clone()); if dis.is_some() { From 52c65affa2645a9ab7883b6e4d4007a8a56d908a Mon Sep 17 00:00:00 2001 From: Gareth Johnson Date: Mon, 26 Feb 2024 14:12:38 +0000 Subject: [PATCH 5/5] Remove ref display name injection + make decoder visitor public --- .../encoding/decode_ref_dis_factory.rs | 65 ----------------- src/haystack/encoding/json/decode.rs | 72 +++++++++---------- src/haystack/encoding/json/encode.rs | 17 ++--- src/haystack/encoding/mod.rs | 2 - 4 files changed, 37 insertions(+), 119 deletions(-) delete mode 100644 src/haystack/encoding/decode_ref_dis_factory.rs diff --git a/src/haystack/encoding/decode_ref_dis_factory.rs b/src/haystack/encoding/decode_ref_dis_factory.rs deleted file mode 100644 index 221bded..0000000 --- a/src/haystack/encoding/decode_ref_dis_factory.rs +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (C) 2020 - 2024, J2 Innovations - -use std::borrow::Cow; -use std::sync::RwLock; - -/// Enables display values to be injected into encoded/decoded Ref objects. -/// -/// This is used to handle the case whereby pre-calculated display -/// names for Refs need to be utilized when encoding/decoding haystack data. -/// -/// Please note, the return type is a `Cow`. At some point we'll make `Ref` a little -/// more flexible regarding how it holds its display data. -type RefDisFactoryFunc<'a> = Box) -> Option> + Send + Sync>; - -/// Holds the Ref factory function used for creating Refs. -static REF_DIS_FACTORY_FUNC: RwLock> = RwLock::new(None); - -/// Get a ref's display name value from any registered factory. -pub fn get_ref_dis_from_factory<'a>(val: &str, dis: Option<&'a str>) -> Option> { - if let Some(func) = REF_DIS_FACTORY_FUNC.read().unwrap().as_ref() { - func(val, dis) - } else { - dis.map(Cow::Borrowed) - } -} - -/// Set the factory function for getting ref display name values. -pub fn set_ref_dis_factory(factory_fn: Option>) { - *REF_DIS_FACTORY_FUNC.write().unwrap() = factory_fn; -} - -#[cfg(test)] -mod test { - use std::{borrow::Cow, sync::Mutex}; - - use super::{get_ref_dis_from_factory, set_ref_dis_factory}; - - // Use a mutex to prevent unit tests from interfering with each other. One of the tests - // sets some global data so they can overlap. - static MUTEX: Mutex<()> = Mutex::new(()); - - #[test] - fn make_ref_returns_ref() { - let _ = MUTEX.lock(); - - let dis = get_ref_dis_from_factory("a", Some("c")); - - assert_eq!(dis, Some(Cow::Borrowed("c"))); - } - - #[test] - fn make_ref_from_factory_returns_ref() { - let _ = MUTEX.lock(); - - let factory_fn = Box::new(|_: &str, _: Option<&str>| Some(Cow::Owned(String::from("c")))); - - set_ref_dis_factory(Some(factory_fn)); - - let dis = get_ref_dis_from_factory("a", Some("b")); - - assert_eq!(dis, Some(Cow::Borrowed("c"))); - - set_ref_dis_factory(None); - } -} diff --git a/src/haystack/encoding/json/decode.rs b/src/haystack/encoding/json/decode.rs index d7d558c..e344458 100644 --- a/src/haystack/encoding/json/decode.rs +++ b/src/haystack/encoding/json/decode.rs @@ -3,7 +3,6 @@ //! //! Implement Hayson decoding //! -use crate::encoding::decode_ref_dis_factory::get_ref_dis_from_factory; use crate::haystack::val::{ Column, Coord, Date, DateTime, Dict, Grid, HaystackDict, List, Marker, Na, Number, Ref, Remove, Str, Symbol, Time, Uri, Value as HVal, XStr, @@ -20,7 +19,7 @@ use std::fmt; /// Hayson Marker deserializer impl<'de> Deserialize<'de> for Marker { fn deserialize>(deserializer: D) -> Result { - let val = deserializer.deserialize_any(HValVisitor)?; + let val = deserializer.deserialize_any(JsonValueDecoderVisitor)?; if val.is_marker() { Ok(Marker) } else { @@ -34,7 +33,7 @@ type JsonErr = serde_json::Error; /// Hayson Remove deserializer impl<'de> Deserialize<'de> for Remove { fn deserialize>(deserializer: D) -> Result { - let val = deserializer.deserialize_any(HValVisitor)?; + let val = deserializer.deserialize_any(JsonValueDecoderVisitor)?; if val.is_remove() { Ok(Remove) } else { @@ -46,7 +45,7 @@ impl<'de> Deserialize<'de> for Remove { /// Hayson Remove deserializer impl<'de> Deserialize<'de> for Na { fn deserialize>(deserializer: D) -> Result { - let val = deserializer.deserialize_any(HValVisitor)?; + let val = deserializer.deserialize_any(JsonValueDecoderVisitor)?; if val.is_na() { Ok(Na) } else { @@ -58,7 +57,7 @@ impl<'de> Deserialize<'de> for Na { /// Hayson Number deserializer impl<'de> Deserialize<'de> for Number { fn deserialize>(deserializer: D) -> Result { - let val = deserializer.deserialize_any(HValVisitor)?; + let val = deserializer.deserialize_any(JsonValueDecoderVisitor)?; match val { HVal::Number(val) => Ok(val), _ => Err(D::Error::custom("Invalid Hayson Number")), @@ -69,7 +68,7 @@ impl<'de> Deserialize<'de> for Number { /// Hayson Date deserializer impl<'de> Deserialize<'de> for Date { fn deserialize>(deserializer: D) -> Result { - let val = deserializer.deserialize_any(HValVisitor)?; + let val = deserializer.deserialize_any(JsonValueDecoderVisitor)?; match val { HVal::Date(val) => Ok(val), _ => Err(D::Error::custom("Invalid Hayson Date")), @@ -80,7 +79,7 @@ impl<'de> Deserialize<'de> for Date { /// Hayson Time deserializer impl<'de> Deserialize<'de> for Time { fn deserialize>(deserializer: D) -> Result { - let val = deserializer.deserialize_any(HValVisitor)?; + let val = deserializer.deserialize_any(JsonValueDecoderVisitor)?; match val { HVal::Time(val) => Ok(val), _ => Err(D::Error::custom("Invalid Hayson Time")), @@ -91,7 +90,7 @@ impl<'de> Deserialize<'de> for Time { /// Hayson DateTime deserializer impl<'de> Deserialize<'de> for DateTime { fn deserialize>(deserializer: D) -> Result { - let val = deserializer.deserialize_any(HValVisitor)?; + let val = deserializer.deserialize_any(JsonValueDecoderVisitor)?; match val { HVal::DateTime(val) => Ok(val), _ => Err(D::Error::custom("Invalid Hayson DateTime")), @@ -102,20 +101,9 @@ impl<'de> Deserialize<'de> for DateTime { /// Hayson Ref deserializer impl<'de> Deserialize<'de> for Ref { fn deserialize>(deserializer: D) -> Result { - let val = deserializer.deserialize_any(HValVisitor)?; + let val = deserializer.deserialize_any(JsonValueDecoderVisitor)?; match val { - HVal::Ref(val) => { - let dis = get_ref_dis_from_factory(val.value.as_str(), val.dis.as_deref()); - - Ok(if dis.as_deref() == val.dis.as_deref() { - val - } else { - Ref { - value: val.value, - dis: dis.map(|d| d.into_owned()), - } - }) - } + HVal::Ref(val) => Ok(val), _ => Err(D::Error::custom("Invalid Hayson Ref")), } } @@ -124,7 +112,7 @@ impl<'de> Deserialize<'de> for Ref { /// Hayson Uri deserializer impl<'de> Deserialize<'de> for Uri { fn deserialize>(deserializer: D) -> Result { - let val = deserializer.deserialize_any(HValVisitor)?; + let val = deserializer.deserialize_any(JsonValueDecoderVisitor)?; match val { HVal::Uri(val) => Ok(val), _ => Err(D::Error::custom("Invalid Hayson Uri")), @@ -135,7 +123,7 @@ impl<'de> Deserialize<'de> for Uri { /// Hayson Symbol deserializer impl<'de> Deserialize<'de> for Symbol { fn deserialize>(deserializer: D) -> Result { - let val = deserializer.deserialize_any(HValVisitor)?; + let val = deserializer.deserialize_any(JsonValueDecoderVisitor)?; match val { HVal::Symbol(val) => Ok(val), _ => Err(D::Error::custom("Invalid Hayson Symbol")), @@ -146,7 +134,7 @@ impl<'de> Deserialize<'de> for Symbol { /// Hayson Str deserializer impl<'de> Deserialize<'de> for Str { fn deserialize>(deserializer: D) -> Result { - let val = deserializer.deserialize_any(HValVisitor)?; + let val = deserializer.deserialize_any(JsonValueDecoderVisitor)?; match val { HVal::Str(val) => Ok(val), _ => Err(D::Error::custom("Invalid Hayson Str")), @@ -157,7 +145,7 @@ impl<'de> Deserialize<'de> for Str { /// Hayson Coord deserializer impl<'de> Deserialize<'de> for Coord { fn deserialize>(deserializer: D) -> Result { - let val = deserializer.deserialize_any(HValVisitor)?; + let val = deserializer.deserialize_any(JsonValueDecoderVisitor)?; match val { HVal::Coord(val) => Ok(val), _ => Err(D::Error::custom("Invalid Hayson Coord")), @@ -168,7 +156,7 @@ impl<'de> Deserialize<'de> for Coord { /// Hayson XStr deserializer impl<'de> Deserialize<'de> for XStr { fn deserialize>(deserializer: D) -> Result { - let val = deserializer.deserialize_any(HValVisitor)?; + let val = deserializer.deserialize_any(JsonValueDecoderVisitor)?; match val { HVal::XStr(val) => Ok(val), _ => Err(D::Error::custom("Invalid Hayson XStr")), @@ -179,7 +167,7 @@ impl<'de> Deserialize<'de> for XStr { /// Hayson XStr deserializer impl<'de> Deserialize<'de> for Dict { fn deserialize>(deserializer: D) -> Result { - let val = deserializer.deserialize_any(HValVisitor)?; + let val = deserializer.deserialize_any(JsonValueDecoderVisitor)?; match val { HVal::Dict(val) => Ok(val), _ => Err(D::Error::custom("Invalid Hayson Dict")), @@ -190,7 +178,7 @@ impl<'de> Deserialize<'de> for Dict { /// Hayson Grid deserializer impl<'de> Deserialize<'de> for Grid { fn deserialize>(deserializer: D) -> Result { - let val = deserializer.deserialize_any(HValVisitor)?; + let val = deserializer.deserialize_any(JsonValueDecoderVisitor)?; match val { HVal::Grid(val) => Ok(val), _ => Err(D::Error::custom("Invalid Hayson Grid")), @@ -201,13 +189,13 @@ impl<'de> Deserialize<'de> for Grid { /// Hayson deserializer impl<'de> Deserialize<'de> for HVal { fn deserialize>(deserializer: D) -> Result { - deserializer.deserialize_any(HValVisitor) + deserializer.deserialize_any(JsonValueDecoderVisitor) } } -struct HValVisitor; +pub struct JsonValueDecoderVisitor; /// Visitor for Hayson elements -impl<'de> Visitor<'de> for HValVisitor { +impl<'de> Visitor<'de> for JsonValueDecoderVisitor { type Value = HVal; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { @@ -387,17 +375,21 @@ fn parse_number(dict: &Dict) -> Result { } fn parse_ref(dict: &Dict) -> Result { - dict.get_str("val") - .map(|val| { - let dis_str = dict.get_str("dis").map(|d| d.as_str()); - let dis = get_ref_dis_from_factory(&val.value, dis_str).map(|val| val.into_owned()); - Ref { + match dict.get_str("val") { + Some(val) => match dict.get_str("dis") { + Some(dis) => Ok(Ref { value: val.value.clone(), - dis, + dis: Some(dis.value.clone()), } - .into() - }) - .ok_or_else(|| JsonErr::custom("Missing or invalid 'val'")) + .into()), + None => Ok(Ref { + value: val.value.clone(), + dis: None, + } + .into()), + }, + None => Err(JsonErr::custom("Missing or invalid 'val'")), + } } fn parse_symbol(dict: &Dict) -> Result { diff --git a/src/haystack/encoding/json/encode.rs b/src/haystack/encoding/json/encode.rs index 105cf93..c232635 100644 --- a/src/haystack/encoding/json/encode.rs +++ b/src/haystack/encoding/json/encode.rs @@ -6,12 +6,9 @@ use chrono::SecondsFormat; -use crate::{ - encoding::decode_ref_dis_factory::get_ref_dis_from_factory, - haystack::val::{ - Column, Coord, Date, DateTime, Dict, Grid, Marker, Na, Number, Ref, Remove, Symbol, Time, - Uri, Value as HVal, XStr, - }, +use crate::haystack::val::{ + Column, Coord, Date, DateTime, Dict, Grid, Marker, Na, Number, Ref, Remove, Symbol, Time, Uri, + Value as HVal, XStr, }; use serde::ser::{Serialize, SerializeMap, SerializeSeq, Serializer}; @@ -57,12 +54,8 @@ impl Serialize for Ref { let mut map = serializer.serialize_map(Some(if self.dis.is_none() { 2 } else { 3 }))?; map.serialize_entry("_kind", "ref")?; map.serialize_entry("val", &self.value)?; - - let dis = get_ref_dis_from_factory(self.value.as_str(), self.dis.as_deref()) - .map(|v| v.into_owned()) - .or_else(|| self.dis.clone()); - - if dis.is_some() { + if self.dis.is_some() { + let dis = self.dis.clone(); map.serialize_entry("dis", &dis)?; } map.end() diff --git a/src/haystack/encoding/mod.rs b/src/haystack/encoding/mod.rs index 6a32bb0..eeb7bac 100644 --- a/src/haystack/encoding/mod.rs +++ b/src/haystack/encoding/mod.rs @@ -7,5 +7,3 @@ pub mod json; #[cfg(feature = "zinc")] pub mod zinc; - -pub mod decode_ref_dis_factory;