1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
use std::collections::HashMap;
use std::hash::Hash;

use rustc_serialize::json::{ToJson, Json};

use parser::Spanning;
use ast::{InputValue, ToInputValue};

/// Serializable value returned from query and field execution.
///
/// Used by the execution engine and resolvers to build up the response
/// structure. Similar to the `Json` type found in the serialize crate.
///
/// It is also similar to the `InputValue` type, but can not contain enum
/// values or variables. Also, lists and objects do not contain any location
/// information since they are generated by resolving fields and values rather
/// than parsing a source query.
#[derive(Debug, PartialEq)]
#[allow(missing_docs)]
pub enum Value {
    Null,
    Int(i64),
    Float(f64),
    String(String),
    Boolean(bool),
    List(Vec<Value>),
    Object(HashMap<String, Value>),
}

impl Value {
    // CONSTRUCTORS

    /// Construct a null value.
    pub fn null() -> Value { Value::Null }

    /// Construct an integer value.
    pub fn int(i: i64) -> Value { Value::Int(i) }

    /// Construct a floating point value.
    pub fn float(f: f64) -> Value { Value::Float(f) }

    /// Construct a string value.
    pub fn string<T: AsRef<str>>(s: T) -> Value { Value::String(s.as_ref().to_owned()) }

    /// Construct a boolean value.
    pub fn boolean(b: bool) -> Value { Value::Boolean(b) }

    /// Construct a list value.
    pub fn list(l: Vec<Value>) -> Value { Value::List(l) }

    /// Construct an object value.
    pub fn object<K>(o: HashMap<K, Value>) -> Value
        where K: AsRef<str> + Eq + Hash
    {
        Value::Object(
            o.into_iter().map(|(k, v)| (k.as_ref().to_owned(), v)).collect()
        )
    }

    // DISCRIMINATORS

    /// Does this value represent null?
    pub fn is_null(&self) -> bool {
        match *self {
            Value::Null => true,
            _ => false,
        }
    }

    /// View the underlying object value, if present.
    pub fn as_object_value(&self) -> Option<&HashMap<String, Value>> {
        match *self {
            Value::Object(ref o) => Some(o),
            _ => None,
        }
    }

    /// View the underlying list value, if present.
    pub fn as_list_value(&self) -> Option<&Vec<Value>> {
        match *self {
            Value::List(ref l) => Some(l),
            _ => None,
        }
    }

    /// View the underlying string value, if present.
    pub fn as_string_value(&self) -> Option<&str> {
        match *self {
            Value::String(ref s) => Some(s),
            _ => None,
        }
    }
}

impl ToJson for Value {
    fn to_json(&self) -> Json {
        match *self {
            Value::Null => Json::Null,
            Value::Int(i) => Json::I64(i),
            Value::Float(f) => Json::F64(f),
            Value::String(ref s) => Json::String(s.clone()),
            Value::Boolean(b) => Json::Boolean(b),
            Value::List(ref l) => Json::Array(l.iter().map(|x| x.to_json()).collect()),
            Value::Object(ref o) => Json::Object(o.iter().map(|(k,v)| (k.clone(), v.to_json())).collect()),
       }
    }
}

impl ToInputValue for Value {
    fn to(&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())).collect()),
            Value::Object(ref o) => InputValue::Object(o.iter().map(|(k,v)|
                (Spanning::unlocated(k.clone()), Spanning::unlocated(v.to()))).collect()),
        }
    }
}