use std::fmt;
use std::collections::HashMap;
use std::hash::Hash;
use std::vec;
use std::slice;
use rustc_serialize::json::{ToJson, Json};
use parser::Spanning;
#[derive(Clone, Eq, PartialEq, Debug)]
pub enum Type {
Named(String),
List(Box<Type>),
NonNullNamed(String),
NonNullList(Box<Type>),
}
#[derive(Clone, PartialEq, Debug)]
#[allow(missing_docs)]
pub enum InputValue {
Null,
Int(i64),
Float(f64),
String(String),
Boolean(bool),
Enum(String),
Variable(String),
List(Vec<Spanning<InputValue>>),
Object(Vec<(Spanning<String>, Spanning<InputValue>)>),
}
#[derive(Clone, PartialEq, Debug)]
pub struct VariableDefinition {
pub var_type: Spanning<Type>,
pub default_value: Option<Spanning<InputValue>>,
}
#[derive(Clone, PartialEq, Debug)]
pub struct Arguments {
pub items: Vec<(Spanning<String>, Spanning<InputValue>)>,
}
#[derive(Clone, PartialEq, Debug)]
pub struct VariableDefinitions {
pub items: Vec<(Spanning<String>, VariableDefinition)>,
}
#[derive(Clone, PartialEq, Debug)]
pub struct Field {
pub alias: Option<Spanning<String>>,
pub name: Spanning<String>,
pub arguments: Option<Spanning<Arguments>>,
pub directives: Option<Vec<Spanning<Directive>>>,
pub selection_set: Option<Vec<Selection>>,
}
#[derive(Clone, PartialEq, Debug)]
pub struct FragmentSpread {
pub name: Spanning<String>,
pub directives: Option<Vec<Spanning<Directive>>>,
}
#[derive(Clone, PartialEq, Debug)]
pub struct InlineFragment {
pub type_condition: Option<Spanning<String>>,
pub directives: Option<Vec<Spanning<Directive>>>,
pub selection_set: Vec<Selection>,
}
#[derive(Clone, PartialEq, Debug)]
#[allow(missing_docs)]
pub enum Selection {
Field(Spanning<Field>),
FragmentSpread(Spanning<FragmentSpread>),
InlineFragment(Spanning<InlineFragment>),
}
#[derive(Clone, PartialEq, Debug)]
pub struct Directive {
pub name: Spanning<String>,
pub arguments: Option<Spanning<Arguments>>,
}
#[derive(Clone, PartialEq, Debug)]
pub enum OperationType {
Query,
Mutation,
}
#[derive(Clone, PartialEq, Debug)]
pub struct Operation {
pub operation_type: OperationType,
pub name: Option<Spanning<String>>,
pub variable_definitions: Option<Spanning<VariableDefinitions>>,
pub directives: Option<Vec<Spanning<Directive>>>,
pub selection_set: Vec<Selection>,
}
#[derive(Clone, PartialEq, Debug)]
pub struct Fragment {
pub name: Spanning<String>,
pub type_condition: Spanning<String>,
pub directives: Option<Vec<Spanning<Directive>>>,
pub selection_set: Vec<Selection>,
}
#[derive(Clone, PartialEq, Debug)]
pub enum Definition {
Operation(Spanning<Operation>),
Fragment(Spanning<Fragment>),
}
pub type Document = Vec<Definition>;
pub trait FromInputValue: Sized {
fn from(v: &InputValue) -> Option<Self>;
}
pub trait ToInputValue: Sized {
fn to(&self) -> InputValue;
}
impl Type {
pub fn name(&self) -> Option<&str> {
match *self {
Type::Named(ref n) | Type::NonNullNamed(ref n) => Some(n),
_ => None
}
}
pub fn innermost_name(&self) -> &str {
match *self {
Type::Named(ref n) | Type::NonNullNamed(ref n) => n,
Type::List(ref l) | Type::NonNullList(ref l) => l.innermost_name(),
}
}
pub fn is_non_null(&self) -> bool {
match *self {
Type::NonNullNamed(_) | Type::NonNullList(_) => true,
_ => false,
}
}
}
impl fmt::Display for Type {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Type::Named(ref n) => write!(f, "{}", n),
Type::NonNullNamed(ref n) => write!(f, "{}!", n),
Type::List(ref t) => write!(f, "[{}]", t),
Type::NonNullList(ref t) => write!(f, "[{}]!", t),
}
}
}
impl InputValue {
pub fn null() -> InputValue { InputValue::Null }
pub fn int(i: i64) -> InputValue { InputValue::Int(i) }
pub fn float(f: f64) -> InputValue { InputValue::Float(f) }
pub fn boolean(b: bool) -> InputValue { InputValue::Boolean(b) }
pub fn string<T: AsRef<str>>(s: T) -> InputValue {
InputValue::String(s.as_ref().to_owned())
}
pub fn enum_value<T: AsRef<str>>(s: T) -> InputValue {
InputValue::Enum(s.as_ref().to_owned())
}
pub fn variable<T: AsRef<str>>(v: T) -> InputValue {
InputValue::Variable(v.as_ref().to_owned())
}
pub fn list(l: Vec<InputValue>) -> InputValue {
InputValue::List(l.into_iter().map(|i| Spanning::unlocated(i)).collect())
}
pub fn parsed_list(l: Vec<Spanning<InputValue>>) -> InputValue {
InputValue::List(l)
}
pub fn object<K>(o: HashMap<K, InputValue>) -> InputValue
where K: AsRef<str> + Eq + Hash
{
InputValue::Object(
o.into_iter()
.map(|(k, v)|
(Spanning::unlocated(k.as_ref().to_owned()), Spanning::unlocated(v)))
.collect()
)
}
pub fn parsed_object(o: Vec<(Spanning<String>, Spanning<InputValue>)>) -> InputValue {
InputValue::Object(o)
}
pub fn from_json(json: Json) -> InputValue {
match json {
Json::I64(i) => InputValue::int(i),
Json::U64(u) => InputValue::float(u as f64),
Json::F64(f) => InputValue::float(f),
Json::String(s) => InputValue::string(s),
Json::Boolean(b) => InputValue::boolean(b),
Json::Array(a) => InputValue::list(a.into_iter().map(InputValue::from_json).collect()),
Json::Object(o) => InputValue::object(o.into_iter().map(|(k,v)| (k, InputValue::from_json(v))).collect()),
Json::Null => InputValue::null(),
}
}
pub fn into_const(self, vars: &HashMap<String, InputValue>) -> InputValue {
match self {
InputValue::Variable(v) => vars.get(&v)
.map_or_else(InputValue::null, Clone::clone),
InputValue::List(l) => InputValue::List(
l.into_iter().map(|s| s.map(|v| v.into_const(vars))).collect()
),
InputValue::Object(o) => InputValue::Object(
o.into_iter().map(|(sk, sv)| (sk, sv.map(|v| v.into_const(vars)))).collect()
),
v => v,
}
}
pub fn convert<T>(&self) -> Option<T> where T: FromInputValue {
<T as FromInputValue>::from(self)
}
pub fn is_null(&self) -> bool {
match *self {
InputValue::Null => true,
_ => false,
}
}
pub fn is_variable(&self) -> bool {
match *self {
InputValue::Variable(_) => true,
_ => false,
}
}
pub fn as_enum_value(&self) -> Option<&str> {
match *self {
InputValue::Enum(ref e) => Some(e),
_ => None,
}
}
pub fn as_int_value(&self) -> Option<i64> {
match *self {
InputValue::Int(i) => Some(i),
_ => None,
}
}
pub fn as_string_value(&self) -> Option<&str> {
match *self {
InputValue::String(ref s) => Some(s),
_ => None,
}
}
pub fn to_object_value(&self) -> Option<HashMap<&str, &InputValue>> {
match *self {
InputValue::Object(ref o) => Some(
o.iter().map(|&(ref sk, ref sv)| (sk.item.as_str(), &sv.item)).collect()),
_ => None,
}
}
pub fn to_list_value(&self) -> Option<Vec<&InputValue>> {
match *self {
InputValue::List(ref l) => Some(l.iter().map(|s| &s.item).collect()),
_ => None,
}
}
pub fn referenced_variables(&self) -> Vec<&str> {
match *self {
InputValue::Variable(ref name) => vec![name],
InputValue::List(ref l) => l.iter().flat_map(|v| v.item.referenced_variables()).collect(),
InputValue::Object(ref obj) => obj.iter().flat_map(|&(_, ref v)| v.item.referenced_variables()).collect(),
_ => vec![],
}
}
pub fn unlocated_eq(&self, other: &InputValue) -> bool {
use InputValue::*;
match (self, other) {
(&Null, &Null) => true,
(&Int(i1), &Int(i2)) => i1 == i2,
(&Float(f1), &Float(f2)) => f1 == f2,
(&String(ref s1), &String(ref s2)) |
(&Enum(ref s1), &Enum(ref s2)) |
(&Variable(ref s1), &Variable(ref s2)) => s1 == s2,
(&Boolean(b1), &Boolean(b2)) => b1 == b2,
(&List(ref l1), &List(ref l2)) =>
l1.iter().zip(l2.iter()).all(|(ref v1, ref v2)| v1.item.unlocated_eq(&v2.item)),
(&Object(ref o1), &Object(ref o2)) =>
o1.len() == o2.len()
&& o1.iter()
.all(|&(ref sk1, ref sv1)| o2.iter().any(
|&(ref sk2, ref sv2)| sk1.item == sk2.item && sv1.item.unlocated_eq(&sv2.item))),
_ => false
}
}
}
impl ToJson for InputValue {
fn to_json(&self) -> Json {
match *self {
InputValue::Null | InputValue::Variable(_) => Json::Null,
InputValue::Int(i) => Json::I64(i),
InputValue::Float(f) => Json::F64(f),
InputValue::String(ref s) | InputValue::Enum(ref s) => Json::String(s.clone()),
InputValue::Boolean(b) => Json::Boolean(b),
InputValue::List(ref l) => Json::Array(l.iter().map(|x| x.item.to_json()).collect()),
InputValue::Object(ref o) => Json::Object(o.iter().map(|&(ref k, ref v)| (k.item.clone(), v.item.to_json())).collect()),
}
}
}
impl Arguments {
pub fn into_iter(self) -> vec::IntoIter<(Spanning<String>, Spanning<InputValue>)> {
self.items.into_iter()
}
pub fn iter(&self) -> slice::Iter<(Spanning<String>, Spanning<InputValue>)> {
self.items.iter()
}
pub fn iter_mut(&mut self) -> slice::IterMut<(Spanning<String>, Spanning<InputValue>)> {
self.items.iter_mut()
}
pub fn drain<'a>(&'a mut self) -> vec::Drain<'a, (Spanning<String>, Spanning<InputValue>)> {
self.items.drain(..)
}
pub fn len(&self) -> usize {
self.items.len()
}
pub fn get(&self, key: &str) -> Option<&Spanning<InputValue>> {
self.items
.iter()
.filter(|&&(ref k, _)| k.item == key)
.map(|&(_, ref v)| v)
.next()
}
}
impl VariableDefinitions {
pub fn iter(&self) -> slice::Iter<(Spanning<String>, VariableDefinition)> {
self.items.iter()
}
}