use serde::{Serialize, Serializer, Deserialize, Deserializer};
use ::codec::{SerializeValue, DeserializeValue};
use super::Expr;
#[derive(Debug)]
pub struct Value<T>(ValueInner<T>);
impl<T> Value<T> {
pub fn new(value: T) -> Value<T> {
Value(ValueInner::Value(value))
}
pub fn reference<S: Into<String>>(id: S) -> Value<T> {
Value(ValueInner::Ref(id.into()))
}
pub fn expression(expr: Expr) -> Value<T> {
Value(ValueInner::Expr(expr))
}
pub fn as_value(&self) -> Option<&T> {
if let ValueInner::Value(ref value) = self.0 {
Some(value)
} else {
None
}
}
pub fn as_reference(&self) -> Option<&str> {
if let ValueInner::Ref(ref ref_id) = self.0 {
Some(ref_id)
} else {
None
}
}
pub fn as_expression(&self) -> Option<&Expr> {
if let ValueInner::Expr(ref expr) = self.0 {
Some(expr)
} else {
None
}
}
}
impl<T: Default> Default for Value<T> {
fn default() -> Value<T> {
Value::new(T::default())
}
}
impl<T> From<T> for Value<T> {
fn from(value: T) -> Value<T> {
Value::new(value)
}
}
#[derive(Debug)]
enum ValueInner<T> {
Value(T),
Ref(String),
Expr(Expr)
}
#[derive(Serialize, Deserialize)]
struct SerdeRef<'a> {
#[serde(rename = "Ref", borrow)]
id: &'a str
}
#[derive(Serialize)]
#[serde(untagged)]
enum SerializeValueProxy<'a, T: 'a + SerializeValue> {
#[serde(serialize_with="SerializeValue::serialize_borrow")]
Value(&'a T),
#[serde(borrow)]
Ref(SerdeRef<'a>),
#[serde(serialize_with="SerializeValue::serialize_borrow")]
Expr(&'a Expr),
}
#[derive(Deserialize)]
#[serde(untagged)]
enum DeserializeValueProxy<'a, T: DeserializeValue> {
#[serde(deserialize_with="DeserializeValue::deserialize")]
Value(T),
#[serde(borrow)]
Ref(SerdeRef<'a>),
#[serde(deserialize_with="DeserializeValue::deserialize")]
Expr(Expr)
}
impl<T: SerializeValue> Serialize for Value<T> {
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
let proxy = match self.0 {
ValueInner::Value(ref literal) => SerializeValueProxy::Value(literal),
ValueInner::Ref(ref id) => SerializeValueProxy::Ref(SerdeRef { id }),
ValueInner::Expr(ref expr) => SerializeValueProxy::Expr(expr)
};
Serialize::serialize(&proxy, s)
}
}
impl<'de, T: DeserializeValue> Deserialize<'de> for Value<T> {
fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
Deserialize::deserialize(d).map(|proxy| {
let inner = match proxy {
DeserializeValueProxy::Value(t) => ValueInner::Value(t),
DeserializeValueProxy::Ref(SerdeRef { id }) => ValueInner::Ref(id.to_owned()),
DeserializeValueProxy::Expr(expr) => ValueInner::Expr(expr)
};
Value(inner)
})
}
}
#[cfg(test)]
mod tests {
use super::{Value, Expr};
#[test]
fn serialize_u32() {
let value = Value::new(42u32);
assert_eq!("\"42\"", ::serde_json::to_string(&value).unwrap());
}
#[test]
fn serialize_u32_string() {
let value = ::serde_json::from_str::<Value<u32>>("\"42\"").unwrap();
assert_eq!(&42, value.as_value().unwrap());
}
#[test]
fn serialize_u32_number() {
let value = ::serde_json::from_str::<Value<u32>>("42").unwrap();
assert_eq!(&42, value.as_value().unwrap());
}
#[test]
fn serialize_ref() {
let value = Value::<String>::reference("foo");
assert_eq!("{\"Ref\":\"foo\"}", ::serde_json::to_string(&value).unwrap());
}
#[test]
fn deserialize_ref() {
let value = ::serde_json::from_str::<Value<String>>("{\"Ref\":\"foo\"}").unwrap();
assert_eq!("foo", value.as_reference().unwrap());
}
#[test]
fn serialize_fn_join() {
let value = Value::<String>::expression(Expr::Join {
delimiter: ":".to_owned(),
values: vec![
Value::new("a".to_owned()),
Value::new("b".to_owned()),
Value::new("c".to_owned())
]
});
assert_eq!("{\"Fn::Join\":[\":\",[\"a\",\"b\",\"c\"]]}",
::serde_json::to_string(&value).unwrap());
}
}