use serde::ser::{Serialize, Serializer, SerializeMap};
pub trait ShouldSkip {
fn should_skip(&self) -> bool;
}
impl<T> ShouldSkip for Option<T> {
fn should_skip(&self) -> bool {
self.is_none()
}
}
pub fn serialize_map_optional_kv<S, K, V>(map_ser: &mut S,
key: K,
value: &Option<V>) -> Result<(), S::Error>
where S: SerializeMap,
K: Serialize,
V: Serialize {
if let &Some(ref x) = value {
map_ser.serialize_entry(&key, x)?;
}
Ok(())
}
#[derive(Debug, Default)]
pub struct NoOuter;
impl MergeSerialize for NoOuter {
fn merge_serialize<S>(&self,
_: &mut S) -> Result<(), S::Error>
where S: SerializeMap {
Ok(())
}
}
#[derive(Debug)]
pub struct FieldBased<F, I, O> {
pub field: F,
pub inner: I,
pub outer: O
}
impl<F, I, O> FieldBased<F, I, O> {
pub fn new(field: F, inner: I, outer: O) -> Self {
FieldBased {
field: field,
inner: inner,
outer: outer
}
}
}
impl<F, I, O> Serialize for FieldBased<F, I, O>
where F: Serialize,
I: Serialize,
O: MergeSerialize {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer {
let mut map = serializer.serialize_map(None)?;
map.serialize_entry(&self.field, &self.inner)?;
self.outer.merge_serialize(&mut map)?;
map.end()
}
}
pub trait MergeSerialize {
fn merge_serialize<S>(&self,
serializer: &mut S) -> Result<(), S::Error>
where S: SerializeMap;
}
macro_rules! add_inner_field {
($n:ident, $f:ident, $t:ty) => (
pub fn $n<T: Into<$t>>(mut self, val: T) -> Self {
self.0.inner.$f = Some(val.into());
self
}
);
}
macro_rules! add_outer_field {
($n:ident, $e:ident, $t:ty) => (
pub fn $n<T: Into<$t>>(mut self, val: T) -> Self {
self.0.outer.$e = Some(val.into());
self
}
)
}
#[cfg(test)]
pub mod tests {
use serde_json;
use serde::ser::SerializeMap;
use super::{FieldBased, MergeSerialize, NoOuter};
#[derive(Serialize)]
struct TestOptions {
opt_a: i64,
opt_b: f64
}
impl MergeSerialize for TestOptions {
fn merge_serialize<S>(&self,
serializer: &mut S) -> Result<(), S::Error>
where S: SerializeMap {
serializer.serialize_entry("opt_a", &self.opt_a)?;
serializer.serialize_entry("opt_b", &self.opt_b)
}
}
#[derive(Serialize)]
struct TestStruct(FieldBased<String, TestOptions, NoOuter>);
impl TestStruct {
fn new(key: String, options: TestOptions) -> Self {
TestStruct(FieldBased::new(key, options, NoOuter))
}
}
#[derive(Serialize)]
struct TestWithOuter(FieldBased<String, TestOptions, TestOptions>);
impl TestWithOuter {
fn new(key: String, options: TestOptions, outer: TestOptions) -> Self {
TestWithOuter(FieldBased::new(key, options, outer))
}
}
#[test]
fn test_simple_field_based() {
let t = TestStruct::new("key".to_owned(),
TestOptions {opt_a: 4i64, opt_b: 3.5f64});
let s = serde_json::to_string(&t).unwrap();
assert_eq!("{\"key\":{\"opt_a\":4,\"opt_b\":3.5}}", s);
}
#[test]
fn test_outer_field_based() {
let t = TestWithOuter::new("key".to_owned(),
TestOptions {opt_a: 8i64, opt_b: 2.5f64},
TestOptions {opt_a: 9i64, opt_b: 1.5f64});
let s = serde_json::to_string(&t).unwrap();
assert_eq!("{\"key\":{\"opt_a\":8,\"opt_b\":2.5},\"opt_a\":9,\"opt_b\":1.5}", s);
}
}