use serde::{Serialize, Serializer};
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_kv<S, K, V>(serializer: &mut S,
state: &mut S::MapState,
key: K,
value: V) -> Result<(), S::Error>
where S: Serializer,
K: Serialize,
V: Serialize {
try!(serializer.serialize_map_key(state, key));
serializer.serialize_map_value(state, value)
}
pub fn serialize_map_optional_kv<S, K, V>(serializer: &mut S,
state: &mut S::MapState,
key: K,
value: &Option<V>) -> Result<(), S::Error>
where S: Serializer,
K: Serialize,
V: Serialize {
match value {
&Some(ref x) => {
try!(serialize_map_kv(serializer, state, key, x));
}
&None => ()
}
Ok(())
}
#[derive(Debug, Default)]
pub struct NoOuter;
impl MergeSerialize for NoOuter {
fn merge_serialize<S>(&self,
_: &mut S,
_: &mut S::MapState) -> Result<(), S::Error>
where S: Serializer {
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: &mut S) -> Result<(), S::Error>
where S: Serializer {
let mut state = try!(serializer.serialize_map(None));
try!(serialize_map_kv(serializer, &mut state, &self.field, &self.inner));
try!(self.outer.merge_serialize(serializer, &mut state));
serializer.serialize_map_end(state)
}
}
pub trait MergeSerialize {
fn merge_serialize<S>(&self,
serializer: &mut S,
state: &mut S::MapState) -> Result<(), S::Error>
where S: Serializer;
}
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::Serializer;
use super::{FieldBased, MergeSerialize, NoOuter, serialize_map_kv};
#[derive(Serialize)]
struct TestOptions {
opt_a: i64,
opt_b: f64
}
impl MergeSerialize for TestOptions {
fn merge_serialize<S>(&self,
serializer: &mut S,
state: &mut S::MapState) -> Result<(), S::Error>
where S: Serializer {
try!(serialize_map_kv(serializer, state, "opt_a", self.opt_a));
serialize_map_kv(serializer, state, "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);
}
}