Skip to content

Commit b8027e7

Browse files
committed
Resculpt ast::Type, vol.2
1 parent 2c6fed0 commit b8027e7

File tree

11 files changed

+176
-97
lines changed

11 files changed

+176
-97
lines changed

juniper/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ rust_decimal = { version = "1.20", default-features = false, optional = true }
6161
ryu = { version = "1.0", optional = true }
6262
serde = { version = "1.0.122", features = ["derive"] }
6363
serde_json = { version = "1.0.18", features = ["std"], default-features = false, optional = true }
64+
smallvec = "1.15"
6465
static_assertions = "1.1"
6566
time = { version = "0.3.37", features = ["formatting", "macros", "parsing"], optional = true }
6667
url = { version = "2.0", optional = true }

juniper/src/ast.rs

Lines changed: 92 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use std::{borrow::Cow, fmt, hash::Hash, slice, vec};
22

33
use arcstr::ArcStr;
4-
54
use indexmap::IndexMap;
5+
use smallvec::{SmallVec, smallvec};
66

77
use crate::{
88
executor::Variables,
@@ -22,7 +22,7 @@ pub(crate) type BorrowedType<'a> = Type<&'a str, &'a [TypeModifier]>;
2222
///
2323
/// Carries no semantic information and might refer to types that don't exist.
2424
#[derive(Clone, Debug)]
25-
pub struct Type<N = ArcStr, M = Box<[TypeModifier]>> {
25+
pub struct Type<N = ArcStr, M = SmallVec<[TypeModifier; 2]>> {
2626
name: N,
2727
modifiers: M,
2828
}
@@ -48,27 +48,56 @@ where
4848
M: AsRef<[TypeModifier]>,
4949
{
5050
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
51-
// PANIC: `self.inner().unwrap()` never panics if there is at least on `TypeModifier`.
52-
match self.modifiers.as_ref().last() {
53-
Some(TypeModifier::NonNull) => write!(f, "{}!", self.inner().unwrap()),
54-
Some(TypeModifier::List(..)) => write!(f, "[{}]", self.inner().unwrap()),
51+
match self.modifier() {
52+
Some(TypeModifier::NonNull) => write!(f, "{}!", self.inner()),
53+
Some(TypeModifier::List(..)) => write!(f, "[{}]", self.inner()),
5554
None => write!(f, "{}", self.name.as_ref()),
5655
}
5756
}
5857
}
5958

59+
impl<'a, N, M> From<&'a Type<N, M>> for BorrowedType<'a>
60+
where
61+
N: AsRef<str>,
62+
M: AsRef<[TypeModifier]>,
63+
{
64+
fn from(value: &'a Type<N, M>) -> Self {
65+
Self {
66+
name: value.name.as_ref(),
67+
modifiers: value.modifiers.as_ref(),
68+
}
69+
}
70+
}
71+
72+
impl<'a> BorrowedType<'a> {
73+
pub(crate) fn inner_borrowed(&self) -> BorrowedType<'a> {
74+
let modifiers = self.modifiers.as_ref();
75+
match modifiers.len() {
76+
0 => unreachable!(),
77+
n => Type {
78+
name: self.name,
79+
modifiers: &modifiers[..n - 1],
80+
},
81+
}
82+
}
83+
84+
pub(crate) fn borrowed_name(&self) -> &'a str {
85+
self.name
86+
}
87+
}
88+
6089
impl<N: AsRef<str>, M> Type<N, M> {
61-
pub(crate) fn inner(&self) -> Option<BorrowedType<'_>>
90+
pub(crate) fn inner(&self) -> BorrowedType<'_>
6291
where
6392
M: AsRef<[TypeModifier]>,
6493
{
6594
let modifiers = self.modifiers.as_ref();
6695
match modifiers.len() {
67-
0 => None,
68-
n => Some(Type {
96+
0 => unreachable!(),
97+
n => Type {
6998
name: self.name.as_ref(),
7099
modifiers: &modifiers[..n - 1],
71-
}),
100+
},
72101
}
73102
}
74103

@@ -100,6 +129,15 @@ impl<N: AsRef<str>, M> Type<N, M> {
100129
self.name.as_ref()
101130
}
102131

132+
/// Returns the [`TypeModifier`] of this [`Type`], if any.
133+
#[must_use]
134+
pub fn modifier(&self) -> Option<&TypeModifier>
135+
where
136+
M: AsRef<[TypeModifier]>,
137+
{
138+
self.modifiers.as_ref().last()
139+
}
140+
103141
/// Indicates whether this [`Type`] can only represent non-`null` values.
104142
#[must_use]
105143
pub fn is_non_null(&self) -> bool
@@ -111,6 +149,50 @@ impl<N: AsRef<str>, M> Type<N, M> {
111149
Some(TypeModifier::List(..)) | None => false,
112150
}
113151
}
152+
153+
#[must_use]
154+
pub fn is_list(&self) -> bool
155+
where
156+
M: AsRef<[TypeModifier]>,
157+
{
158+
match self.modifiers.as_ref().last() {
159+
Some(TypeModifier::NonNull) => self.inner().is_non_null(),
160+
Some(TypeModifier::List(..)) => true,
161+
None => false,
162+
}
163+
}
164+
}
165+
166+
impl<N: AsRef<str>> Type<N> {
167+
/// Wraps this [`Type`] into the provided [`TypeModifier`].
168+
fn wrap(mut self, modifier: TypeModifier) -> Self {
169+
self.modifiers.push(modifier);
170+
self
171+
}
172+
173+
pub fn wrap_list(self, size_hint: Option<usize>) -> Self {
174+
// TODO: assert?
175+
self.wrap(TypeModifier::List(size_hint))
176+
}
177+
178+
pub fn wrap_non_null(self) -> Self {
179+
// TODO: assert?
180+
self.wrap(TypeModifier::NonNull)
181+
}
182+
183+
pub fn nullable(mut self) -> Self {
184+
if self.is_non_null() {
185+
_ = self.modifiers.pop();
186+
}
187+
self
188+
}
189+
190+
pub fn named(name: impl Into<N>) -> Self {
191+
Self {
192+
name: name.into(),
193+
modifiers: smallvec![],
194+
}
195+
}
114196
}
115197

116198
/// A JSON-like value that can be passed into the query execution, either

juniper/src/executor/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1155,7 +1155,7 @@ impl<S> Registry<S> {
11551155
if let Some(name) = T::name(info) {
11561156
let validated_name = Name::new(name.clone()).unwrap();
11571157
if !self.types.contains_key(&name) {
1158-
self.insert_placeholder(validated_name.clone(), Type::NonNullNamed(name.clone()));
1158+
self.insert_placeholder(validated_name.clone(), Type::named(name.clone()).wrap_non_null());
11591159
let meta = T::meta(info, self);
11601160
self.types.insert(validated_name, meta);
11611161
}

juniper/src/parser/document.rs

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -517,10 +517,10 @@ pub fn parse_type<'a>(parser: &mut Parser<'a>) -> ParseResult<Type<&'a str>> {
517517
Spanning::start_end(
518518
&start_span.start,
519519
&end_pos,
520-
Type::List(Box::new(inner_type.item), None),
520+
inner_type.item.wrap_list(None),
521521
)
522522
} else {
523-
parser.expect_name()?.map(Type::Named)
523+
parser.expect_name()?.map(Type::named)
524524
};
525525

526526
Ok(match *parser.peek() {
@@ -534,15 +534,13 @@ pub fn parse_type<'a>(parser: &mut Parser<'a>) -> ParseResult<Type<&'a str>> {
534534

535535
fn wrap_non_null<'a>(
536536
parser: &mut Parser<'a>,
537-
inner: Spanning<Type<&'a str>>,
537+
mut inner: Spanning<Type<&'a str>>,
538538
) -> ParseResult<Type<&'a str>> {
539539
let end_pos = &parser.expect(&Token::ExclamationMark)?.span.end;
540540

541-
let wrapped = match inner.item {
542-
Type::Named(name) => Type::NonNullNamed(name),
543-
Type::List(l, expected_size) => Type::NonNullList(l, expected_size),
544-
ty @ (Type::NonNullList(..) | Type::NonNullNamed(..)) => ty,
545-
};
541+
if !inner.item.is_non_null() {
542+
inner.item = inner.item.wrap_non_null();
543+
}
546544

547-
Ok(Spanning::start_end(&inner.span.start, end_pos, wrapped))
545+
Ok(Spanning::start_end(&inner.span.start, end_pos, inner.item))
548546
}

juniper/src/parser/tests/value.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,8 +173,8 @@ fn input_value_literals() {
173173
),
174174
);
175175
let fields = [
176-
Argument::new("key", Type::NonNullNamed("Int".into())),
177-
Argument::new("other", Type::NonNullNamed("Bar".into())),
176+
Argument::new("key", Type::named("Int").wrap_non_null()),
177+
Argument::new("other", Type::named("Bar").wrap_non_null()),
178178
];
179179
let meta = &MetaType::InputObject(InputObjectMeta::new::<Foo>("foo", &fields));
180180
assert_eq!(

juniper/src/schema/meta.rs

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -710,18 +710,12 @@ impl<S> MetaType<S> {
710710
| Self::Interface(InterfaceMeta { name, .. })
711711
| Self::Object(ObjectMeta { name, .. })
712712
| Self::Scalar(ScalarMeta { name, .. })
713-
| Self::Union(UnionMeta { name, .. }) => Type::NonNullNamed(name.clone()),
713+
| Self::Union(UnionMeta { name, .. }) => Type::named(name.clone()).wrap_non_null(),
714714
Self::List(ListMeta {
715715
of_type,
716716
expected_size,
717-
}) => Type::NonNullList(Box::new(of_type.clone()), *expected_size),
718-
Self::Nullable(NullableMeta { of_type }) => match of_type {
719-
Type::NonNullNamed(inner) => Type::Named(inner.clone()),
720-
Type::NonNullList(inner, expected_size) => {
721-
Type::List(inner.clone(), *expected_size)
722-
}
723-
ty @ (Type::List(..) | Type::Named(..)) => ty.clone(),
724-
},
717+
}) => of_type.clone().wrap_list(*expected_size).wrap_non_null(),
718+
Self::Nullable(NullableMeta { of_type }) => of_type.clone().nullable(),
725719
Self::Placeholder(PlaceholderMeta { of_type }) => of_type.clone(),
726720
}
727721
}

juniper/src/schema/model.rs

Lines changed: 31 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use graphql_parser::schema::Document;
77

88
use crate::{
99
GraphQLEnum,
10-
ast::Type,
10+
ast::{Type, TypeModifier, TypeModifier::NonNull},
1111
executor::{Context, Registry},
1212
schema::meta::{Argument, InterfaceMeta, MetaType, ObjectMeta, PlaceholderMeta, UnionMeta},
1313
types::{base::GraphQLType, name::Name},
@@ -318,12 +318,14 @@ impl<S> SchemaType<S> {
318318
self.types.get(name.as_ref())
319319
}
320320

321-
pub(crate) fn lookup_type(&self, tpe: &Type<impl AsRef<str>>) -> Option<&MetaType<S>> {
322-
match tpe {
323-
Type::Named(name) | Type::NonNullNamed(name) => {
324-
self.concrete_type_by_name(name.as_ref())
325-
}
326-
Type::List(inner, ..) | Type::NonNullList(inner, ..) => self.lookup_type(inner),
321+
pub(crate) fn lookup_type(
322+
&self,
323+
ty: &Type<impl AsRef<str>, impl AsRef<[TypeModifier]>>,
324+
) -> Option<&MetaType<S>> {
325+
if let Some(name) = ty.name() {
326+
self.concrete_type_by_name(name)
327+
} else {
328+
self.lookup_type(&ty.inner())
327329
}
328330
}
329331

@@ -392,19 +394,15 @@ impl<S> SchemaType<S> {
392394
}
393395

394396
/// Make a type.
395-
pub fn make_type(&self, ty: &Type<impl AsRef<str>>) -> TypeType<S> {
396-
match ty {
397-
Type::List(inner, expected_size) => {
398-
TypeType::List(Box::new(self.make_type(inner)), *expected_size)
397+
pub fn make_type(&self, ty: &Type<impl AsRef<str>, impl AsRef<[TypeModifier]>>) -> TypeType<S> {
398+
match ty.modifier() {
399+
Some(TypeModifier::NonNull) => TypeType::NonNull(Box::new(self.make_type(&ty.inner()))),
400+
Some(TypeModifier::List(expected_size)) => {
401+
TypeType::List(Box::new(self.make_type(&ty.inner())), *expected_size)
399402
}
400-
Type::Named(n) => self.type_by_name(n).expect("Type not found in schema"),
401-
Type::NonNullList(inner, expected_size) => TypeType::NonNull(Box::new(TypeType::List(
402-
Box::new(self.make_type(inner)),
403-
*expected_size,
404-
))),
405-
Type::NonNullNamed(n) => TypeType::NonNull(Box::new(
406-
self.type_by_name(n).expect("Type not found in schema"),
407-
)),
403+
None => self
404+
.type_by_name(ty.innermost_name())
405+
.expect("Type not found in schema"),
408406
}
409407
}
410408

@@ -475,25 +473,27 @@ impl<S> SchemaType<S> {
475473
/// If the type is a subtype of another type.
476474
pub fn is_subtype(
477475
&self,
478-
sub_type: &Type<impl AsRef<str>>,
479-
super_type: &Type<impl AsRef<str>>,
476+
sub_type: &Type<impl AsRef<str>, impl AsRef<[TypeModifier]>>,
477+
super_type: &Type<impl AsRef<str>, impl AsRef<[TypeModifier]>>,
480478
) -> bool {
481-
use Type::*;
479+
use TypeModifier::{List, NonNull};
482480

483481
if super_type == sub_type {
484482
return true;
485483
}
486484

487-
match (super_type, sub_type) {
488-
(NonNullNamed(super_name), NonNullNamed(sub_name))
489-
| (Named(super_name), Named(sub_name))
490-
| (Named(super_name), NonNullNamed(sub_name)) => {
491-
self.is_named_subtype(sub_name.as_ref(), super_name.as_ref())
485+
match (super_type.modifier(), sub_type.modifier()) {
486+
(Some(NonNull), Some(NonNull)) => {
487+
self.is_subtype(&sub_type.inner(), &super_type.inner())
488+
}
489+
(None | Some(List(..)), Some(NonNull)) => {
490+
self.is_subtype(&sub_type.inner(), super_type)
491+
}
492+
(Some(List(..)), Some(List(..))) => {
493+
self.is_subtype(&sub_type.inner(), &super_type.inner())
492494
}
493-
(NonNullList(super_inner, _), NonNullList(sub_inner, _))
494-
| (List(super_inner, _), List(sub_inner, _))
495-
| (List(super_inner, _), NonNullList(sub_inner, _)) => {
496-
self.is_subtype(sub_inner, super_inner)
495+
(None, None) => {
496+
self.is_named_subtype(sub_type.innermost_name(), super_type.innermost_name())
497497
}
498498
_ => false,
499499
}

juniper/src/schema/translate/graphql_parser.rs

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use graphql_parser::{
1414
};
1515

1616
use crate::{
17-
ast::{InputValue, Type},
17+
ast::{BorrowedType, InputValue, Type, TypeModifier},
1818
schema::{
1919
meta::{Argument, DeprecationStatus, EnumValue, Field, MetaType},
2020
model::SchemaType,
@@ -90,7 +90,7 @@ impl GraphQLParserTranslator {
9090
position: Pos::default(),
9191
description: input.description.as_deref().map(Into::into),
9292
name: From::from(input.name.as_str()),
93-
value_type: GraphQLParserTranslator::translate_type(&input.arg_type),
93+
value_type: GraphQLParserTranslator::translate_type((&input.arg_type).into()),
9494
default_value: input
9595
.default_value
9696
.as_ref()
@@ -139,21 +139,18 @@ impl GraphQLParserTranslator {
139139
}
140140
}
141141

142-
fn translate_type<'a, T>(input: &'a Type<impl AsRef<str>>) -> ExternalType<'a, T>
142+
fn translate_type<'a, T>(input: BorrowedType<'a>) -> ExternalType<'a, T>
143143
where
144144
T: Text<'a>,
145145
{
146-
match input {
147-
Type::List(x, ..) => {
148-
ExternalType::ListType(GraphQLParserTranslator::translate_type(x).into())
146+
match input.modifier() {
147+
Some(TypeModifier::NonNull) => {
148+
ExternalType::NonNullType(Self::translate_type(input.inner_borrowed()).into())
149149
}
150-
Type::Named(x) => ExternalType::NamedType(From::from(x.as_ref())),
151-
Type::NonNullList(x, ..) => ExternalType::NonNullType(Box::new(
152-
ExternalType::ListType(Box::new(GraphQLParserTranslator::translate_type(x))),
153-
)),
154-
Type::NonNullNamed(x) => {
155-
ExternalType::NonNullType(Box::new(ExternalType::NamedType(From::from(x.as_ref()))))
150+
Some(TypeModifier::List(..)) => {
151+
ExternalType::ListType(Self::translate_type(input.inner_borrowed()).into())
156152
}
153+
None => ExternalType::NamedType(input.borrowed_name().into()),
157154
}
158155
}
159156

@@ -276,7 +273,7 @@ impl GraphQLParserTranslator {
276273
name: From::from(input.name.as_str()),
277274
description: input.description.as_deref().map(Into::into),
278275
directives: generate_directives(&input.deprecation_status),
279-
field_type: GraphQLParserTranslator::translate_type(&input.field_type),
276+
field_type: GraphQLParserTranslator::translate_type((&input.field_type).into()),
280277
arguments,
281278
}
282279
}

juniper/src/validation/context.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,8 @@ impl std::error::Error for RuleError {}
7272

7373
impl<'a, S: Debug> ValidatorContext<'a, S> {
7474
#[doc(hidden)]
75-
pub fn new(schema: &'a SchemaType<S>, document: &Document<'a, S>) -> ValidatorContext<'a, S> {
76-
ValidatorContext {
75+
pub fn new(schema: &'a SchemaType<S>, document: &Document<'a, S>) -> Self {
76+
Self {
7777
errors: Vec::new(),
7878
schema,
7979
type_stack: Vec::new(),

0 commit comments

Comments
 (0)