Skip to content

Commit d9d8f3a

Browse files
committed
Resculpt ast::Type, vol.3
1 parent b8027e7 commit d9d8f3a

File tree

5 files changed

+46
-127
lines changed

5 files changed

+46
-127
lines changed

juniper/src/ast.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ pub enum TypeModifier {
1818

1919
pub(crate) type BorrowedType<'a> = Type<&'a str, &'a [TypeModifier]>;
2020

21+
impl Copy for BorrowedType<'_> {}
22+
2123
/// Type literal in a syntax tree.
2224
///
2325
/// Carries no semantic information and might refer to types that don't exist.
@@ -80,6 +82,13 @@ impl<'a> BorrowedType<'a> {
8082
},
8183
}
8284
}
85+
pub(crate) fn list_inner_borrowed(&self) -> Option<BorrowedType<'a>> {
86+
match self.modifiers.as_ref().last() {
87+
Some(TypeModifier::NonNull) => self.inner_borrowed().list_inner_borrowed(),
88+
Some(TypeModifier::List(..)) => Some(self.inner_borrowed()),
89+
None => None,
90+
}
91+
}
8392

8493
pub(crate) fn borrowed_name(&self) -> &'a str {
8594
self.name

juniper/src/schema/model.rs

Lines changed: 0 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -746,86 +746,6 @@ mod concrete_type_sort {
746746
}
747747
}
748748

749-
/// Allows seeing [`Type`] with different name/string representations
750-
/// as the same type without allocation.
751-
// TODO: Ideally this type should not exist, but the reason it currently does is that `Type` has a
752-
// recursive design to allow arbitrary number of list wrappings.
753-
// The list layout could instead be modelled as a modifier so that type becomes a tuple of
754-
// (name, modifier).
755-
// If `Type` is modelled like this it becomes easier to project it as a borrowed version of
756-
// itself, i.e. [Type<ArcStr>] vs [Type<&str>].
757-
#[derive(Clone, Copy, Debug)]
758-
pub enum DynType<'a> {
759-
Named(&'a str),
760-
List(&'a dyn AsDynType, Option<usize>),
761-
NonNullNamed(&'a str),
762-
NonNullList(&'a dyn AsDynType, Option<usize>),
763-
}
764-
765-
impl<'a> DynType<'a> {
766-
pub fn equals(&self, other: &DynType) -> bool {
767-
match (self, other) {
768-
(Self::Named(n0), DynType::Named(n1)) => n0 == n1,
769-
(Self::List(t0, s0), DynType::List(t1, s1)) => {
770-
t0.as_dyn_type().equals(&t1.as_dyn_type()) && s0 == s1
771-
}
772-
(Self::NonNullNamed(n0), DynType::NonNullNamed(n1)) => n0 == n1,
773-
(Self::NonNullList(t0, s0), DynType::NonNullList(t1, s1)) => {
774-
t0.as_dyn_type().equals(&t1.as_dyn_type()) && s0 == s1
775-
}
776-
_ => false,
777-
}
778-
}
779-
780-
pub fn innermost_name(&self) -> &'a str {
781-
match self {
782-
Self::Named(n) | Self::NonNullNamed(n) => n,
783-
Self::List(l, _) | Self::NonNullList(l, _) => l.as_dyn_type().innermost_name(),
784-
}
785-
}
786-
}
787-
788-
impl fmt::Display for DynType<'_> {
789-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
790-
match self {
791-
Self::Named(n) => write!(f, "{n}"),
792-
Self::NonNullNamed(n) => write!(f, "{n}!"),
793-
Self::List(t, _) => write!(f, "[{}]", t.as_dyn_type()),
794-
Self::NonNullList(t, _) => write!(f, "[{}]!", t.as_dyn_type()),
795-
}
796-
}
797-
}
798-
799-
/// Conversion of a [`Type`] into a [`DynType`].
800-
pub trait AsDynType: fmt::Debug {
801-
/// Project this value as a [`DynType`].
802-
///
803-
/// Should not allocate memory.
804-
fn as_dyn_type(&self) -> DynType<'_>;
805-
}
806-
807-
impl AsDynType for Type<ArcStr> {
808-
fn as_dyn_type(&self) -> DynType<'_> {
809-
match self {
810-
Self::Named(n) => DynType::Named(n.as_str()),
811-
Self::List(t, s) => DynType::List(t.as_ref(), *s),
812-
Self::NonNullNamed(n) => DynType::NonNullNamed(n.as_str()),
813-
Self::NonNullList(t, s) => DynType::NonNullList(t.as_ref(), *s),
814-
}
815-
}
816-
}
817-
818-
impl AsDynType for Type<&str> {
819-
fn as_dyn_type(&self) -> DynType<'_> {
820-
match self {
821-
Self::Named(n) => DynType::Named(n),
822-
Self::List(t, s) => DynType::List(t.as_ref(), *s),
823-
Self::NonNullNamed(n) => DynType::NonNullNamed(n),
824-
Self::NonNullList(t, s) => DynType::NonNullList(t.as_ref(), *s),
825-
}
826-
}
827-
}
828-
829749
#[cfg(test)]
830750
mod root_node_test {
831751
#[cfg(feature = "schema-language")]

juniper/src/validation/context.rs

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,11 @@ use std::{
44
};
55

66
use crate::{
7-
ast::{Definition, Document},
8-
schema::model::DynType,
7+
ast::{BorrowedType, Definition, Document, Type, TypeModifier},
8+
parser::SourcePosition,
9+
schema::{meta::MetaType, model::SchemaType},
910
};
1011

11-
use crate::schema::{meta::MetaType, model::SchemaType};
12-
13-
use crate::parser::SourcePosition;
14-
1512
/// Query validation error
1613
#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
1714
pub struct RuleError {
@@ -24,9 +21,9 @@ pub struct ValidatorContext<'a, S: Debug + 'a> {
2421
pub schema: &'a SchemaType<S>,
2522
errors: Vec<RuleError>,
2623
type_stack: Vec<Option<&'a MetaType<S>>>,
27-
type_literal_stack: Vec<Option<DynType<'a>>>,
24+
type_literal_stack: Vec<Option<BorrowedType<'a>>>,
2825
input_type_stack: Vec<Option<&'a MetaType<S>>>,
29-
input_type_literal_stack: Vec<Option<DynType<'a>>>,
26+
input_type_literal_stack: Vec<Option<BorrowedType<'a>>>,
3027
parent_type_stack: Vec<Option<&'a MetaType<S>>>,
3128
fragment_names: HashSet<&'a str>,
3229
}
@@ -112,10 +109,12 @@ impl<'a, S: Debug> ValidatorContext<'a, S> {
112109
}
113110

114111
#[doc(hidden)]
115-
pub fn with_pushed_type<F, R>(&mut self, t: Option<DynType<'a>>, f: F) -> R
112+
pub fn with_pushed_type<F, R>(&mut self, t: Option<impl Into<BorrowedType<'a>>>, f: F) -> R
116113
where
117114
F: FnOnce(&mut ValidatorContext<'a, S>) -> R,
118115
{
116+
let t = t.map(Into::into);
117+
119118
if let Some(t) = t {
120119
self.type_stack
121120
.push(self.schema.concrete_type_by_name(t.innermost_name()));
@@ -147,10 +146,16 @@ impl<'a, S: Debug> ValidatorContext<'a, S> {
147146
}
148147

149148
#[doc(hidden)]
150-
pub fn with_pushed_input_type<F, R>(&mut self, t: Option<DynType<'a>>, f: F) -> R
149+
pub fn with_pushed_input_type<F, R>(
150+
&mut self,
151+
t: Option<impl Into<BorrowedType<'a>>>,
152+
f: F,
153+
) -> R
151154
where
152155
F: FnOnce(&mut ValidatorContext<'a, S>) -> R,
153156
{
157+
let t = t.map(Into::into);
158+
154159
if let Some(t) = t {
155160
self.input_type_stack
156161
.push(self.schema.concrete_type_by_name(t.innermost_name()));
@@ -174,7 +179,7 @@ impl<'a, S: Debug> ValidatorContext<'a, S> {
174179
}
175180

176181
#[doc(hidden)]
177-
pub fn current_type_literal(&self) -> Option<DynType<'a>> {
182+
pub fn current_type_literal(&self) -> Option<BorrowedType<'a>> {
178183
match self.type_literal_stack.last() {
179184
Some(Some(t)) => Some(*t),
180185
_ => None,
@@ -187,7 +192,7 @@ impl<'a, S: Debug> ValidatorContext<'a, S> {
187192
}
188193

189194
#[doc(hidden)]
190-
pub fn current_input_type_literal(&self) -> Option<DynType<'a>> {
195+
pub fn current_input_type_literal(&self) -> Option<BorrowedType<'a>> {
191196
match self.input_type_literal_stack.last() {
192197
Some(Some(t)) => Some(*t),
193198
_ => None,

juniper/src/validation/rules/variables_in_allowed_position.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,8 @@ use std::{
55

66
use crate::{
77
Span,
8-
ast::{Document, Fragment, FragmentSpread, Operation, Type, TypeModifier, VariableDefinition},
8+
ast::{Document, Fragment, FragmentSpread, Operation, BorrowedType, TypeModifier, VariableDefinition},
99
parser::Spanning,
10-
schema::model::{AsDynType, DynType},
1110
validation::{ValidatorContext, Visitor},
1211
value::ScalarValue,
1312
};
@@ -29,7 +28,7 @@ pub fn factory<'a, S: fmt::Debug>() -> VariableInAllowedPosition<'a, S> {
2928

3029
pub struct VariableInAllowedPosition<'a, S: fmt::Debug + 'a> {
3130
spreads: HashMap<Scope<'a>, HashSet<&'a str>>,
32-
variable_usages: HashMap<Scope<'a>, Vec<(SpannedInput<'a, String>, DynType<'a>)>>,
31+
variable_usages: HashMap<Scope<'a>, Vec<(SpannedInput<'a, String>, BorrowedType<'a>)>>,
3332
#[expect(clippy::type_complexity, reason = "readable enough")]
3433
variable_defs: HashMap<Scope<'a>, Vec<&'a (Spanning<&'a str>, VariableDefinition<'a, S>)>>,
3534
current_scope: Option<Scope<'a>>,

juniper/src/validation/visitor.rs

Lines changed: 18 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@ use crate::{
22
ast::{
33
Arguments, Definition, Directive, Document, Field, Fragment, FragmentSpread,
44
InlineFragment, InputValue, Operation, OperationType, Selection, VariableDefinitions,
5+
Type,
56
},
67
parser::Spanning,
78
schema::{
89
meta::Argument,
9-
model::{AsDynType, DynType},
1010
},
1111
validation::{ValidatorContext, Visitor, multi_visitor::MultiVisitorCons},
1212
value::ScalarValue,
@@ -32,25 +32,23 @@ where
3232
V: Visitor<'a, S>,
3333
{
3434
for def in d {
35-
let def_type = match *def {
35+
let def_type = match def {
3636
Definition::Fragment(Spanning {
3737
item:
3838
Fragment {
3939
type_condition: Spanning { item: name, .. },
4040
..
4141
},
4242
..
43-
}) => Some(DynType::NonNullNamed(name)),
43+
}) => Some(Type::named(*name).wrap_non_null()),
4444
Definition::Operation(Spanning {
4545
item:
4646
Operation {
4747
operation_type: OperationType::Query,
4848
..
4949
},
5050
..
51-
}) => Some(DynType::NonNullNamed(
52-
ctx.schema.concrete_query_type().name().unwrap(),
53-
)),
51+
}) => Some(ctx.schema.concrete_query_type().as_type()),
5452
Definition::Operation(Spanning {
5553
item:
5654
Operation {
@@ -61,7 +59,7 @@ where
6159
}) => ctx
6260
.schema
6361
.concrete_mutation_type()
64-
.map(|t| DynType::NonNullNamed(t.name().unwrap())),
62+
.map(|t| t.as_type()),
6563
Definition::Operation(Spanning {
6664
item:
6765
Operation {
@@ -72,10 +70,10 @@ where
7270
}) => ctx
7371
.schema
7472
.concrete_subscription_type()
75-
.map(|t| DynType::NonNullNamed(t.name().unwrap())),
73+
.map(|t| t.as_type()),
7674
};
7775

78-
ctx.with_pushed_type(def_type, |ctx| {
76+
ctx.with_pushed_type(def_type.as_ref(), |ctx| {
7977
enter_definition(v, ctx, def);
8078
visit_definition(v, ctx, def);
8179
exit_definition(v, ctx, def);
@@ -135,7 +133,7 @@ fn visit_variable_definitions<'a, S, V>(
135133
for def in defs.item.iter() {
136134
let var_type = &def.1.var_type.item;
137135

138-
ctx.with_pushed_input_type(Some(var_type.as_dyn_type()), |ctx| {
136+
ctx.with_pushed_input_type(Some(var_type), |ctx| {
139137
v.enter_variable_definition(ctx, def);
140138

141139
if let Some(ref default_value) = def.1.default_value {
@@ -196,8 +194,7 @@ fn visit_arguments<'a, S, V>(
196194
for argument in arguments.item.iter() {
197195
let arg_type = meta_args
198196
.and_then(|args| args.iter().find(|a| a.name == argument.0.item))
199-
.map(|a| &a.arg_type)
200-
.map(|t| t.as_dyn_type());
197+
.map(|a| &a.arg_type);
201198

202199
ctx.with_pushed_input_type(arg_type, |ctx| {
203200
v.enter_argument(ctx, argument);
@@ -256,7 +253,7 @@ fn visit_field<'a, S, V>(
256253
.parent_type()
257254
.and_then(|t| t.field_by_name(field.item.name.item));
258255

259-
let field_type = meta_field.map(|f| f.field_type.as_dyn_type());
256+
let field_type = meta_field.map(|f| &f.field_type);
260257
let field_args = meta_field.and_then(|f| f.arguments.as_ref());
261258

262259
ctx.with_pushed_type(field_type, |ctx| {
@@ -291,7 +288,7 @@ fn visit_fragment_spread<'a, S, V>(
291288
fn visit_inline_fragment<'a, S, V>(
292289
v: &mut V,
293290
ctx: &mut ValidatorContext<'a, S>,
294-
fragment: &'a Spanning<InlineFragment<S>>,
291+
fragment: &'a Spanning<InlineFragment<'a, S>>,
295292
) where
296293
S: ScalarValue,
297294
V: Visitor<'a, S>,
@@ -309,7 +306,7 @@ fn visit_inline_fragment<'a, S, V>(
309306
item: type_name, ..
310307
}) = fragment.item.type_condition
311308
{
312-
ctx.with_pushed_type(Some(DynType::NonNullNamed(type_name)), visit_fn);
309+
ctx.with_pushed_type(Some(&Type::<&str>::named(type_name).wrap_non_null()), visit_fn);
313310
} else {
314311
visit_fn(ctx);
315312
}
@@ -325,20 +322,14 @@ fn visit_input_value<'a, S, V>(
325322
{
326323
enter_input_value(v, ctx, input_value);
327324

328-
match input_value.item {
329-
InputValue::Object(ref fields) => {
325+
match &input_value.item {
326+
InputValue::Object(fields) => {
330327
for (key, value) in fields {
331328
let inner_type = ctx
332329
.current_input_type_literal()
333-
.and_then(|t| match t {
334-
DynType::NonNullNamed(name) | DynType::Named(name) => {
335-
ctx.schema.concrete_type_by_name(name)
336-
}
337-
_ => None,
338-
})
330+
.and_then(|t| t.name().and_then(|n| ctx.schema.concrete_type_by_name(n)))
339331
.and_then(|ct| ct.input_field_by_name(&key.item))
340-
.map(|f| &f.arg_type)
341-
.map(|t| t.as_dyn_type());
332+
.map(|f| &f.arg_type);
342333

343334
ctx.with_pushed_input_type(inner_type, |ctx| {
344335
v.enter_object_field(ctx, (key.as_ref(), value.as_ref()));
@@ -347,13 +338,8 @@ fn visit_input_value<'a, S, V>(
347338
})
348339
}
349340
}
350-
InputValue::List(ref ls) => {
351-
let inner_type = ctx.current_input_type_literal().and_then(|t| match t {
352-
DynType::List(inner, _) | DynType::NonNullList(inner, _) => {
353-
Some(inner.as_dyn_type())
354-
}
355-
_ => None,
356-
});
341+
InputValue::List(ls) => {
342+
let inner_type = ctx.current_input_type_literal().and_then(|t| t.list_inner_borrowed());
357343

358344
ctx.with_pushed_input_type(inner_type, |ctx| {
359345
for value in ls {

0 commit comments

Comments
 (0)