use ordermap::OrderMap;
use std::hash::Hash;
use parser::Spanning;
use ast::{InputValue, ToInputValue};
#[derive(Debug, PartialEq)]
#[allow(missing_docs)]
pub enum Value {
Null,
Int(i32),
Float(f64),
String(String),
Boolean(bool),
List(Vec<Value>),
Object(OrderMap<String, Value>),
}
impl Value {
pub fn null() -> Value {
Value::Null
}
pub fn int(i: i32) -> Value {
Value::Int(i)
}
pub fn float(f: f64) -> Value {
Value::Float(f)
}
pub fn string<T: AsRef<str>>(s: T) -> Value {
Value::String(s.as_ref().to_owned())
}
pub fn boolean(b: bool) -> Value {
Value::Boolean(b)
}
pub fn list(l: Vec<Value>) -> Value {
Value::List(l)
}
pub fn object<K>(o: OrderMap<K, Value>) -> Value
where
K: Into<String> + Eq + Hash,
{
Value::Object(o.into_iter().map(|(k, v)| (k.into(), v)).collect())
}
pub fn is_null(&self) -> bool {
match *self {
Value::Null => true,
_ => false,
}
}
pub fn as_float_value(&self) -> Option<&f64> {
match *self {
Value::Float(ref f) => Some(f),
_ => None,
}
}
pub fn as_object_value(&self) -> Option<&OrderMap<String, Value>> {
match *self {
Value::Object(ref o) => Some(o),
_ => None,
}
}
pub fn as_mut_object_value(&mut self) -> Option<&mut OrderMap<String, Value>> {
match *self {
Value::Object(ref mut o) => Some(o),
_ => None,
}
}
pub fn as_list_value(&self) -> Option<&Vec<Value>> {
match *self {
Value::List(ref l) => Some(l),
_ => None,
}
}
pub fn as_string_value(&self) -> Option<&str> {
match *self {
Value::String(ref s) => Some(s),
_ => None,
}
}
}
impl ToInputValue for Value {
fn to_input_value(&self) -> InputValue {
match *self {
Value::Null => InputValue::Null,
Value::Int(i) => InputValue::Int(i),
Value::Float(f) => InputValue::Float(f),
Value::String(ref s) => InputValue::String(s.clone()),
Value::Boolean(b) => InputValue::Boolean(b),
Value::List(ref l) => {
InputValue::List(l.iter().map(|x| Spanning::unlocated(x.to_input_value())).collect())
}
Value::Object(ref o) => InputValue::Object(
o.iter()
.map(|(k, v)| {
(Spanning::unlocated(k.clone()), Spanning::unlocated(v.to_input_value()))
})
.collect(),
),
}
}
}
impl<'a> From<&'a str> for Value {
fn from(s: &'a str) -> Value {
Value::string(s)
}
}
impl From<String> for Value {
fn from(s: String) -> Value {
Value::string(s)
}
}
impl From<bool> for Value {
fn from(b: bool) -> Value {
Value::boolean(b)
}
}
impl From<i32> for Value {
fn from(i: i32) -> Value {
Value::int(i)
}
}
impl From<f64> for Value {
fn from(f: f64) -> Value {
Value::float(f)
}
}
impl<T> From<Option<T>> for Value where Value: From<T> {
fn from(v: Option<T>) -> Value {
match v {
Some(v) => Value::from(v),
None => Value::null()
}
}
}
#[macro_export]
macro_rules! graphql_value {
([ $($arg:tt),* $(,)* ]) => {
$crate::Value::list(vec![
$( graphql_value!($arg), )*
])
};
({ $($key:tt : $val:tt ),* $(,)* }) => {
$crate::Value::object(vec![
$( ($key, graphql_value!($val)), )*
].into_iter().collect())
};
(None) => ($crate::Value::null());
($e:expr) => ($crate::Value::from($e))
}
#[cfg(test)]
mod tests {
use super::Value;
#[test]
fn value_macro_string() {
assert_eq!(
graphql_value!("test"),
Value::string("test")
);
}
#[test]
fn value_macro_int() {
assert_eq!(
graphql_value!(123),
Value::int(123)
);
}
#[test]
fn value_macro_float() {
assert_eq!(
graphql_value!(123.5),
Value::float(123.5)
);
}
#[test]
fn value_macro_boolean() {
assert_eq!(
graphql_value!(false),
Value::boolean(false)
);
}
#[test]
fn value_macro_option() {
assert_eq!(
graphql_value!(Some("test")),
Value::string("test")
);
assert_eq!(
graphql_value!(None),
Value::null()
);
}
#[test]
fn value_macro_list() {
assert_eq!(
graphql_value!([ 123, "Test", false ]),
Value::list(vec![
Value::int(123),
Value::string("Test"),
Value::boolean(false),
])
);
assert_eq!(
graphql_value!([ 123, [ 456 ], 789 ]),
Value::list(vec![
Value::int(123),
Value::list(vec![ Value::int(456) ]),
Value::int(789),
])
);
}
#[test]
fn value_macro_object() {
assert_eq!(
graphql_value!({ "key": 123, "next": true }),
Value::object(vec![
("key", Value::int(123)),
("next", Value::boolean(true)),
].into_iter().collect())
);
}
}