Skip to content

Commit 9c96732

Browse files
committed
Refactor all Ast types to use Cow<'_, str> instead of String
This enhances performance for users that do not want to clone everything, while still making owned use easy with the 'static lifetime.
1 parent a1fb575 commit 9c96732

File tree

9 files changed

+320
-304
lines changed

9 files changed

+320
-304
lines changed

src/common.rs

Lines changed: 33 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use std::collections::BTreeMap;
2+
use std::borrow::Cow;
23

34
use combine::{parser, ParseResult, Parser};
45
use combine::easy::Error;
@@ -11,13 +12,14 @@ use position::Pos;
1112

1213

1314
/// An alias for string, used where graphql expects a name
14-
pub type Name = String;
15+
pub type BorrowedStr<'a> = Cow<'a, str>;
16+
pub type Name<'a> = BorrowedStr<'a>;
1517

1618
#[derive(Debug, Clone, PartialEq)]
17-
pub struct Directive {
19+
pub struct Directive<'a> {
1820
pub position: Pos,
19-
pub name: Name,
20-
pub arguments: Vec<(Name, Value)>,
21+
pub name: Name<'a>,
22+
pub arguments: Vec<(Name<'a>, Value<'a>)>,
2123
}
2224

2325
/// This represents integer number
@@ -32,23 +34,23 @@ pub struct Directive {
3234
pub struct Number(pub(crate) i64);
3335

3436
#[derive(Debug, Clone, PartialEq)]
35-
pub enum Value {
36-
Variable(Name),
37+
pub enum Value<'a> {
38+
Variable(Name<'a>),
3739
Int(Number),
3840
Float(f64),
39-
String(String),
41+
String(BorrowedStr<'a>),
4042
Boolean(bool),
4143
Null,
42-
Enum(Name),
43-
List(Vec<Value>),
44-
Object(BTreeMap<Name, Value>),
44+
Enum(Name<'a>),
45+
List(Vec<Value<'a>>),
46+
Object(BTreeMap<Name<'a>, Value<'a>>),
4547
}
4648

4749
#[derive(Debug, Clone, PartialEq)]
48-
pub enum Type {
49-
NamedType(Name),
50-
ListType(Box<Type>),
51-
NonNullType(Box<Type>),
50+
pub enum Type<'a> {
51+
NamedType(Name<'a>),
52+
ListType(Box<Type<'a>>),
53+
NonNullType(Box<Type<'a>>),
5254
}
5355

5456
impl Number {
@@ -65,7 +67,7 @@ impl From<i32> for Number {
6567
}
6668

6769
pub fn directives<'a>(input: &mut TokenStream<'a>)
68-
-> ParseResult<Vec<Directive>, TokenStream<'a>>
70+
-> ParseResult<Vec<Directive<'a>>, TokenStream<'a>>
6971
{
7072
many(position()
7173
.skip(punct("@"))
@@ -78,7 +80,7 @@ pub fn directives<'a>(input: &mut TokenStream<'a>)
7880
}
7981

8082
pub fn arguments<'a>(input: &mut TokenStream<'a>)
81-
-> ParseResult<Vec<(String, Value)>, TokenStream<'a>>
83+
-> ParseResult<Vec<(BorrowedStr<'a>, Value<'a>)>, TokenStream<'a>>
8284
{
8385
optional(
8486
punct("(")
@@ -93,22 +95,22 @@ pub fn arguments<'a>(input: &mut TokenStream<'a>)
9395
}
9496

9597
pub fn int_value<'a>(input: &mut TokenStream<'a>)
96-
-> ParseResult<Value, TokenStream<'a>>
98+
-> ParseResult<Value<'a>, TokenStream<'a>>
9799
{
98100
kind(T::IntValue).and_then(|tok| tok.value.parse())
99101
.map(Number).map(Value::Int)
100102
.parse_stream(input)
101103
}
102104

103105
pub fn float_value<'a>(input: &mut TokenStream<'a>)
104-
-> ParseResult<Value, TokenStream<'a>>
106+
-> ParseResult<Value<'a>, TokenStream<'a>>
105107
{
106108
kind(T::FloatValue).and_then(|tok| tok.value.parse())
107109
.map(Value::Float)
108110
.parse_stream(input)
109111
}
110112

111-
fn unquote_block_string(src: &str) -> Result<String, Error<Token, Token>> {
113+
fn unquote_block_string<'a>(src: &'a str) -> Result<BorrowedStr<'a>, Error<Token<'a>, Token<'a>>> {
112114
debug_assert!(src.starts_with("\"\"\"") && src.ends_with("\"\"\""));
113115
let indent = src[3..src.len()-3].lines().skip(1)
114116
.filter_map(|line| {
@@ -141,10 +143,11 @@ fn unquote_block_string(src: &str) -> Result<String, Error<Token, Token>> {
141143
result.truncate(last_line);
142144
}
143145

144-
Ok(result)
146+
// FIXME: prevent clone
147+
Ok(std::borrow::Cow::Owned(result))
145148
}
146149

147-
fn unquote_string(s: &str) -> Result<String, Error<Token, Token>> {
150+
fn unquote_string<'a>(s: &str) -> Result<Cow<'a, str>, Error<Token, Token>> {
148151
let mut res = String::with_capacity(s.len());
149152
debug_assert!(s.starts_with('"') && s.ends_with('"'));
150153
let mut chars = s[1..s.len()-1].chars();
@@ -171,11 +174,12 @@ fn unquote_string(s: &str) -> Result<String, Error<Token, Token>> {
171174
}
172175
}
173176

174-
Ok(res)
177+
// FIXME: prevent clone
178+
Ok(std::borrow::Cow::Owned(res))
175179
}
176180

177181
pub fn string<'a>(input: &mut TokenStream<'a>)
178-
-> ParseResult<String, TokenStream<'a>>
182+
-> ParseResult<BorrowedStr<'a>, TokenStream<'a>>
179183
{
180184
choice((
181185
kind(T::StringValue).and_then(|tok| unquote_string(tok.value)),
@@ -184,23 +188,23 @@ pub fn string<'a>(input: &mut TokenStream<'a>)
184188
}
185189

186190
pub fn string_value<'a>(input: &mut TokenStream<'a>)
187-
-> ParseResult<Value, TokenStream<'a>>
191+
-> ParseResult<Value<'a>, TokenStream<'a>>
188192
{
189193
kind(T::StringValue).and_then(|tok| unquote_string(tok.value))
190194
.map(Value::String)
191195
.parse_stream(input)
192196
}
193197

194198
pub fn block_string_value<'a>(input: &mut TokenStream<'a>)
195-
-> ParseResult<Value, TokenStream<'a>>
199+
-> ParseResult<Value<'a>, TokenStream<'a>>
196200
{
197201
kind(T::BlockString).and_then(|tok| unquote_block_string(tok.value))
198202
.map(Value::String)
199203
.parse_stream(input)
200204
}
201205

202206
pub fn plain_value<'a>(input: &mut TokenStream<'a>)
203-
-> ParseResult<Value, TokenStream<'a>>
207+
-> ParseResult<Value<'a>, TokenStream<'a>>
204208
{
205209
ident("true").map(|_| Value::Boolean(true))
206210
.or(ident("false").map(|_| Value::Boolean(false)))
@@ -214,7 +218,7 @@ pub fn plain_value<'a>(input: &mut TokenStream<'a>)
214218
}
215219

216220
pub fn value<'a>(input: &mut TokenStream<'a>)
217-
-> ParseResult<Value, TokenStream<'a>>
221+
-> ParseResult<Value<'a>, TokenStream<'a>>
218222
{
219223
parser(plain_value)
220224
.or(punct("$").with(name()).map(Value::Variable))
@@ -228,7 +232,7 @@ pub fn value<'a>(input: &mut TokenStream<'a>)
228232
}
229233

230234
pub fn default_value<'a>(input: &mut TokenStream<'a>)
231-
-> ParseResult<Value, TokenStream<'a>>
235+
-> ParseResult<Value<'a>, TokenStream<'a>>
232236
{
233237
parser(plain_value)
234238
.or(punct("[").with(many(parser(default_value))).skip(punct("]"))
@@ -241,7 +245,7 @@ pub fn default_value<'a>(input: &mut TokenStream<'a>)
241245
}
242246

243247
pub fn parse_type<'a>(input: &mut TokenStream<'a>)
244-
-> ParseResult<Type, TokenStream<'a>>
248+
-> ParseResult<Type<'a>, TokenStream<'a>>
245249
{
246250
name().map(Type::NamedType)
247251
.or(punct("[")

src/format.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,4 +147,14 @@ macro_rules! impl_display {
147147
}
148148
)+
149149
};
150+
151+
('a $($typ: ident, )+) => {
152+
$(
153+
impl<'a> fmt::Display for $typ<'a> {
154+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
155+
f.write_str(&to_string(self))
156+
}
157+
}
158+
)+
159+
};
150160
}

src/helpers.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ use combine::stream::easy::{Error, Errors, Info};
77
use tokenizer::{TokenStream, Kind, Token};
88
use position::Pos;
99

10+
use super::common::BorrowedStr;
11+
1012

1113
#[derive(Debug, Clone)]
1214
pub struct TokenMatch<'a> {
@@ -99,15 +101,15 @@ impl<'a> Parser for Value<'a> {
99101

100102
impl<'a> Parser for NameMatch<'a> {
101103
type Input = TokenStream<'a>;
102-
type Output = String;
104+
type Output = BorrowedStr<'a>;
103105
type PartialState = ();
104106

105107
#[inline]
106108
fn parse_lazy(&mut self, input: &mut Self::Input)
107109
-> ConsumedResult<Self::Output, Self::Input>
108110
{
109111
satisfy(|c: Token<'a>| c.kind == Kind::Name)
110-
.map(|t: Token<'a>| t.value.to_string())
112+
.map(|t: Token<'a>| t.value.into())
111113
.parse_lazy(input)
112114
}
113115

src/query/ast.rs

Lines changed: 56 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -6,111 +6,111 @@
66
//! [graphql grammar]: http://facebook.github.io/graphql/October2016/#sec-Appendix-Grammar-Summary
77
//!
88
use position::Pos;
9-
pub use common::{Directive, Number, Value, Name, Type};
9+
pub use common::{Directive, Number, Value, BorrowedStr, Name, Type};
1010

1111
/// Root of query data
1212
#[derive(Debug, Clone, PartialEq)]
13-
pub struct Document {
14-
pub definitions: Vec<Definition>,
13+
pub struct Document<'a> {
14+
pub definitions: Vec<Definition<'a>>,
1515
}
1616

1717
#[derive(Debug, Clone, PartialEq)]
18-
pub enum Definition {
19-
Operation(OperationDefinition),
20-
Fragment(FragmentDefinition),
18+
pub enum Definition<'a> {
19+
Operation(OperationDefinition<'a>),
20+
Fragment(FragmentDefinition<'a>),
2121
}
2222

2323
#[derive(Debug, Clone, PartialEq)]
24-
pub struct FragmentDefinition {
24+
pub struct FragmentDefinition<'a> {
2525
pub position: Pos,
26-
pub name: Name,
27-
pub type_condition: TypeCondition,
28-
pub directives: Vec<Directive>,
29-
pub selection_set: SelectionSet,
26+
pub name: Name<'a>,
27+
pub type_condition: TypeCondition<'a>,
28+
pub directives: Vec<Directive<'a>>,
29+
pub selection_set: SelectionSet<'a>,
3030
}
3131

3232
#[derive(Debug, Clone, PartialEq)]
33-
pub enum OperationDefinition {
34-
SelectionSet(SelectionSet),
35-
Query(Query),
36-
Mutation(Mutation),
37-
Subscription(Subscription),
33+
pub enum OperationDefinition<'a> {
34+
SelectionSet(SelectionSet<'a>),
35+
Query(Query<'a>),
36+
Mutation(Mutation<'a>),
37+
Subscription(Subscription<'a>),
3838
}
3939

4040
#[derive(Debug, Clone, PartialEq)]
41-
pub struct Query {
41+
pub struct Query<'a> {
4242
pub position: Pos,
43-
pub name: Option<Name>,
44-
pub variable_definitions: Vec<VariableDefinition>,
45-
pub directives: Vec<Directive>,
46-
pub selection_set: SelectionSet,
43+
pub name: Option<Name<'a>>,
44+
pub variable_definitions: Vec<VariableDefinition<'a>>,
45+
pub directives: Vec<Directive<'a>>,
46+
pub selection_set: SelectionSet<'a>,
4747
}
4848

4949
#[derive(Debug, Clone, PartialEq)]
50-
pub struct Mutation {
50+
pub struct Mutation<'a> {
5151
pub position: Pos,
52-
pub name: Option<Name>,
53-
pub variable_definitions: Vec<VariableDefinition>,
54-
pub directives: Vec<Directive>,
55-
pub selection_set: SelectionSet,
52+
pub name: Option<Name<'a>>,
53+
pub variable_definitions: Vec<VariableDefinition<'a>>,
54+
pub directives: Vec<Directive<'a>>,
55+
pub selection_set: SelectionSet<'a>,
5656
}
5757

5858
#[derive(Debug, Clone, PartialEq)]
59-
pub struct Subscription {
59+
pub struct Subscription<'a> {
6060
pub position: Pos,
61-
pub name: Option<Name>,
62-
pub variable_definitions: Vec<VariableDefinition>,
63-
pub directives: Vec<Directive>,
64-
pub selection_set: SelectionSet,
61+
pub name: Option<Name<'a>>,
62+
pub variable_definitions: Vec<VariableDefinition<'a>>,
63+
pub directives: Vec<Directive<'a>>,
64+
pub selection_set: SelectionSet<'a>,
6565
}
6666

6767
#[derive(Debug, Clone, PartialEq)]
68-
pub struct SelectionSet {
68+
pub struct SelectionSet<'a> {
6969
pub span: (Pos, Pos),
70-
pub items: Vec<Selection>,
70+
pub items: Vec<Selection<'a>>,
7171
}
7272

7373
#[derive(Debug, Clone, PartialEq)]
74-
pub struct VariableDefinition {
74+
pub struct VariableDefinition<'a> {
7575
pub position: Pos,
76-
pub name: Name,
77-
pub var_type: Type,
78-
pub default_value: Option<Value>,
76+
pub name: Name<'a>,
77+
pub var_type: Type<'a>,
78+
pub default_value: Option<Value<'a>>,
7979
}
8080

8181
#[derive(Debug, Clone, PartialEq)]
82-
pub enum Selection {
83-
Field(Field),
84-
FragmentSpread(FragmentSpread),
85-
InlineFragment(InlineFragment),
82+
pub enum Selection<'a> {
83+
Field(Field<'a>),
84+
FragmentSpread(FragmentSpread<'a>),
85+
InlineFragment(InlineFragment<'a>),
8686
}
8787

8888
#[derive(Debug, Clone, PartialEq)]
89-
pub struct Field {
89+
pub struct Field<'a> {
9090
pub position: Pos,
91-
pub alias: Option<Name>,
92-
pub name: Name,
93-
pub arguments: Vec<(Name, Value)>,
94-
pub directives: Vec<Directive>,
95-
pub selection_set: SelectionSet,
91+
pub alias: Option<Name<'a>>,
92+
pub name: Name<'a>,
93+
pub arguments: Vec<(Name<'a>, Value<'a>)>,
94+
pub directives: Vec<Directive<'a>>,
95+
pub selection_set: SelectionSet<'a>,
9696
}
9797

9898
#[derive(Debug, Clone, PartialEq)]
99-
pub struct FragmentSpread {
99+
pub struct FragmentSpread<'a> {
100100
pub position: Pos,
101-
pub fragment_name: Name,
102-
pub directives: Vec<Directive>,
101+
pub fragment_name: Name<'a>,
102+
pub directives: Vec<Directive<'a>>,
103103
}
104104

105105
#[derive(Debug, Clone, PartialEq)]
106-
pub enum TypeCondition {
107-
On(Name),
106+
pub enum TypeCondition<'a> {
107+
On(Name<'a>),
108108
}
109109

110110
#[derive(Debug, Clone, PartialEq)]
111-
pub struct InlineFragment {
111+
pub struct InlineFragment<'a> {
112112
pub position: Pos,
113-
pub type_condition: Option<TypeCondition>,
114-
pub directives: Vec<Directive>,
115-
pub selection_set: SelectionSet,
113+
pub type_condition: Option<TypeCondition<'a>>,
114+
pub directives: Vec<Directive<'a>>,
115+
pub selection_set: SelectionSet<'a>,
116116
}

0 commit comments

Comments
 (0)