use std::borrow::Cow;
use std::fmt;
use ast::{FromInputValue, InputValue, Type};
use types::base::TypeKind;
pub struct ScalarMeta<'a> {
#[doc(hidden)]
pub name: Cow<'a, str>,
#[doc(hidden)]
pub description: Option<String>,
#[doc(hidden)]
pub try_parse_fn: Box<Fn(&InputValue) -> bool + Send + Sync>,
}
#[derive(Debug)]
pub struct ListMeta<'a> {
#[doc(hidden)]
pub of_type: Type<'a>,
}
#[derive(Debug)]
pub struct NullableMeta<'a> {
#[doc(hidden)]
pub of_type: Type<'a>,
}
#[derive(Debug)]
pub struct ObjectMeta<'a> {
#[doc(hidden)]
pub name: Cow<'a, str>,
#[doc(hidden)]
pub description: Option<String>,
#[doc(hidden)]
pub fields: Vec<Field<'a>>,
#[doc(hidden)]
pub interface_names: Vec<String>,
}
pub struct EnumMeta<'a> {
#[doc(hidden)]
pub name: Cow<'a, str>,
#[doc(hidden)]
pub description: Option<String>,
#[doc(hidden)]
pub values: Vec<EnumValue>,
#[doc(hidden)]
pub try_parse_fn: Box<Fn(&InputValue) -> bool + Send + Sync>,
}
#[derive(Debug)]
pub struct InterfaceMeta<'a> {
#[doc(hidden)]
pub name: Cow<'a, str>,
#[doc(hidden)]
pub description: Option<String>,
#[doc(hidden)]
pub fields: Vec<Field<'a>>,
}
#[derive(Debug)]
pub struct UnionMeta<'a> {
#[doc(hidden)]
pub name: Cow<'a, str>,
#[doc(hidden)]
pub description: Option<String>,
#[doc(hidden)]
pub of_type_names: Vec<String>,
}
pub struct InputObjectMeta<'a> {
#[doc(hidden)]
pub name: Cow<'a, str>,
#[doc(hidden)]
pub description: Option<String>,
#[doc(hidden)]
pub input_fields: Vec<Argument<'a>>,
#[doc(hidden)]
pub try_parse_fn: Box<Fn(&InputValue) -> bool + Send + Sync>,
}
#[derive(Debug)]
pub struct PlaceholderMeta<'a> {
#[doc(hidden)]
pub of_type: Type<'a>,
}
#[derive(Debug)]
pub enum MetaType<'a> {
#[doc(hidden)]
Scalar(ScalarMeta<'a>),
#[doc(hidden)]
List(ListMeta<'a>),
#[doc(hidden)]
Nullable(NullableMeta<'a>),
#[doc(hidden)]
Object(ObjectMeta<'a>),
#[doc(hidden)]
Enum(EnumMeta<'a>),
#[doc(hidden)]
Interface(InterfaceMeta<'a>),
#[doc(hidden)]
Union(UnionMeta<'a>),
#[doc(hidden)]
InputObject(InputObjectMeta<'a>),
#[doc(hidden)]
Placeholder(PlaceholderMeta<'a>),
}
#[derive(Debug, Clone)]
pub struct Field<'a> {
#[doc(hidden)]
pub name: String,
#[doc(hidden)]
pub description: Option<String>,
#[doc(hidden)]
pub arguments: Option<Vec<Argument<'a>>>,
#[doc(hidden)]
pub field_type: Type<'a>,
#[doc(hidden)]
pub deprecation_reason: Option<String>,
}
#[derive(Debug, Clone)]
pub struct Argument<'a> {
#[doc(hidden)]
pub name: String,
#[doc(hidden)]
pub description: Option<String>,
#[doc(hidden)]
pub arg_type: Type<'a>,
#[doc(hidden)]
pub default_value: Option<InputValue>,
}
#[derive(Debug, Clone)]
pub struct EnumValue {
pub name: String,
pub description: Option<String>,
pub deprecation_reason: Option<String>,
}
impl<'a> MetaType<'a> {
pub fn name(&self) -> Option<&str> {
match *self {
MetaType::Scalar(ScalarMeta { ref name, .. })
| MetaType::Object(ObjectMeta { ref name, .. })
| MetaType::Enum(EnumMeta { ref name, .. })
| MetaType::Interface(InterfaceMeta { ref name, .. })
| MetaType::Union(UnionMeta { ref name, .. })
| MetaType::InputObject(InputObjectMeta { ref name, .. }) => Some(name),
_ => None,
}
}
pub fn description(&self) -> Option<&String> {
match *self {
MetaType::Scalar(ScalarMeta {
ref description, ..
})
| MetaType::Object(ObjectMeta {
ref description, ..
})
| MetaType::Enum(EnumMeta {
ref description, ..
})
| MetaType::Interface(InterfaceMeta {
ref description, ..
})
| MetaType::Union(UnionMeta {
ref description, ..
})
| MetaType::InputObject(InputObjectMeta {
ref description, ..
}) => description.as_ref(),
_ => None,
}
}
pub fn type_kind(&self) -> TypeKind {
match *self {
MetaType::Scalar(_) => TypeKind::Scalar,
MetaType::List(_) => TypeKind::List,
MetaType::Nullable(_) => panic!("Can't take type_kind of nullable meta type"),
MetaType::Object(_) => TypeKind::Object,
MetaType::Enum(_) => TypeKind::Enum,
MetaType::Interface(_) => TypeKind::Interface,
MetaType::Union(_) => TypeKind::Union,
MetaType::InputObject(_) => TypeKind::InputObject,
MetaType::Placeholder(_) => panic!("Can't take type_kind of placeholder meta type"),
}
}
pub fn field_by_name(&self, name: &str) -> Option<&Field> {
match *self {
MetaType::Object(ObjectMeta { ref fields, .. })
| MetaType::Interface(InterfaceMeta { ref fields, .. }) => {
fields.iter().find(|f| f.name == name)
}
_ => None,
}
}
pub fn input_field_by_name(&self, name: &str) -> Option<&Argument> {
match *self {
MetaType::InputObject(InputObjectMeta {
ref input_fields, ..
}) => input_fields.iter().find(|f| f.name == name),
_ => None,
}
}
pub fn as_type(&self) -> Type<'a> {
match *self {
MetaType::Scalar(ScalarMeta { ref name, .. })
| MetaType::Object(ObjectMeta { ref name, .. })
| MetaType::Enum(EnumMeta { ref name, .. })
| MetaType::Interface(InterfaceMeta { ref name, .. })
| MetaType::Union(UnionMeta { ref name, .. })
| MetaType::InputObject(InputObjectMeta { ref name, .. }) => {
Type::NonNullNamed(name.clone())
}
MetaType::List(ListMeta { ref of_type }) => {
Type::NonNullList(Box::new(of_type.clone()))
}
MetaType::Nullable(NullableMeta { ref of_type }) => match *of_type {
Type::NonNullNamed(ref inner) => Type::Named(inner.clone()),
Type::NonNullList(ref inner) => Type::List(inner.clone()),
ref t => t.clone(),
},
MetaType::Placeholder(PlaceholderMeta { ref of_type }) => of_type.clone(),
}
}
pub fn input_value_parse_fn(&self) -> Option<&Box<Fn(&InputValue) -> bool + Send + Sync>> {
match *self {
MetaType::Scalar(ScalarMeta {
ref try_parse_fn, ..
})
| MetaType::Enum(EnumMeta {
ref try_parse_fn, ..
})
| MetaType::InputObject(InputObjectMeta {
ref try_parse_fn, ..
}) => Some(try_parse_fn),
_ => None,
}
}
pub fn is_composite(&self) -> bool {
match *self {
MetaType::Object(_) | MetaType::Interface(_) | MetaType::Union(_) => true,
_ => false,
}
}
pub fn is_leaf(&self) -> bool {
match *self {
MetaType::Enum(_) | MetaType::Scalar(_) => true,
_ => false,
}
}
pub fn is_abstract(&self) -> bool {
match *self {
MetaType::Interface(_) | MetaType::Union(_) => true,
_ => false,
}
}
pub fn is_input(&self) -> bool {
match *self {
MetaType::Scalar(_) | MetaType::Enum(_) | MetaType::InputObject(_) => true,
_ => false,
}
}
}
impl<'a> ScalarMeta<'a> {
pub fn new<T: FromInputValue>(name: Cow<'a, str>) -> ScalarMeta<'a> {
ScalarMeta {
name: name,
description: None,
try_parse_fn: Box::new(|v: &InputValue| {
<T as FromInputValue>::from_input_value(v).is_some()
}),
}
}
pub fn description(mut self, description: &str) -> ScalarMeta<'a> {
self.description = Some(description.to_owned());
self
}
pub fn into_meta(self) -> MetaType<'a> {
MetaType::Scalar(self)
}
}
impl<'a> ListMeta<'a> {
pub fn new(of_type: Type<'a>) -> ListMeta<'a> {
ListMeta { of_type: of_type }
}
pub fn into_meta(self) -> MetaType<'a> {
MetaType::List(self)
}
}
impl<'a> NullableMeta<'a> {
pub fn new(of_type: Type<'a>) -> NullableMeta<'a> {
NullableMeta { of_type: of_type }
}
pub fn into_meta(self) -> MetaType<'a> {
MetaType::Nullable(self)
}
}
impl<'a> ObjectMeta<'a> {
pub fn new(name: Cow<'a, str>, fields: &[Field<'a>]) -> ObjectMeta<'a> {
ObjectMeta {
name: name,
description: None,
fields: fields.to_vec(),
interface_names: vec![],
}
}
pub fn description(mut self, description: &str) -> ObjectMeta<'a> {
self.description = Some(description.to_owned());
self
}
pub fn interfaces(mut self, interfaces: &[Type<'a>]) -> ObjectMeta<'a> {
self.interface_names = interfaces
.iter()
.map(|t| t.innermost_name().to_owned())
.collect();
self
}
pub fn into_meta(self) -> MetaType<'a> {
MetaType::Object(self)
}
}
impl<'a> EnumMeta<'a> {
pub fn new<T: FromInputValue>(name: Cow<'a, str>, values: &[EnumValue]) -> EnumMeta<'a> {
EnumMeta {
name: name,
description: None,
values: values.to_vec(),
try_parse_fn: Box::new(|v: &InputValue| {
<T as FromInputValue>::from_input_value(v).is_some()
}),
}
}
pub fn description(mut self, description: &str) -> EnumMeta<'a> {
self.description = Some(description.to_owned());
self
}
pub fn into_meta(self) -> MetaType<'a> {
MetaType::Enum(self)
}
}
impl<'a> InterfaceMeta<'a> {
pub fn new(name: Cow<'a, str>, fields: &[Field<'a>]) -> InterfaceMeta<'a> {
InterfaceMeta {
name: name,
description: None,
fields: fields.to_vec(),
}
}
pub fn description(mut self, description: &str) -> InterfaceMeta<'a> {
self.description = Some(description.to_owned());
self
}
pub fn into_meta(self) -> MetaType<'a> {
MetaType::Interface(self)
}
}
impl<'a> UnionMeta<'a> {
pub fn new(name: Cow<'a, str>, of_types: &[Type]) -> UnionMeta<'a> {
UnionMeta {
name: name,
description: None,
of_type_names: of_types
.iter()
.map(|t| t.innermost_name().to_owned())
.collect(),
}
}
pub fn description(mut self, description: &str) -> UnionMeta<'a> {
self.description = Some(description.to_owned());
self
}
pub fn into_meta(self) -> MetaType<'a> {
MetaType::Union(self)
}
}
impl<'a> InputObjectMeta<'a> {
pub fn new<T: FromInputValue>(
name: Cow<'a, str>,
input_fields: &[Argument<'a>],
) -> InputObjectMeta<'a> {
InputObjectMeta {
name: name,
description: None,
input_fields: input_fields.to_vec(),
try_parse_fn: Box::new(|v: &InputValue| {
<T as FromInputValue>::from_input_value(v).is_some()
}),
}
}
pub fn description(mut self, description: &str) -> InputObjectMeta<'a> {
self.description = Some(description.to_owned());
self
}
pub fn into_meta(self) -> MetaType<'a> {
MetaType::InputObject(self)
}
}
impl<'a> Field<'a> {
pub fn description(mut self, description: &str) -> Field<'a> {
self.description = Some(description.to_owned());
self
}
pub fn argument(mut self, argument: Argument<'a>) -> Field<'a> {
match self.arguments {
None => {
self.arguments = Some(vec![argument]);
}
Some(ref mut args) => {
args.push(argument);
}
};
self
}
pub fn deprecated(mut self, reason: &str) -> Field<'a> {
self.deprecation_reason = Some(reason.to_owned());
self
}
}
impl<'a> Argument<'a> {
#[doc(hidden)]
pub fn new(name: &str, arg_type: Type<'a>) -> Argument<'a> {
Argument {
name: name.to_owned(),
description: None,
arg_type: arg_type,
default_value: None,
}
}
pub fn description(mut self, description: &str) -> Argument<'a> {
self.description = Some(description.to_owned());
self
}
pub fn default_value(mut self, default_value: InputValue) -> Argument<'a> {
self.default_value = Some(default_value);
self
}
}
impl EnumValue {
pub fn new(name: &str) -> EnumValue {
EnumValue {
name: name.to_owned(),
description: None,
deprecation_reason: None,
}
}
pub fn description(mut self, description: &str) -> EnumValue {
self.description = Some(description.to_owned());
self
}
pub fn deprecated(mut self, reason: &str) -> EnumValue {
self.deprecation_reason = Some(reason.to_owned());
self
}
}
impl<'a> fmt::Debug for ScalarMeta<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("ScalarMeta")
.field("name", &self.name)
.field("description", &self.description)
.finish()
}
}
impl<'a> fmt::Debug for EnumMeta<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("EnumMeta")
.field("name", &self.name)
.field("description", &self.description)
.field("values", &self.values)
.finish()
}
}
impl<'a> fmt::Debug for InputObjectMeta<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("InputObjectMeta")
.field("name", &self.name)
.field("description", &self.description)
.field("input_fields", &self.input_fields)
.finish()
}
}