From 500308d18c9ad19c6c1c78aa2a1aadf3f3e6f3a3 Mon Sep 17 00:00:00 2001 From: Christoph Herzog Date: Tue, 14 May 2019 14:25:50 +0200 Subject: [PATCH 1/2] Make AST generic over string values This commit introduces a Text trait that is used for representing text data in the AST. This enables using the ast with &str references only, with Cow, or just as now in an owned fashion (with String). To prevent a wrapper type, the Text trait has an associated type 'Value' that represents the actual value and has to be used in the AST nodes. --- benches/graphql.rs | 10 +- src/common.rs | 115 ++++++++++------ src/format.rs | 16 ++- src/helpers.rs | 24 ++-- src/lib.rs | 6 +- src/query/ast.rs | 131 ++++++++++-------- src/query/format.rs | 112 ++++++++++----- src/query/grammar.rs | 91 +++++++------ src/schema/ast.rs | 271 ++++++++++++++++++++----------------- src/schema/format.rs | 165 ++++++++++++++-------- src/schema/grammar.rs | 181 ++++++++++++++----------- tests/query_errors.rs | 2 +- tests/query_roundtrips.rs | 4 +- tests/schema_roundtrips.rs | 4 +- 14 files changed, 676 insertions(+), 456 deletions(-) diff --git a/benches/graphql.rs b/benches/graphql.rs index a5c1d7a..39b8235 100644 --- a/benches/graphql.rs +++ b/benches/graphql.rs @@ -19,29 +19,29 @@ fn load_file(name: &str) -> String { #[bench] fn bench_minimal(b: &mut test::Bencher) { let f = load_file("minimal"); - b.iter(|| parse_query(&f).unwrap()); + b.iter(|| parse_query::(&f).unwrap()); } #[bench] fn bench_inline_fragment(b: &mut test::Bencher) { let f = load_file("inline_fragment"); - b.iter(|| parse_query(&f).unwrap()); + b.iter(|| parse_query::(&f).unwrap()); } #[bench] fn bench_directive_args(b: &mut test::Bencher) { let f = load_file("directive_args"); - b.iter(|| parse_query(&f).unwrap()); + b.iter(|| parse_query::(&f).unwrap()); } #[bench] fn bench_query_vars(b: &mut test::Bencher) { let f = load_file("query_vars"); - b.iter(|| parse_query(&f).unwrap()); + b.iter(|| parse_query::(&f).unwrap()); } #[bench] fn bench_kitchen_sink(b: &mut test::Bencher) { let f = load_file("kitchen-sink"); - b.iter(|| parse_query(&f).unwrap()); + b.iter(|| parse_query::(&f).unwrap()); } diff --git a/src/common.rs b/src/common.rs index 85e0da1..d0f3a65 100644 --- a/src/common.rs +++ b/src/common.rs @@ -1,4 +1,4 @@ -use std::collections::BTreeMap; +use std::{fmt, collections::BTreeMap}; use combine::{parser, ParseResult, Parser}; use combine::easy::Error; @@ -9,15 +9,29 @@ use tokenizer::{Kind as T, Token, TokenStream}; use helpers::{punct, ident, kind, name}; use position::Pos; +/// Text abstracts over types that hold a string value. +/// It is used to make the AST generic over the string type. +pub trait Text<'a>: 'a { + type Value: 'a + From<&'a str> + AsRef + std::borrow::Borrow + PartialEq + Eq + PartialOrd + Ord + fmt::Debug + Clone; +} + +impl<'a> Text<'a> for &'a str { + type Value = Self; +} -/// An alias for string, used where graphql expects a name -pub type Name = String; +impl<'a> Text<'a> for String { + type Value = String; +} + +impl<'a> Text<'a> for std::borrow::Cow<'a, str> { + type Value = Self; +} #[derive(Debug, Clone, PartialEq)] -pub struct Directive { +pub struct Directive<'a, T: Text<'a>> { pub position: Pos, - pub name: Name, - pub arguments: Vec<(Name, Value)>, + pub name: T::Value, + pub arguments: Vec<(T::Value, Value<'a, T>)>, } /// This represents integer number @@ -32,23 +46,23 @@ pub struct Directive { pub struct Number(pub(crate) i64); #[derive(Debug, Clone, PartialEq)] -pub enum Value { - Variable(Name), +pub enum Value<'a, T: Text<'a>> { + Variable(T::Value), Int(Number), Float(f64), String(String), Boolean(bool), Null, - Enum(Name), - List(Vec), - Object(BTreeMap), + Enum(T::Value), + List(Vec>), + Object(BTreeMap>), } #[derive(Debug, Clone, PartialEq)] -pub enum Type { - NamedType(Name), - ListType(Box), - NonNullType(Box), +pub enum Type<'a, T: Text<'a>> { + NamedType(T::Value), + ListType(Box>), + NonNullType(Box>), } impl Number { @@ -64,12 +78,13 @@ impl From for Number { } } -pub fn directives<'a>(input: &mut TokenStream<'a>) - -> ParseResult, TokenStream<'a>> +pub fn directives<'a, T>(input: &mut TokenStream<'a>) + -> ParseResult>, TokenStream<'a>> + where T: Text<'a>, { many(position() .skip(punct("@")) - .and(name()) + .and(name::<'a, T>()) .and(parser(arguments)) .map(|((position, name), arguments)| { Directive { position, name, arguments } @@ -77,12 +92,13 @@ pub fn directives<'a>(input: &mut TokenStream<'a>) .parse_stream(input) } -pub fn arguments<'a>(input: &mut TokenStream<'a>) - -> ParseResult, TokenStream<'a>> +pub fn arguments<'a, T>(input: &mut TokenStream<'a>) + -> ParseResult)>, TokenStream<'a>> + where T: Text<'a>, { optional( punct("(") - .with(many1(name() + .with(many1(name::<'a, T>() .skip(punct(":")) .and(parser(value)))) .skip(punct(")"))) @@ -92,27 +108,29 @@ pub fn arguments<'a>(input: &mut TokenStream<'a>) .parse_stream(input) } -pub fn int_value<'a>(input: &mut TokenStream<'a>) - -> ParseResult> +pub fn int_value<'a, S>(input: &mut TokenStream<'a>) + -> ParseResult, TokenStream<'a>> + where S: Text<'a> { kind(T::IntValue).and_then(|tok| tok.value.parse()) .map(Number).map(Value::Int) .parse_stream(input) } -pub fn float_value<'a>(input: &mut TokenStream<'a>) - -> ParseResult> +pub fn float_value<'a, S>(input: &mut TokenStream<'a>) + -> ParseResult, TokenStream<'a>> + where S: Text<'a> { kind(T::FloatValue).and_then(|tok| tok.value.parse()) .map(Value::Float) .parse_stream(input) } -fn unquote_block_string(src: &str) -> Result> { +fn unquote_block_string<'a>(src: &'a str) -> Result, Token<'a>>> { debug_assert!(src.starts_with("\"\"\"") && src.ends_with("\"\"\"")); let indent = src[3..src.len()-3].lines().skip(1) .filter_map(|line| { - let trimmed = line.trim_left().len(); + let trimmed = line.trim_start().len(); if trimmed > 0 { Some(line.len() - trimmed) } else { @@ -144,7 +162,8 @@ fn unquote_block_string(src: &str) -> Result> { Ok(result) } -fn unquote_string(s: &str) -> Result> { +fn unquote_string<'a>(s: &'a str) -> Result> +{ let mut res = String::with_capacity(s.len()); debug_assert!(s.starts_with('"') && s.ends_with('"')); let mut chars = s[1..s.len()-1].chars(); @@ -183,29 +202,32 @@ pub fn string<'a>(input: &mut TokenStream<'a>) )).parse_stream(input) } -pub fn string_value<'a>(input: &mut TokenStream<'a>) - -> ParseResult> +pub fn string_value<'a, S>(input: &mut TokenStream<'a>) + -> ParseResult, TokenStream<'a>> + where S: Text<'a>, { kind(T::StringValue).and_then(|tok| unquote_string(tok.value)) .map(Value::String) .parse_stream(input) } -pub fn block_string_value<'a>(input: &mut TokenStream<'a>) - -> ParseResult> +pub fn block_string_value<'a, S>(input: &mut TokenStream<'a>) + -> ParseResult, TokenStream<'a>> + where S: Text<'a>, { kind(T::BlockString).and_then(|tok| unquote_block_string(tok.value)) .map(Value::String) .parse_stream(input) } -pub fn plain_value<'a>(input: &mut TokenStream<'a>) - -> ParseResult> +pub fn plain_value<'a, T>(input: &mut TokenStream<'a>) + -> ParseResult, TokenStream<'a>> + where T: Text<'a>, { ident("true").map(|_| Value::Boolean(true)) .or(ident("false").map(|_| Value::Boolean(false))) .or(ident("null").map(|_| Value::Null)) - .or(name().map(Value::Enum)) + .or(name::<'a, T>().map(Value::Enum)) .or(parser(int_value)) .or(parser(float_value)) .or(parser(string_value)) @@ -213,37 +235,40 @@ pub fn plain_value<'a>(input: &mut TokenStream<'a>) .parse_stream(input) } -pub fn value<'a>(input: &mut TokenStream<'a>) - -> ParseResult> +pub fn value<'a, T>(input: &mut TokenStream<'a>) + -> ParseResult, TokenStream<'a>> + where T: Text<'a>, { parser(plain_value) - .or(punct("$").with(name()).map(Value::Variable)) + .or(punct("$").with(name::<'a, T>()).map(Value::Variable)) .or(punct("[").with(many(parser(value))).skip(punct("]")) .map(Value::List)) .or(punct("{") - .with(many(name().skip(punct(":")).and(parser(value)))) + .with(many(name::<'a, T>().skip(punct(":")).and(parser(value)))) .skip(punct("}")) .map(Value::Object)) .parse_stream(input) } -pub fn default_value<'a>(input: &mut TokenStream<'a>) - -> ParseResult> +pub fn default_value<'a, T>(input: &mut TokenStream<'a>) + -> ParseResult, TokenStream<'a>> + where T: Text<'a>, { parser(plain_value) .or(punct("[").with(many(parser(default_value))).skip(punct("]")) .map(Value::List)) .or(punct("{") - .with(many(name().skip(punct(":")).and(parser(default_value)))) + .with(many(name::<'a, T>().skip(punct(":")).and(parser(default_value)))) .skip(punct("}")) .map(Value::Object)) .parse_stream(input) } -pub fn parse_type<'a>(input: &mut TokenStream<'a>) - -> ParseResult> +pub fn parse_type<'a, T>(input: &mut TokenStream<'a>) + -> ParseResult, TokenStream<'a>> + where T: Text<'a>, { - name().map(Type::NamedType) + name::<'a, T>().map(Type::NamedType) .or(punct("[") .with(parser(parse_type)) .skip(punct("]")) diff --git a/src/format.rs b/src/format.rs index 6935d93..a824b2f 100644 --- a/src/format.rs +++ b/src/format.rs @@ -130,7 +130,9 @@ impl<'a> Formatter<'a> { } } -pub(crate) fn format_directives(dirs: &[Directive], f: &mut Formatter) { +pub(crate) fn format_directives<'a, T>(dirs: &[Directive<'a, T>], f: &mut Formatter) + where T: ::common::Text<'a>, +{ for dir in dirs { f.write(" "); dir.display(f); @@ -147,4 +149,16 @@ macro_rules! impl_display { } )+ }; + + ('a $($typ: ident, )+) => { + $( + impl<'a, T> fmt::Display for $typ<'a, T> + where T: Text<'a>, + { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(&to_string(self)) + } + } + )+ + }; } diff --git a/src/helpers.rs b/src/helpers.rs index 78278e4..9dc1c9e 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -7,6 +7,8 @@ use combine::stream::easy::{Error, Errors, Info}; use tokenizer::{TokenStream, Kind, Token}; use position::Pos; +use super::common::{Text}; + #[derive(Debug, Clone)] pub struct TokenMatch<'a> { @@ -15,8 +17,10 @@ pub struct TokenMatch<'a> { } #[derive(Debug, Clone)] -pub struct NameMatch<'a> { - phantom: PhantomData<&'a u8>, +pub struct NameMatch<'a, T> + where T: Text<'a> +{ + phantom: PhantomData<(&'a T)>, } #[derive(Debug, Clone)] @@ -34,7 +38,9 @@ pub fn kind<'x>(kind: Kind) -> TokenMatch<'x> { } } -pub fn name<'x>() -> NameMatch<'x> { +pub fn name<'a, T>() -> NameMatch<'a, T> + where T: Text<'a> +{ NameMatch { phantom: PhantomData, } @@ -60,7 +66,7 @@ impl<'a> Parser for TokenMatch<'a> { } } -pub fn punct<'x>(value: &'static str) -> Value<'x> { +pub fn punct<'s>(value: &'static str) -> Value<'s> { Value { kind: Kind::Punctuator, value: value, @@ -68,7 +74,7 @@ pub fn punct<'x>(value: &'static str) -> Value<'x> { } } -pub fn ident<'x>(value: &'static str) -> Value<'x> { +pub fn ident<'s>(value: &'static str) -> Value<'s> { Value { kind: Kind::Name, value: value, @@ -97,9 +103,11 @@ impl<'a> Parser for Value<'a> { } } -impl<'a> Parser for NameMatch<'a> { +impl<'a, S> Parser for NameMatch<'a, S> + where S: Text<'a>, +{ type Input = TokenStream<'a>; - type Output = String; + type Output = S::Value; type PartialState = (); #[inline] @@ -107,7 +115,7 @@ impl<'a> Parser for NameMatch<'a> { -> ConsumedResult { satisfy(|c: Token<'a>| c.kind == Kind::Name) - .map(|t: Token<'a>| t.value.to_string()) + .map(|t: Token<'a>| -> S::Value { S::Value::from(t.value) } ) .parse_lazy(input) } diff --git a/src/lib.rs b/src/lib.rs index 84303be..e4cd1fa 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,7 +25,7 @@ //! use graphql_parser::parse_query; //! //! # fn parse() -> Result<(), failure::Error> { -//! let ast = parse_query("query MyQuery { field1, field2 }")?; +//! let ast = parse_query::<&str>("query MyQuery { field1, field2 }")?; //! // Format canonical representation //! assert_eq!(format!("{}", ast), "\ //! query MyQuery { @@ -49,7 +49,7 @@ //! use graphql_parser::parse_schema; //! //! # fn parse() -> Result<(), failure::Error> { -//! let ast = parse_schema(r#" +//! let ast = parse_schema::(r#" //! schema { //! query: Query //! } @@ -64,7 +64,7 @@ //! type User { //! name: String!, //! } -//! "#)?; +//! "#)?.to_owned(); //! // Format canonical representation //! assert_eq!(format!("{}", ast), "\ //! schema { diff --git a/src/query/ast.rs b/src/query/ast.rs index 8e9935a..d97749e 100644 --- a/src/query/ast.rs +++ b/src/query/ast.rs @@ -6,111 +6,130 @@ //! [graphql grammar]: http://facebook.github.io/graphql/October2016/#sec-Appendix-Grammar-Summary //! use position::Pos; -pub use common::{Directive, Number, Value, Name, Type}; +pub use common::{Directive, Number, Value, Text, Type}; /// Root of query data #[derive(Debug, Clone, PartialEq)] -pub struct Document { - pub definitions: Vec, +pub struct Document<'a, T: Text<'a>> { + pub definitions: Vec>, +} + +impl<'a> Document<'a, String> { + pub fn into_static(self) -> Document<'static, String> { + // To support both reference and owned values in the AST, + // all string data is represented with the ::common::Str<'a, T: Text<'a>> + // wrapper type. + // This type must carry the liftetime of the query string, + // and is stored in a PhantomData value on the Str type. + // When using owned String types, the actual lifetime of + // the Ast nodes is 'static, since no references are kept, + // but the nodes will still carry the input lifetime. + // To continue working with Document in a owned fasion + // the lifetime needs to be transmuted to 'static. + // + // This is safe because no references are present. + // Just the PhantomData lifetime reference is transmuted away. + unsafe { std::mem::transmute::<_, Document<'static, String>>(self) } + } } #[derive(Debug, Clone, PartialEq)] -pub enum Definition { - Operation(OperationDefinition), - Fragment(FragmentDefinition), +pub enum Definition<'a, T: Text<'a>> { + Operation(OperationDefinition<'a, T>), + Fragment(FragmentDefinition<'a, T>), } #[derive(Debug, Clone, PartialEq)] -pub struct FragmentDefinition { +pub struct FragmentDefinition<'a, T: Text<'a>> { pub position: Pos, - pub name: Name, - pub type_condition: TypeCondition, - pub directives: Vec, - pub selection_set: SelectionSet, + pub name: T::Value, + pub type_condition: TypeCondition<'a, T>, + pub directives: Vec>, + pub selection_set: SelectionSet<'a, T>, } #[derive(Debug, Clone, PartialEq)] -pub enum OperationDefinition { - SelectionSet(SelectionSet), - Query(Query), - Mutation(Mutation), - Subscription(Subscription), +pub enum OperationDefinition<'a, T: Text<'a>> { + SelectionSet(SelectionSet<'a, T>), + Query(Query<'a, T>), + Mutation(Mutation<'a, T>), + Subscription(Subscription<'a, T>), } #[derive(Debug, Clone, PartialEq)] -pub struct Query { +pub struct Query<'a, T: Text<'a>> { pub position: Pos, - pub name: Option, - pub variable_definitions: Vec, - pub directives: Vec, - pub selection_set: SelectionSet, + pub name: Option, + pub variable_definitions: Vec>, + pub directives: Vec>, + pub selection_set: SelectionSet<'a, T>, } #[derive(Debug, Clone, PartialEq)] -pub struct Mutation { +pub struct Mutation<'a, T: Text<'a>> { pub position: Pos, - pub name: Option, - pub variable_definitions: Vec, - pub directives: Vec, - pub selection_set: SelectionSet, + pub name: Option, + pub variable_definitions: Vec>, + pub directives: Vec>, + pub selection_set: SelectionSet<'a, T>, } #[derive(Debug, Clone, PartialEq)] -pub struct Subscription { +pub struct Subscription<'a, T: Text<'a>> { pub position: Pos, - pub name: Option, - pub variable_definitions: Vec, - pub directives: Vec, - pub selection_set: SelectionSet, + pub name: Option, + pub variable_definitions: Vec>, + pub directives: Vec>, + pub selection_set: SelectionSet<'a, T>, } #[derive(Debug, Clone, PartialEq)] -pub struct SelectionSet { +pub struct SelectionSet<'a, T: Text<'a>> { pub span: (Pos, Pos), - pub items: Vec, + pub items: Vec>, } #[derive(Debug, Clone, PartialEq)] -pub struct VariableDefinition { +pub struct VariableDefinition<'a, T: Text<'a>> { pub position: Pos, - pub name: Name, - pub var_type: Type, - pub default_value: Option, + pub name: T::Value, + pub var_type: Type<'a, T>, + pub default_value: Option>, } #[derive(Debug, Clone, PartialEq)] -pub enum Selection { - Field(Field), - FragmentSpread(FragmentSpread), - InlineFragment(InlineFragment), +pub enum Selection<'a, T: Text<'a>> { + Field(Field<'a, T>), + FragmentSpread(FragmentSpread<'a, T>), + InlineFragment(InlineFragment<'a, T>), } #[derive(Debug, Clone, PartialEq)] -pub struct Field { +pub struct Field<'a, T: Text<'a>> { pub position: Pos, - pub alias: Option, - pub name: Name, - pub arguments: Vec<(Name, Value)>, - pub directives: Vec, - pub selection_set: SelectionSet, + pub alias: Option, + pub name: T::Value, + pub arguments: Vec<(T::Value, Value<'a, T>)>, + pub directives: Vec>, + pub selection_set: SelectionSet<'a, T>, } #[derive(Debug, Clone, PartialEq)] -pub struct FragmentSpread { +pub struct FragmentSpread<'a, T: Text<'a>> { pub position: Pos, - pub fragment_name: Name, - pub directives: Vec, + pub fragment_name: T::Value, + pub directives: Vec>, } #[derive(Debug, Clone, PartialEq)] -pub enum TypeCondition { - On(Name), +pub enum TypeCondition<'a, T: Text<'a>> { + On(T::Value), } #[derive(Debug, Clone, PartialEq)] -pub struct InlineFragment { +pub struct InlineFragment<'a, T: Text<'a>> { pub position: Pos, - pub type_condition: Option, - pub directives: Vec, - pub selection_set: SelectionSet, + pub type_condition: Option>, + pub directives: Vec>, + pub selection_set: SelectionSet<'a, T>, } diff --git a/src/query/format.rs b/src/query/format.rs index 0292c0e..00b9a94 100644 --- a/src/query/format.rs +++ b/src/query/format.rs @@ -5,7 +5,9 @@ use ::format::{Displayable, Formatter, Style, format_directives}; use query::ast::*; -impl Document { +impl<'a, T: Text<'a>> Document<'a, T> + where T: Text<'a>, +{ /// Format a document according to style pub fn format(&self, style: &Style) -> String { let mut formatter = Formatter::new(style); @@ -21,7 +23,9 @@ fn to_string(v: &T) -> String { formatter.into_string() } -impl Displayable for Document { +impl<'a, T: Text<'a>> Displayable for Document<'a, T> + where T: Text<'a>, +{ fn display(&self, f: &mut Formatter) { for item in &self.definitions { item.display(f); @@ -29,7 +33,9 @@ impl Displayable for Document { } } -impl Displayable for Definition { +impl<'a, T: Text<'a>> Displayable for Definition<'a, T> + where T: Text<'a>, +{ fn display(&self, f: &mut Formatter) { match *self { Definition::Operation(ref op) => op.display(f), @@ -38,7 +44,9 @@ impl Displayable for Definition { } } -impl Displayable for OperationDefinition { +impl<'a, T: Text<'a>> Displayable for OperationDefinition<'a, T> + where T: Text<'a>, +{ fn display(&self, f: &mut Formatter) { match *self { OperationDefinition::SelectionSet(ref set) => set.display(f), @@ -49,12 +57,14 @@ impl Displayable for OperationDefinition { } } -impl Displayable for FragmentDefinition { +impl<'a, T: Text<'a>> Displayable for FragmentDefinition<'a, T> + where T: Text<'a>, +{ fn display(&self, f: &mut Formatter) { f.margin(); f.indent(); f.write("fragment "); - f.write(&self.name); + f.write(self.name.as_ref()); f.write(" "); self.type_condition.display(f); format_directives(&self.directives, f); @@ -67,7 +77,9 @@ impl Displayable for FragmentDefinition { } } -impl Displayable for SelectionSet { +impl<'a, T: Text<'a>> Displayable for SelectionSet<'a, T> + where T: Text<'a>, +{ fn display(&self, f: &mut Formatter) { f.margin(); f.indent(); @@ -79,7 +91,9 @@ impl Displayable for SelectionSet { } } -impl Displayable for Selection { +impl<'a, T: Text<'a>> Displayable for Selection<'a, T> + where T: Text<'a>, +{ fn display(&self, f: &mut Formatter) { match *self { Selection::Field(ref fld) => fld.display(f), @@ -89,15 +103,17 @@ impl Displayable for Selection { } } -fn format_arguments(arguments: &[(String, Value)], f: &mut Formatter) { +fn format_arguments<'a, T: Text<'a>>(arguments: &[(T::Value, Value<'a, T>)], f: &mut Formatter) + where T: Text<'a>, +{ if !arguments.is_empty() { f.write("("); - f.write(&arguments[0].0); + f.write(arguments[0].0.as_ref()); f.write(": "); arguments[0].1.display(f); for arg in &arguments[1..] { f.write(", "); - f.write(&arg.0); + f.write(arg.0.as_ref()); f.write(": "); arg.1.display(f); } @@ -105,14 +121,16 @@ fn format_arguments(arguments: &[(String, Value)], f: &mut Formatter) { } } -impl Displayable for Field { +impl<'a, T: Text<'a>> Displayable for Field<'a, T> + where T: Text<'a>, +{ fn display(&self, f: &mut Formatter) { f.indent(); if let Some(ref alias) = self.alias { - f.write(alias); + f.write(alias.as_ref()); f.write(": "); } - f.write(&self.name); + f.write(self.name.as_ref()); format_arguments(&self.arguments, f); format_directives(&self.directives, f); if !self.selection_set.items.is_empty() { @@ -128,14 +146,16 @@ impl Displayable for Field { } } -impl Displayable for Query { +impl<'a, T: Text<'a>> Displayable for Query<'a, T> + where T: Text<'a>, +{ fn display(&self, f: &mut Formatter) { f.margin(); f.indent(); f.write("query"); if let Some(ref name) = self.name { f.write(" "); - f.write(name); + f.write(name.as_ref()); if !self.variable_definitions.is_empty() { f.write("("); self.variable_definitions[0].display(f); @@ -156,14 +176,16 @@ impl Displayable for Query { } } -impl Displayable for Mutation { +impl<'a, T: Text<'a>> Displayable for Mutation<'a, T> + where T: Text<'a>, +{ fn display(&self, f: &mut Formatter) { f.margin(); f.indent(); f.write("mutation"); if let Some(ref name) = self.name { f.write(" "); - f.write(name); + f.write(name.as_ref()); if !self.variable_definitions.is_empty() { f.write("("); for var in &self.variable_definitions { @@ -182,14 +204,16 @@ impl Displayable for Mutation { } } -impl Displayable for Subscription { +impl<'a, T: Text<'a>> Displayable for Subscription<'a, T> + where T: Text<'a>, +{ fn display(&self, f: &mut Formatter) { f.margin(); f.indent(); f.write("subscription"); if let Some(ref name) = self.name { f.write(" "); - f.write(name); + f.write(name.as_ref()); if !self.variable_definitions.is_empty() { f.write("("); for var in &self.variable_definitions { @@ -208,10 +232,12 @@ impl Displayable for Subscription { } } -impl Displayable for VariableDefinition { +impl<'a, T: Text<'a>> Displayable for VariableDefinition<'a, T> + where T: Text<'a>, +{ fn display(&self, f: &mut Formatter) { f.write("$"); - f.write(&self.name); + f.write(self.name.as_ref()); f.write(": "); self.var_type.display(f); if let Some(ref default) = self.default_value { @@ -221,10 +247,12 @@ impl Displayable for VariableDefinition { } } -impl Displayable for Type { +impl<'a, T: Text<'a>> Displayable for Type<'a, T> + where T: Text<'a>, +{ fn display(&self, f: &mut Formatter) { match *self { - Type::NamedType(ref name) => f.write(name), + Type::NamedType(ref name) => f.write(name.as_ref()), Type::ListType(ref typ) => { f.write("["); typ.display(f); @@ -238,17 +266,19 @@ impl Displayable for Type { } } -impl Displayable for Value { +impl<'a, T: Text<'a>> Displayable for Value<'a, T> + where T: Text<'a>, +{ fn display(&self, f: &mut Formatter) { match *self { - Value::Variable(ref name) => { f.write("$"); f.write(name); }, + Value::Variable(ref name) => { f.write("$"); f.write(name.as_ref()); }, Value::Int(ref num) => f.write(&format!("{}", num.0)), Value::Float(val) => f.write(&format!("{}", val)), Value::String(ref val) => f.write_quoted(val), Value::Boolean(true) => f.write("true"), Value::Boolean(false) => f.write("false"), Value::Null => f.write("null"), - Value::Enum(ref name) => f.write(name), + Value::Enum(ref name) => f.write(name.as_ref()), Value::List(ref items) => { f.write("["); if !items.is_empty() { @@ -269,7 +299,7 @@ impl Displayable for Value { } else { f.write(", "); } - f.write(name); + f.write(name.as_ref()); f.write(": "); value.display(f); } @@ -279,7 +309,9 @@ impl Displayable for Value { } } -impl Displayable for InlineFragment { +impl<'a, T: Text<'a>> Displayable for InlineFragment<'a, T> + where T: Text<'a>, +{ fn display(&self, f: &mut Formatter) { f.indent(); f.write("..."); @@ -297,37 +329,44 @@ impl Displayable for InlineFragment { } } -impl Displayable for TypeCondition { +impl<'a, T: Text<'a>> Displayable for TypeCondition<'a, T> + where T: Text<'a>, +{ fn display(&self, f: &mut Formatter) { match *self { TypeCondition::On(ref name) => { f.write("on "); - f.write(name); + f.write(name.as_ref()); } } } } -impl Displayable for FragmentSpread { +impl<'a, T: Text<'a>> Displayable for FragmentSpread<'a, T> + where T: Text<'a>, +{ fn display(&self, f: &mut Formatter) { f.indent(); f.write("..."); - f.write(&self.fragment_name); + f.write(self.fragment_name.as_ref()); format_directives(&self.directives, f); f.endline(); } } -impl Displayable for Directive { +impl<'a, T: Text<'a>> Displayable for Directive<'a, T> + where T: Text<'a>, +{ fn display(&self, f: &mut Formatter) { f.write("@"); - f.write(&self.name); - format_arguments(&self.arguments, f); + f.write(self.name.as_ref()); + format_arguments(self.arguments.as_slice(), f); } } impl_display!( + 'a Document, Definition, OperationDefinition, @@ -345,4 +384,3 @@ impl_display!( FragmentSpread, Directive, ); - diff --git a/src/query/grammar.rs b/src/query/grammar.rs index a61aafa..fa51c75 100644 --- a/src/query/grammar.rs +++ b/src/query/grammar.rs @@ -8,13 +8,14 @@ use helpers::{punct, ident, name}; use query::error::{ParseError}; use query::ast::*; -pub fn field<'a>(input: &mut TokenStream<'a>) - -> ParseResult> +pub fn field<'a, S>(input: &mut TokenStream<'a>) + -> ParseResult, TokenStream<'a>> + where S: Text<'a> { ( position(), - name(), - optional(punct(":").with(name())), + name::<'a, S>(), + optional(punct(":").with(name::<'a, S>())), parser(arguments), parser(directives), optional(parser(selection_set)), @@ -36,13 +37,14 @@ pub fn field<'a>(input: &mut TokenStream<'a>) .parse_stream(input) } -pub fn selection<'a>(input: &mut TokenStream<'a>) - -> ParseResult> +pub fn selection<'a, S>(input: &mut TokenStream<'a>) + -> ParseResult, TokenStream<'a>> + where S: Text<'a> { parser(field).map(Selection::Field) .or(punct("...").with(( position(), - optional(ident("on").with(name()).map(TypeCondition::On)), + optional(ident("on").with(name::<'a, S>()).map(TypeCondition::On)), parser(directives), parser(selection_set), ).map(|(position, type_condition, directives, selection_set)| { @@ -51,7 +53,7 @@ pub fn selection<'a>(input: &mut TokenStream<'a>) }) .map(Selection::InlineFragment) .or((position(), - name(), + name::<'a, S>(), parser(directives), ).map(|(position, fragment_name, directives)| { FragmentSpread { position, fragment_name, directives } @@ -61,8 +63,9 @@ pub fn selection<'a>(input: &mut TokenStream<'a>) .parse_stream(input) } -pub fn selection_set<'a>(input: &mut TokenStream<'a>) - -> ParseResult> +pub fn selection_set<'a, S>(input: &mut TokenStream<'a>) + -> ParseResult, TokenStream<'a>> + where S: Text<'a>, { ( position().skip(punct("{")), @@ -72,8 +75,9 @@ pub fn selection_set<'a>(input: &mut TokenStream<'a>) .parse_stream(input) } -pub fn query<'a>(input: &mut TokenStream<'a>) - -> ParseResult> +pub fn query<'a, T: Text<'a>>(input: &mut TokenStream<'a>) + -> ParseResult, TokenStream<'a>> + where T: Text<'a>, { position() .skip(ident("query")) @@ -86,23 +90,25 @@ pub fn query<'a>(input: &mut TokenStream<'a>) } /// A set of attributes common to a Query and a Mutation -type OperationCommon = ( - Option, - Vec, - Vec, - SelectionSet, +#[allow(type_alias_bounds)] +type OperationCommon<'a, T: Text<'a>> = ( + Option, + Vec>, + Vec>, + SelectionSet<'a, T>, ); -pub fn operation_common<'a>(input: &mut TokenStream<'a>) - -> ParseResult> +pub fn operation_common<'a, T: Text<'a>>(input: &mut TokenStream<'a>) + -> ParseResult, TokenStream<'a>> + where T: Text<'a>, { - optional(name()) + optional(name::<'a, T>()) .and(optional( punct("(") .with(many1( ( position(), - punct("$").with(name()).skip(punct(":")), + punct("$").with(name::<'a, T>()).skip(punct(":")), parser(parse_type), optional( punct("=") @@ -120,8 +126,9 @@ pub fn operation_common<'a>(input: &mut TokenStream<'a>) .parse_stream(input) } -pub fn mutation<'a>(input: &mut TokenStream<'a>) - -> ParseResult> +pub fn mutation<'a, T: Text<'a>>(input: &mut TokenStream<'a>) + -> ParseResult, TokenStream<'a>> + where T: Text<'a>, { position() .skip(ident("mutation")) @@ -133,8 +140,9 @@ pub fn mutation<'a>(input: &mut TokenStream<'a>) .parse_stream(input) } -pub fn subscription<'a>(input: &mut TokenStream<'a>) - -> ParseResult> +pub fn subscription<'a, T: Text<'a>>(input: &mut TokenStream<'a>) + -> ParseResult, TokenStream<'a>> + where T: Text<'a>, { position() .skip(ident("subscription")) @@ -146,8 +154,9 @@ pub fn subscription<'a>(input: &mut TokenStream<'a>) .parse_stream(input) } -pub fn operation_definition<'a>(input: &mut TokenStream<'a>) - -> ParseResult> +pub fn operation_definition<'a, S>(input: &mut TokenStream<'a>) + -> ParseResult, TokenStream<'a>> + where S: Text<'a>, { parser(selection_set).map(OperationDefinition::SelectionSet) .or(parser(query).map(OperationDefinition::Query)) @@ -156,13 +165,14 @@ pub fn operation_definition<'a>(input: &mut TokenStream<'a>) .parse_stream(input) } -pub fn fragment_definition<'a>(input: &mut TokenStream<'a>) - -> ParseResult> +pub fn fragment_definition<'a, T: Text<'a>>(input: &mut TokenStream<'a>) + -> ParseResult, TokenStream<'a>> + where T: Text<'a>, { ( position().skip(ident("fragment")), - name(), - ident("on").with(name()).map(TypeCondition::On), + name::<'a, T>(), + ident("on").with(name::<'a, T>()).map(TypeCondition::On), parser(directives), parser(selection_set) ).map(|(position, name, type_condition, directives, selection_set)| { @@ -173,8 +183,9 @@ pub fn fragment_definition<'a>(input: &mut TokenStream<'a>) .parse_stream(input) } -pub fn definition<'a>(input: &mut TokenStream<'a>) - -> ParseResult> +pub fn definition<'a, S>(input: &mut TokenStream<'a>) + -> ParseResult, TokenStream<'a>> + where S: Text<'a>, { parser(operation_definition).map(Definition::Operation) .or(parser(fragment_definition).map(Definition::Fragment)) @@ -182,7 +193,9 @@ pub fn definition<'a>(input: &mut TokenStream<'a>) } /// Parses a piece of query language and returns an AST -pub fn parse_query(s: &str) -> Result { +pub fn parse_query<'a, S>(s: &'a str) -> Result, ParseError> + where S: Text<'a>, +{ let mut tokens = TokenStream::new(s); let (doc, _) = many1(parser(definition)) .map(|d| Document { definitions: d }) @@ -199,8 +212,8 @@ mod test { use query::grammar::*; use super::parse_query; - fn ast(s: &str) -> Document { - parse_query(s).unwrap() + fn ast(s: &str) -> Document { + parse_query::(&s).unwrap().to_owned() } #[test] @@ -246,11 +259,11 @@ mod test { alias: None, name: "a".into(), arguments: vec![ - ("t".to_string(), + ("t".into(), Value::Boolean(true)), - ("f".to_string(), + ("f".into(), Value::Boolean(false)), - ("n".to_string(), + ("n".into(), Value::Null), ], directives: Vec::new(), diff --git a/src/schema/ast.rs b/src/schema/ast.rs index cb5d88f..c8183f1 100644 --- a/src/schema/ast.rs +++ b/src/schema/ast.rs @@ -1,63 +1,64 @@ use std::str::FromStr; -pub use common::{Directive, Type, Name, Value}; +pub use common::{Directive, Type, Value, Text}; use position::Pos; -pub type NamedType = String; - - #[derive(Debug, Clone, Default, PartialEq)] -pub struct Document { - pub definitions: Vec, +pub struct Document<'a, T: Text<'a>> + where T: Text<'a> +{ + pub definitions: Vec>, } #[derive(Debug, Clone, PartialEq)] -pub enum Definition { - SchemaDefinition(SchemaDefinition), - TypeDefinition(TypeDefinition), - TypeExtension(TypeExtension), - DirectiveDefinition(DirectiveDefinition), +pub enum Definition<'a, T: Text<'a>> { + SchemaDefinition(SchemaDefinition<'a, T>), + TypeDefinition(TypeDefinition<'a, T>), + TypeExtension(TypeExtension<'a, T>), + DirectiveDefinition(DirectiveDefinition<'a, T>), } #[derive(Debug, Clone, Default, PartialEq)] -pub struct SchemaDefinition { +pub struct SchemaDefinition<'a, T: Text<'a>> { pub position: Pos, - pub directives: Vec, - pub query: Option, - pub mutation: Option, - pub subscription: Option, + pub directives: Vec>, + pub query: Option, + pub mutation: Option, + pub subscription: Option, } #[derive(Debug, Clone, PartialEq)] -pub enum TypeDefinition { - Scalar(ScalarType), - Object(ObjectType), - Interface(InterfaceType), - Union(UnionType), - Enum(EnumType), - InputObject(InputObjectType), +pub enum TypeDefinition<'a, T: Text<'a>> { + Scalar(ScalarType<'a, T>), + Object(ObjectType<'a, T>), + Interface(InterfaceType<'a, T>), + Union(UnionType<'a, T>), + Enum(EnumType<'a, T>), + InputObject(InputObjectType<'a, T>), } #[derive(Debug, Clone, PartialEq)] -pub enum TypeExtension { - Scalar(ScalarTypeExtension), - Object(ObjectTypeExtension), - Interface(InterfaceTypeExtension), - Union(UnionTypeExtension), - Enum(EnumTypeExtension), - InputObject(InputObjectTypeExtension), +pub enum TypeExtension<'a, T: Text<'a>> { + Scalar(ScalarTypeExtension<'a, T>), + Object(ObjectTypeExtension<'a, T>), + Interface(InterfaceTypeExtension<'a, T>), + Union(UnionTypeExtension<'a, T>), + Enum(EnumTypeExtension<'a, T>), + InputObject(InputObjectTypeExtension<'a, T>), } #[derive(Debug, Clone, PartialEq)] -pub struct ScalarType { +pub struct ScalarType<'a, T: Text<'a>> { pub position: Pos, pub description: Option, - pub name: Name, - pub directives: Vec, + pub name: T::Value, + pub directives: Vec>, } -impl ScalarType { - pub fn new(name: Name) -> Self { +impl<'a, T> ScalarType<'a, T> + where T: Text<'a> +{ + pub fn new(name: T::Value) -> Self { Self { position: Pos::default(), description: None, @@ -68,14 +69,16 @@ impl ScalarType { } #[derive(Debug, Clone, PartialEq)] -pub struct ScalarTypeExtension { +pub struct ScalarTypeExtension<'a, T: Text<'a>> { pub position: Pos, - pub name: Name, - pub directives: Vec, + pub name: T::Value, + pub directives: Vec>, } -impl ScalarTypeExtension { - pub fn new(name: Name) -> Self { +impl<'a, T> ScalarTypeExtension<'a, T> + where T: Text<'a> +{ + pub fn new(name: T::Value) -> Self { Self { position: Pos::default(), name, @@ -85,17 +88,19 @@ impl ScalarTypeExtension { } #[derive(Debug, Clone, PartialEq)] -pub struct ObjectType { +pub struct ObjectType<'a, T: Text<'a>> { pub position: Pos, pub description: Option, - pub name: Name, - pub implements_interfaces: Vec, - pub directives: Vec, - pub fields: Vec, + pub name: T::Value, + pub implements_interfaces: Vec, + pub directives: Vec>, + pub fields: Vec>, } -impl ObjectType { - pub fn new(name: Name) -> Self { +impl<'a, T> ObjectType<'a, T> + where T: Text<'a> +{ + pub fn new(name: T::Value) -> Self { Self { position: Pos::default(), description: None, @@ -108,16 +113,18 @@ impl ObjectType { } #[derive(Debug, Clone, PartialEq)] -pub struct ObjectTypeExtension { +pub struct ObjectTypeExtension<'a, T: Text<'a>> { pub position: Pos, - pub name: Name, - pub implements_interfaces: Vec, - pub directives: Vec, - pub fields: Vec, + pub name: T::Value, + pub implements_interfaces: Vec, + pub directives: Vec>, + pub fields: Vec>, } -impl ObjectTypeExtension { - pub fn new(name: Name) -> Self { +impl<'a, T> ObjectTypeExtension<'a, T> + where T: Text<'a> +{ + pub fn new(name: T::Value) -> Self { Self { position: Pos::default(), name, @@ -129,36 +136,38 @@ impl ObjectTypeExtension { } #[derive(Debug, Clone, PartialEq)] -pub struct Field { +pub struct Field<'a, T: Text<'a>> { pub position: Pos, pub description: Option, - pub name: Name, - pub arguments: Vec, - pub field_type: Type, - pub directives: Vec, + pub name: T::Value, + pub arguments: Vec>, + pub field_type: Type<'a, T>, + pub directives: Vec>, } #[derive(Debug, Clone, PartialEq)] -pub struct InputValue { +pub struct InputValue<'a, T: Text<'a>> { pub position: Pos, pub description: Option, - pub name: Name, - pub value_type: Type, - pub default_value: Option, - pub directives: Vec, + pub name: T::Value, + pub value_type: Type<'a, T>, + pub default_value: Option>, + pub directives: Vec>, } #[derive(Debug, Clone, PartialEq)] -pub struct InterfaceType { +pub struct InterfaceType<'a, T: Text<'a>> { pub position: Pos, pub description: Option, - pub name: Name, - pub directives: Vec, - pub fields: Vec, + pub name: T::Value, + pub directives: Vec>, + pub fields: Vec>, } -impl InterfaceType { - pub fn new(name: Name) -> Self { +impl<'a, T> InterfaceType<'a, T> + where T: Text<'a> +{ + pub fn new(name: T::Value) -> Self { Self { position: Pos::default(), description: None, @@ -170,15 +179,17 @@ impl InterfaceType { } #[derive(Debug, Clone, PartialEq)] -pub struct InterfaceTypeExtension { +pub struct InterfaceTypeExtension<'a, T: Text<'a>> { pub position: Pos, - pub name: Name, - pub directives: Vec, - pub fields: Vec, + pub name: T::Value, + pub directives: Vec>, + pub fields: Vec>, } -impl InterfaceTypeExtension { - pub fn new(name: Name) -> Self { +impl<'a, T> InterfaceTypeExtension<'a, T> +where T: Text<'a> +{ + pub fn new(name: T::Value) -> Self { Self { position: Pos::default(), name, @@ -189,16 +200,18 @@ impl InterfaceTypeExtension { } #[derive(Debug, Clone, PartialEq)] -pub struct UnionType { +pub struct UnionType<'a, T: Text<'a>> { pub position: Pos, pub description: Option, - pub name: Name, - pub directives: Vec, - pub types: Vec, + pub name: T::Value, + pub directives: Vec>, + pub types: Vec, } -impl UnionType { - pub fn new(name: Name) -> Self { +impl<'a, T> UnionType<'a, T> +where T: Text<'a> +{ + pub fn new(name: T::Value) -> Self { Self { position: Pos::default(), description: None, @@ -210,15 +223,17 @@ impl UnionType { } #[derive(Debug, Clone, PartialEq)] -pub struct UnionTypeExtension { +pub struct UnionTypeExtension<'a, T: Text<'a>> { pub position: Pos, - pub name: Name, - pub directives: Vec, - pub types: Vec, + pub name: T::Value, + pub directives: Vec>, + pub types: Vec, } -impl UnionTypeExtension { - pub fn new(name: Name) -> Self { +impl<'a, T> UnionTypeExtension<'a, T> +where T: Text<'a> +{ + pub fn new(name: T::Value) -> Self { Self { position: Pos::default(), name, @@ -229,16 +244,18 @@ impl UnionTypeExtension { } #[derive(Debug, Clone, PartialEq)] -pub struct EnumType { +pub struct EnumType<'a, T: Text<'a>> { pub position: Pos, pub description: Option, - pub name: Name, - pub directives: Vec, - pub values: Vec, + pub name: T::Value, + pub directives: Vec>, + pub values: Vec>, } -impl EnumType { - pub fn new(name: Name) -> Self { +impl<'a, T> EnumType<'a, T> +where T: Text<'a> +{ + pub fn new(name: T::Value) -> Self { Self { position: Pos::default(), description: None, @@ -250,15 +267,17 @@ impl EnumType { } #[derive(Debug, Clone, PartialEq)] -pub struct EnumValue { +pub struct EnumValue<'a, T: Text<'a>> { pub position: Pos, pub description: Option, - pub name: Name, - pub directives: Vec, + pub name: T::Value, + pub directives: Vec>, } -impl EnumValue { - pub fn new(name: Name) -> Self { +impl<'a, T> EnumValue<'a, T> +where T: Text<'a> +{ + pub fn new(name: T::Value) -> Self { Self { position: Pos::default(), description: None, @@ -269,15 +288,17 @@ impl EnumValue { } #[derive(Debug, Clone, PartialEq)] -pub struct EnumTypeExtension { +pub struct EnumTypeExtension<'a, T: Text<'a>> { pub position: Pos, - pub name: Name, - pub directives: Vec, - pub values: Vec, + pub name: T::Value, + pub directives: Vec>, + pub values: Vec>, } -impl EnumTypeExtension { - pub fn new(name: Name) -> Self { +impl<'a, T> EnumTypeExtension<'a, T> +where T: Text<'a> +{ + pub fn new(name: T::Value) -> Self { Self { position: Pos::default(), name, @@ -288,16 +309,18 @@ impl EnumTypeExtension { } #[derive(Debug, Clone, PartialEq)] -pub struct InputObjectType { +pub struct InputObjectType<'a, T: Text<'a>> { pub position: Pos, pub description: Option, - pub name: Name, - pub directives: Vec, - pub fields: Vec, + pub name: T::Value, + pub directives: Vec>, + pub fields: Vec>, } -impl InputObjectType { - pub fn new(name: Name) -> Self { +impl<'a, T> InputObjectType<'a, T> +where T: Text<'a> +{ + pub fn new(name: T::Value) -> Self { Self { position: Pos::default(), description: None, @@ -309,15 +332,17 @@ impl InputObjectType { } #[derive(Debug, Clone, PartialEq)] -pub struct InputObjectTypeExtension { +pub struct InputObjectTypeExtension<'a, T: Text<'a>> { pub position: Pos, - pub name: Name, - pub directives: Vec, - pub fields: Vec, + pub name: T::Value, + pub directives: Vec>, + pub fields: Vec>, } -impl InputObjectTypeExtension { - pub fn new(name: Name) -> Self { +impl<'a, T> InputObjectTypeExtension<'a, T> +where T: Text<'a> +{ + pub fn new(name: T::Value) -> Self { Self { position: Pos::default(), name, @@ -353,16 +378,18 @@ pub enum DirectiveLocation { } #[derive(Debug, Clone, PartialEq)] -pub struct DirectiveDefinition { +pub struct DirectiveDefinition<'a, T: Text<'a>> { pub position: Pos, pub description: Option, - pub name: Name, - pub arguments: Vec, + pub name: T::Value, + pub arguments: Vec>, pub locations: Vec, } -impl DirectiveDefinition { - pub fn new(name: Name) -> Self { +impl<'a, T> DirectiveDefinition<'a, T> +where T: Text<'a> +{ + pub fn new(name: T::Value) -> Self { Self { position: Pos::default(), description: None, diff --git a/src/schema/format.rs b/src/schema/format.rs index 70b0ace..10fffaa 100644 --- a/src/schema/format.rs +++ b/src/schema/format.rs @@ -1,11 +1,14 @@ use std::fmt; use ::format::{Displayable, Formatter, Style, format_directives}; +use ::common::Text; use schema::ast::*; -impl Document { +impl<'a, T> Document<'a, T> + where T: Text<'a>, +{ /// Format a document according to style pub fn format(&self, style: &Style) -> String { let mut formatter = Formatter::new(style); @@ -21,16 +24,18 @@ fn to_string(v: &T) -> String { formatter.into_string() } -fn description(description: &Option, f: &mut Formatter) { +fn description<'a>(description: &Option, f: &mut Formatter) { if let Some(ref descr) = *description { f.indent(); - f.write_quoted(descr); + f.write_quoted(descr.as_ref()); f.endline(); } } -impl Displayable for Document { +impl<'a, T> Displayable for Document<'a, T> + where T: Text<'a>, +{ fn display(&self, f: &mut Formatter) { for item in &self.definitions { item.display(f); @@ -38,7 +43,9 @@ impl Displayable for Document { } } -impl Displayable for Definition { +impl<'a, T> Displayable for Definition<'a, T> + where T: Text<'a>, +{ fn display(&self, f: &mut Formatter) { f.margin(); match *self { @@ -50,7 +57,9 @@ impl Displayable for Definition { } } -impl Displayable for SchemaDefinition { +impl<'a, T> Displayable for SchemaDefinition<'a, T> + where T: Text<'a>, +{ fn display(&self, f: &mut Formatter) { f.indent(); f.write("schema"); @@ -60,26 +69,28 @@ impl Displayable for SchemaDefinition { if let Some(ref q) = self.query { f.indent(); f.write("query: "); - f.write(q); + f.write(q.as_ref()); f.endline(); } if let Some(ref m) = self.mutation { f.indent(); f.write("mutation: "); - f.write(m); + f.write(m.as_ref()); f.endline(); } if let Some(ref s) = self.subscription { f.indent(); f.write("subscription: "); - f.write(s); + f.write(s.as_ref()); f.endline(); } f.end_block(); } } -impl Displayable for TypeDefinition { +impl<'a, T> Displayable for TypeDefinition<'a, T> + where T: Text<'a>, +{ fn display(&self, f: &mut Formatter) { match *self { TypeDefinition::Scalar(ref s) => s.display(f), @@ -92,28 +103,34 @@ impl Displayable for TypeDefinition { } } -impl Displayable for ScalarType { +impl<'a, T> Displayable for ScalarType<'a, T> + where T: Text<'a>, +{ fn display(&self, f: &mut Formatter) { description(&self.description, f); f.indent(); f.write("scalar "); - f.write(&self.name); + f.write(self.name.as_ref()); format_directives(&self.directives, f); f.endline(); } } -impl Displayable for ScalarTypeExtension { +impl<'a, T> Displayable for ScalarTypeExtension<'a, T> + where T: Text<'a>, +{ fn display(&self, f: &mut Formatter) { f.indent(); f.write("extend scalar "); - f.write(&self.name); + f.write(self.name.as_ref()); format_directives(&self.directives, f); f.endline(); } } -fn format_fields(fields: &[Field], f: &mut Formatter) { +fn format_fields<'a, T>(fields: &[Field<'a, T>], f: &mut Formatter) + where T: Text<'a>, +{ if !fields.is_empty() { f.write(" "); f.start_block(); @@ -126,18 +143,20 @@ fn format_fields(fields: &[Field], f: &mut Formatter) { } } -impl Displayable for ObjectType { +impl<'a, T> Displayable for ObjectType<'a, T> + where T: Text<'a>, +{ fn display(&self, f: &mut Formatter) { description(&self.description, f); f.indent(); f.write("type "); - f.write(&self.name); + f.write(self.name.as_ref()); if !self.implements_interfaces.is_empty() { f.write(" implements "); - f.write(&self.implements_interfaces[0]); + f.write(self.implements_interfaces[0].as_ref()); for name in &self.implements_interfaces[1..] { f.write(" & "); - f.write(name); + f.write(name.as_ref()); } } format_directives(&self.directives, f); @@ -145,17 +164,19 @@ impl Displayable for ObjectType { } } -impl Displayable for ObjectTypeExtension { +impl<'a, T> Displayable for ObjectTypeExtension<'a, T> + where T: Text<'a>, +{ fn display(&self, f: &mut Formatter) { f.indent(); f.write("extend type "); - f.write(&self.name); + f.write(self.name.as_ref()); if !self.implements_interfaces.is_empty() { f.write(" implements "); - f.write(&self.implements_interfaces[0]); + f.write(self.implements_interfaces[0].as_ref()); for name in &self.implements_interfaces[1..] { f.write(" & "); - f.write(name); + f.write(name.as_ref()); } } format_directives(&self.directives, f); @@ -163,13 +184,15 @@ impl Displayable for ObjectTypeExtension { } } -impl Displayable for InputValue { +impl<'a, T> Displayable for InputValue<'a, T> + where T: Text<'a>, +{ fn display(&self, f: &mut Formatter) { if let Some(ref descr) = self.description { - f.write_quoted(descr); + f.write_quoted(descr.as_ref()); f.write(" "); } - f.write(&self.name); + f.write(self.name.as_ref()); f.write(": "); self.value_type.display(f); if let Some(ref def) = self.default_value { @@ -180,7 +203,9 @@ impl Displayable for InputValue { } } -fn format_arguments(arguments: &[InputValue], f: &mut Formatter) { +fn format_arguments<'a, T>(arguments: &[InputValue<'a, T>], f: &mut Formatter) + where T: Text<'a>, +{ if !arguments.is_empty() { f.write("("); arguments[0].display(f); @@ -192,11 +217,13 @@ fn format_arguments(arguments: &[InputValue], f: &mut Formatter) { } } -impl Displayable for Field { +impl<'a, T> Displayable for Field<'a, T> + where T: Text<'a>, +{ fn display(&self, f: &mut Formatter) { description(&self.description, f); f.indent(); - f.write(&self.name); + f.write(self.name.as_ref()); format_arguments(&self.arguments, f); f.write(": "); self.field_type.display(f); @@ -205,70 +232,80 @@ impl Displayable for Field { } } -impl Displayable for InterfaceType { +impl<'a, T> Displayable for InterfaceType<'a, T> + where T: Text<'a>, +{ fn display(&self, f: &mut Formatter) { description(&self.description, f); f.indent(); f.write("interface "); - f.write(&self.name); + f.write(self.name.as_ref()); format_directives(&self.directives, f); format_fields(&self.fields, f); } } -impl Displayable for InterfaceTypeExtension { +impl<'a, T> Displayable for InterfaceTypeExtension<'a, T> + where T: Text<'a>, +{ fn display(&self, f: &mut Formatter) { f.indent(); f.write("extend interface "); - f.write(&self.name); + f.write(self.name.as_ref()); format_directives(&self.directives, f); format_fields(&self.fields, f); } } -impl Displayable for UnionType { +impl<'a, T> Displayable for UnionType<'a, T> + where T: Text<'a>, +{ fn display(&self, f: &mut Formatter) { description(&self.description, f); f.indent(); f.write("union "); - f.write(&self.name); + f.write(self.name.as_ref()); format_directives(&self.directives, f); if !self.types.is_empty() { f.write(" = "); - f.write(&self.types[0]); + f.write(self.types[0].as_ref()); for typ in &self.types[1..] { f.write(" | "); - f.write(typ); + f.write(typ.as_ref()); } } f.endline(); } } -impl Displayable for UnionTypeExtension { +impl<'a, T> Displayable for UnionTypeExtension<'a, T> + where T: Text<'a>, +{ fn display(&self, f: &mut Formatter) { f.indent(); f.write("extend union "); - f.write(&self.name); + f.write(self.name.as_ref()); format_directives(&self.directives, f); if !self.types.is_empty() { f.write(" = "); - f.write(&self.types[0]); + f.write(self.types[0].as_ref()); for typ in &self.types[1..] { f.write(" | "); - f.write(typ); + f.write(typ.as_ref()); } } f.endline(); } } -impl Displayable for EnumType { +impl<'a, T> Displayable for EnumType<'a, T> + where T: Text<'a>, +{ fn display(&self, f: &mut Formatter) { description(&self.description, f); f.indent(); f.write("enum "); - f.write(&self.name); + f.write(self.name.as_ref()); format_directives(&self.directives, f); if !self.values.is_empty() { f.write(" "); @@ -276,10 +313,10 @@ impl Displayable for EnumType { for val in &self.values { f.indent(); if let Some(ref descr) = val.description { - f.write_quoted(descr); + f.write_quoted(descr.as_ref()); f.write(" "); } - f.write(&val.name); + f.write(val.name.as_ref()); format_directives(&val.directives, f); f.endline(); } @@ -290,11 +327,13 @@ impl Displayable for EnumType { } } -impl Displayable for EnumTypeExtension { +impl<'a, T> Displayable for EnumTypeExtension<'a, T> + where T: Text<'a>, +{ fn display(&self, f: &mut Formatter) { f.indent(); f.write("extend enum "); - f.write(&self.name); + f.write(self.name.as_ref()); format_directives(&self.directives, f); if !self.values.is_empty() { f.write(" "); @@ -302,10 +341,10 @@ impl Displayable for EnumTypeExtension { for val in &self.values { f.indent(); if let Some(ref descr) = val.description { - f.write_quoted(descr); + f.write_quoted(descr.as_ref()); f.write(" "); } - f.write(&val.name); + f.write(val.name.as_ref()); format_directives(&val.directives, f); f.endline(); } @@ -316,7 +355,9 @@ impl Displayable for EnumTypeExtension { } } -fn format_inputs(fields: &[InputValue], f: &mut Formatter) { +fn format_inputs<'a, T>(fields: &[InputValue<'a, T>], f: &mut Formatter) + where T: Text<'a>, +{ if !fields.is_empty() { f.write(" "); f.start_block(); @@ -331,28 +372,34 @@ fn format_inputs(fields: &[InputValue], f: &mut Formatter) { } } -impl Displayable for InputObjectType { +impl<'a, T> Displayable for InputObjectType<'a, T> + where T: Text<'a>, +{ fn display(&self, f: &mut Formatter) { description(&self.description, f); f.indent(); f.write("input "); - f.write(&self.name); + f.write(self.name.as_ref()); format_directives(&self.directives, f); format_inputs(&self.fields, f); } } -impl Displayable for InputObjectTypeExtension { +impl<'a, T> Displayable for InputObjectTypeExtension<'a, T> + where T: Text<'a>, +{ fn display(&self, f: &mut Formatter) { f.indent(); f.write("extend input "); - f.write(&self.name); + f.write(self.name.as_ref()); format_directives(&self.directives, f); format_inputs(&self.fields, f); } } -impl Displayable for TypeExtension { +impl<'a, T> Displayable for TypeExtension<'a, T> + where T: Text<'a>, +{ fn display(&self, f: &mut Formatter) { match *self { TypeExtension::Scalar(ref s) => s.display(f), @@ -365,12 +412,14 @@ impl Displayable for TypeExtension { } } -impl Displayable for DirectiveDefinition { +impl<'a, T> Displayable for DirectiveDefinition<'a, T> + where T: Text<'a>, +{ fn display(&self, f: &mut Formatter) { description(&self.description, f); f.indent(); f.write("directive @"); - f.write(&self.name); + f.write(self.name.as_ref()); format_arguments(&self.arguments, f); if !self.locations.is_empty() { f.write(" on "); @@ -389,6 +438,7 @@ impl Displayable for DirectiveDefinition { } impl_display!( + 'a Document, Definition, SchemaDefinition, @@ -410,4 +460,3 @@ impl_display!( InputObjectTypeExtension, DirectiveDefinition, ); - diff --git a/src/schema/grammar.rs b/src/schema/grammar.rs index 3ea8c04..02b287e 100644 --- a/src/schema/grammar.rs +++ b/src/schema/grammar.rs @@ -7,13 +7,14 @@ use failure::Fail; use tokenizer::{Kind as T, Token, TokenStream}; use helpers::{punct, ident, kind, name}; -use common::{directives, string, default_value, parse_type}; +use common::{directives, string, default_value, parse_type, Text}; use schema::error::{ParseError}; use schema::ast::*; -pub fn schema<'a>(input: &mut TokenStream<'a>) - -> ParseResult> +pub fn schema<'a, S>(input: &mut TokenStream<'a>) + -> ParseResult, TokenStream<'a>> + where S: Text<'a>, { ( position().skip(ident("schema")), @@ -21,7 +22,7 @@ pub fn schema<'a>(input: &mut TokenStream<'a>) punct("{") .with(many(( kind(T::Name).skip(punct(":")), - name(), + name::<'a, S>(), ))) .skip(punct("}")), ) @@ -74,12 +75,13 @@ pub fn schema<'a>(input: &mut TokenStream<'a>) .parse_stream(input) } -pub fn scalar_type<'a>(input: &mut TokenStream<'a>) - -> ParseResult> +pub fn scalar_type<'a, T>(input: &mut TokenStream<'a>) + -> ParseResult, TokenStream<'a>> + where T: Text<'a>, { ( position(), - ident("scalar").with(name()), + ident("scalar").with(name::<'a, T>()), parser(directives), ) .map(|(position, name, directives)| { @@ -88,12 +90,13 @@ pub fn scalar_type<'a>(input: &mut TokenStream<'a>) .parse_stream(input) } -pub fn scalar_type_extension<'a>(input: &mut TokenStream<'a>) - -> ParseResult> +pub fn scalar_type_extension<'a, T>(input: &mut TokenStream<'a>) + -> ParseResult, TokenStream<'a>> + where T: Text<'a>, { ( position(), - ident("scalar").with(name()), + ident("scalar").with(name::<'a, T>()), parser(directives), ) .flat_map(|(position, name, directives)| { @@ -109,25 +112,27 @@ pub fn scalar_type_extension<'a>(input: &mut TokenStream<'a>) .parse_stream(input) } -pub fn implements_interfaces<'a>(input: &mut TokenStream<'a>) - -> ParseResult, TokenStream<'a>> +pub fn implements_interfaces<'a, X>(input: &mut TokenStream<'a>) + -> ParseResult, TokenStream<'a>> + where X: Text<'a>, { optional( ident("implements") .skip(optional(punct("&"))) - .with(sep_by1(name(), punct("&"))) + .with(sep_by1(name::<'a, X>(), punct("&"))) ) .map(|opt| opt.unwrap_or_else(Vec::new)) .parse_stream(input) } -pub fn input_value<'a>(input: &mut TokenStream<'a>) - -> ParseResult> +pub fn input_value<'a, X>(input: &mut TokenStream<'a>) + -> ParseResult, TokenStream<'a>> + where X: Text<'a>, { ( position(), optional(parser(string)), - name(), + name::<'a, X>(), punct(":").with(parser(parse_type)), optional(punct("=").with(parser(default_value))), parser(directives), @@ -141,21 +146,23 @@ pub fn input_value<'a>(input: &mut TokenStream<'a>) .parse_stream(input) } -pub fn arguments_definition<'a>(input: &mut TokenStream<'a>) - -> ParseResult, TokenStream<'a>> +pub fn arguments_definition<'a, T>(input: &mut TokenStream<'a>) + -> ParseResult>, TokenStream<'a>> + where T: Text<'a>, { optional(punct("(").with(many1(parser(input_value))).skip(punct(")"))) .map(|v| v.unwrap_or_else(Vec::new)) .parse_stream(input) } -pub fn field<'a>(input: &mut TokenStream<'a>) - -> ParseResult> +pub fn field<'a, S>(input: &mut TokenStream<'a>) + -> ParseResult, TokenStream<'a>> + where S: Text<'a>, { ( position(), optional(parser(string)), - name(), + name::<'a, S>(), parser(arguments_definition), punct(":").with(parser(parse_type)), parser(directives), @@ -168,8 +175,9 @@ pub fn field<'a>(input: &mut TokenStream<'a>) .parse_stream(input) } -pub fn fields<'a>(input: &mut TokenStream<'a>) - -> ParseResult, TokenStream<'a>> +pub fn fields<'a, S>(input: &mut TokenStream<'a>) + -> ParseResult>, TokenStream<'a>> + where S: Text<'a>, { optional(punct("{").with(many1(parser(field))).skip(punct("}"))) .map(|v| v.unwrap_or_else(Vec::new)) @@ -177,13 +185,14 @@ pub fn fields<'a>(input: &mut TokenStream<'a>) } -pub fn object_type<'a>(input: &mut TokenStream<'a>) - -> ParseResult> +pub fn object_type<'a, S>(input: &mut TokenStream<'a>) + -> ParseResult, TokenStream<'a>> + where S: Text<'a>, { ( position(), - ident("type").with(name()), - parser(implements_interfaces), + ident("type").with(name::<'a, S>()), + parser(implements_interfaces::), parser(directives), parser(fields), ) @@ -197,13 +206,14 @@ pub fn object_type<'a>(input: &mut TokenStream<'a>) .parse_stream(input) } -pub fn object_type_extension<'a>(input: &mut TokenStream<'a>) - -> ParseResult> +pub fn object_type_extension<'a, S>(input: &mut TokenStream<'a>) + -> ParseResult, TokenStream<'a>> + where S: Text<'a>, { ( position(), - ident("type").with(name()), - parser(implements_interfaces), + ident("type").with(name::<'a, S>()), + parser(implements_interfaces::), parser(directives), parser(fields), ) @@ -225,12 +235,13 @@ pub fn object_type_extension<'a>(input: &mut TokenStream<'a>) .parse_stream(input) } -pub fn interface_type<'a>(input: &mut TokenStream<'a>) - -> ParseResult> +pub fn interface_type<'a, T>(input: &mut TokenStream<'a>) + -> ParseResult, TokenStream<'a>> + where T: Text<'a>, { ( position(), - ident("interface").with(name()), + ident("interface").with(name::<'a, T>()), parser(directives), parser(fields), ) @@ -243,12 +254,13 @@ pub fn interface_type<'a>(input: &mut TokenStream<'a>) .parse_stream(input) } -pub fn interface_type_extension<'a>(input: &mut TokenStream<'a>) - -> ParseResult> +pub fn interface_type_extension<'a, T>(input: &mut TokenStream<'a>) + -> ParseResult, TokenStream<'a>> + where T: Text<'a>, { ( position(), - ident("interface").with(name()), + ident("interface").with(name::<'a, T>()), parser(directives), parser(fields), ) @@ -267,22 +279,24 @@ pub fn interface_type_extension<'a>(input: &mut TokenStream<'a>) .parse_stream(input) } -pub fn union_members<'a>(input: &mut TokenStream<'a>) - -> ParseResult, TokenStream<'a>> +pub fn union_members<'a, T>(input: &mut TokenStream<'a>) + -> ParseResult, TokenStream<'a>> + where T: Text<'a>, { optional(punct("|")) - .with(sep_by1(name(), punct("|"))) + .with(sep_by1(name::<'a, T>(), punct("|"))) .parse_stream(input) } -pub fn union_type<'a>(input: &mut TokenStream<'a>) - -> ParseResult> +pub fn union_type<'a, T>(input: &mut TokenStream<'a>) + -> ParseResult, TokenStream<'a>> + where T: Text<'a>, { ( position(), - ident("union").with(name()), + ident("union").with(name::<'a, T>()), parser(directives), - optional(punct("=").with(parser(union_members))), + optional(punct("=").with(parser(union_members::))), ) .map(|(position, name, directives, types)| { UnionType { @@ -294,14 +308,15 @@ pub fn union_type<'a>(input: &mut TokenStream<'a>) .parse_stream(input) } -pub fn union_type_extension<'a>(input: &mut TokenStream<'a>) - -> ParseResult> +pub fn union_type_extension<'a, T>(input: &mut TokenStream<'a>) + -> ParseResult, TokenStream<'a>> + where T: Text<'a>, { ( position(), - ident("union").with(name()), + ident("union").with(name::<'a, T>()), parser(directives), - optional(punct("=").with(parser(union_members))), + optional(punct("=").with(parser(union_members::))), ) .flat_map(|(position, name, directives, types)| { if directives.is_empty() && types.is_none() { @@ -319,15 +334,16 @@ pub fn union_type_extension<'a>(input: &mut TokenStream<'a>) .parse_stream(input) } -pub fn enum_values<'a>(input: &mut TokenStream<'a>) - -> ParseResult, TokenStream<'a>> +pub fn enum_values<'a, T>(input: &mut TokenStream<'a>) + -> ParseResult>, TokenStream<'a>> + where T: Text<'a>, { punct("{") .with(many1( ( position(), optional(parser(string)), - name(), + name::<'a, T>(), parser(directives), ) .map(|(position, description, name, directives)| { @@ -338,12 +354,13 @@ pub fn enum_values<'a>(input: &mut TokenStream<'a>) .parse_stream(input) } -pub fn enum_type<'a>(input: &mut TokenStream<'a>) - -> ParseResult> +pub fn enum_type<'a, T>(input: &mut TokenStream<'a>) + -> ParseResult, TokenStream<'a>> + where T: Text<'a>, { ( position(), - ident("enum").with(name()), + ident("enum").with(name::<'a, T>()), parser(directives), optional(parser(enum_values)), ) @@ -357,12 +374,13 @@ pub fn enum_type<'a>(input: &mut TokenStream<'a>) .parse_stream(input) } -pub fn enum_type_extension<'a>(input: &mut TokenStream<'a>) - -> ParseResult> +pub fn enum_type_extension<'a, T>(input: &mut TokenStream<'a>) + -> ParseResult, TokenStream<'a>> + where T: Text<'a>, { ( position(), - ident("enum").with(name()), + ident("enum").with(name::<'a, T>()), parser(directives), optional(parser(enum_values)), ) @@ -382,20 +400,22 @@ pub fn enum_type_extension<'a>(input: &mut TokenStream<'a>) .parse_stream(input) } -pub fn input_fields<'a>(input: &mut TokenStream<'a>) - -> ParseResult, TokenStream<'a>> +pub fn input_fields<'a, T>(input: &mut TokenStream<'a>) + -> ParseResult>, TokenStream<'a>> + where T: Text<'a>, { optional(punct("{").with(many1(parser(input_value))).skip(punct("}"))) .map(|v| v.unwrap_or_else(Vec::new)) .parse_stream(input) } -pub fn input_object_type<'a>(input: &mut TokenStream<'a>) - -> ParseResult> +pub fn input_object_type<'a, T>(input: &mut TokenStream<'a>) + -> ParseResult, TokenStream<'a>> + where T: Text<'a>, { ( position(), - ident("input").with(name()), + ident("input").with(name::<'a, T>()), parser(directives), parser(input_fields), ) @@ -408,12 +428,13 @@ pub fn input_object_type<'a>(input: &mut TokenStream<'a>) .parse_stream(input) } -pub fn input_object_type_extension<'a>(input: &mut TokenStream<'a>) - -> ParseResult> +pub fn input_object_type_extension<'a, T>(input: &mut TokenStream<'a>) + -> ParseResult, TokenStream<'a>> + where T: Text<'a>, { ( position(), - ident("input").with(name()), + ident("input").with(name::<'a, T>()), parser(directives), parser(input_fields), ) @@ -447,12 +468,13 @@ pub fn directive_locations<'a>(input: &mut TokenStream<'a>) .parse_stream(input) } -pub fn directive_definition<'a>(input: &mut TokenStream<'a>) - -> ParseResult> +pub fn directive_definition<'a, T>(input: &mut TokenStream<'a>) + -> ParseResult, TokenStream<'a>> + where T: Text<'a>, { ( position(), - ident("directive").and(punct("@")).with(name()), + ident("directive").and(punct("@")).with(name::<'a, T>()), parser(arguments_definition), ident("on").with(parser(directive_locations)), ) @@ -465,8 +487,9 @@ pub fn directive_definition<'a>(input: &mut TokenStream<'a>) .parse_stream(input) } -pub fn described_definition<'a>(input: &mut TokenStream<'a>) - -> ParseResult> +pub fn described_definition<'a, T>(input: &mut TokenStream<'a>) + -> ParseResult, TokenStream<'a>> + where T: Text<'a>, { use self::TypeDefinition::*; ( @@ -506,8 +529,9 @@ pub fn described_definition<'a>(input: &mut TokenStream<'a>) .parse_stream(input) } -pub fn type_extension<'a>(input: &mut TokenStream<'a>) - -> ParseResult> +pub fn type_extension<'a, T>(input: &mut TokenStream<'a>) + -> ParseResult, TokenStream<'a>> + where T: Text<'a>, { ident("extend") .with(choice(( @@ -522,8 +546,9 @@ pub fn type_extension<'a>(input: &mut TokenStream<'a>) } -pub fn definition<'a>(input: &mut TokenStream<'a>) - -> ParseResult> +pub fn definition<'a, T>(input: &mut TokenStream<'a>) + -> ParseResult, TokenStream<'a>> + where T: Text<'a>, { choice(( parser(schema).map(Definition::SchemaDefinition), @@ -533,7 +558,9 @@ pub fn definition<'a>(input: &mut TokenStream<'a>) } /// Parses a piece of schema language and returns an AST -pub fn parse_schema(s: &str) -> Result { +pub fn parse_schema<'a, T>(s: &'a str) -> Result, ParseError> + where T: Text<'a>, +{ let mut tokens = TokenStream::new(s); let (doc, _) = many1(parser(definition)) .map(|d| Document { definitions: d }) @@ -551,8 +578,8 @@ mod test { use schema::grammar::*; use super::parse_schema; - fn ast(s: &str) -> Document { - parse_schema(s).unwrap() + fn ast(s: &str) -> Document { + parse_schema::(&s).unwrap().to_owned() } #[test] diff --git a/tests/query_errors.rs b/tests/query_errors.rs index d458e3a..74eafe7 100644 --- a/tests/query_errors.rs +++ b/tests/query_errors.rs @@ -14,7 +14,7 @@ fn test_error(filename: &str) { let mut iter = buf.splitn(2, "\n---\n"); let graphql = iter.next().unwrap(); let expected = iter.next().expect("file should contain error message"); - let err = parse_query(graphql).unwrap_err(); + let err = parse_query::(graphql).unwrap_err(); assert_eq!(err.to_string(), expected); } diff --git a/tests/query_roundtrips.rs b/tests/query_roundtrips.rs index 962a9f4..411c7c2 100644 --- a/tests/query_roundtrips.rs +++ b/tests/query_roundtrips.rs @@ -11,7 +11,7 @@ fn roundtrip(filename: &str) { let path = format!("tests/queries/{}.graphql", filename); let mut f = File::open(&path).unwrap(); f.read_to_string(&mut buf).unwrap(); - let ast = parse_query(&buf).unwrap(); + let ast = parse_query::(&buf).unwrap().to_owned(); assert_eq!(ast.to_string(), buf); } @@ -21,7 +21,7 @@ fn roundtrip2(filename: &str) { let target = format!("tests/queries/{}_canonical.graphql", filename); let mut f = File::open(&source).unwrap(); f.read_to_string(&mut buf).unwrap(); - let ast = parse_query(&buf).unwrap(); + let ast = parse_query::(&buf).unwrap().to_owned(); let mut buf = String::with_capacity(1024); let mut f = File::open(&target).unwrap(); diff --git a/tests/schema_roundtrips.rs b/tests/schema_roundtrips.rs index 5bd8624..ab84017 100644 --- a/tests/schema_roundtrips.rs +++ b/tests/schema_roundtrips.rs @@ -11,7 +11,7 @@ fn roundtrip(filename: &str) { let path = format!("tests/schemas/{}.graphql", filename); let mut f = File::open(&path).unwrap(); f.read_to_string(&mut buf).unwrap(); - let ast = parse_schema(&buf).unwrap(); + let ast = parse_schema::(&buf).unwrap().to_owned(); assert_eq!(ast.to_string(), buf); } @@ -21,7 +21,7 @@ fn roundtrip2(filename: &str) { let target = format!("tests/schemas/{}_canonical.graphql", filename); let mut f = File::open(&source).unwrap(); f.read_to_string(&mut buf).unwrap(); - let ast = parse_schema(&buf).unwrap(); + let ast = parse_schema::(&buf).unwrap(); let mut buf = String::with_capacity(1024); let mut f = File::open(&target).unwrap(); From 267fa4331c8179bec7751e7fa635bdd42ae0edec Mon Sep 17 00:00:00 2001 From: Christoph Herzog Date: Mon, 21 Oct 2019 17:52:36 +0200 Subject: [PATCH 2/2] chore: Fix deprecation warnings --- src/format.rs | 4 ++-- src/tokenizer.rs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/format.rs b/src/format.rs index a824b2f..7224b72 100644 --- a/src/format.rs +++ b/src/format.rs @@ -93,7 +93,7 @@ impl<'a> Formatter<'a> { for c in s.chars() { match c { '\n' => has_newline = true, - '\r' | '\t' | '\u{0020}'...'\u{FFFF}' => {} + '\r' | '\t' | '\u{0020}'..='\u{FFFF}' => {} _ => has_nonprintable = true, } } @@ -107,7 +107,7 @@ impl<'a> Formatter<'a> { '\t' => self.write(r"\t"), '"' => self.write("\\\""), '\\' => self.write(r"\\"), - '\u{0020}'...'\u{FFFF}' => self.buf.push(c), + '\u{0020}'..='\u{FFFF}' => self.buf.push(c), _ => write!(&mut self.buf, "\\u{:04}", c as u32).unwrap(), } } diff --git a/src/tokenizer.rs b/src/tokenizer.rs index e70dea1..59971b9 100644 --- a/src/tokenizer.rs +++ b/src/tokenizer.rs @@ -169,10 +169,10 @@ impl<'a> TokenStream<'a> { ) } } - '_' | 'a'...'z' | 'A'...'Z' => { + '_' | 'a'..='z' | 'A'..='Z' => { while let Some((idx, cur_char)) = iter.next() { match cur_char { - '_' | 'a'...'z' | 'A'...'Z' | '0'...'9' => continue, + '_' | 'a'..='z' | 'A'..='Z' | '0'..='9' => continue, _ => { self.position.column += idx; self.off += idx; @@ -186,7 +186,7 @@ impl<'a> TokenStream<'a> { Ok((Name, len)) } - '-' | '0'...'9' => { + '-' | '0'..='9' => { let mut exponent = None; let mut real = None; let len = loop {