Skip to content

Commit 2c6fed0

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

File tree

2 files changed

+70
-52
lines changed

2 files changed

+70
-52
lines changed

juniper/src/ast.rs

Lines changed: 69 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -10,64 +10,85 @@ use crate::{
1010
value::{DefaultScalarValue, ScalarValue},
1111
};
1212

13+
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
14+
pub enum TypeModifier {
15+
NonNull,
16+
List(Option<usize>),
17+
}
18+
19+
pub(crate) type BorrowedType<'a> = Type<&'a str, &'a [TypeModifier]>;
20+
1321
/// Type literal in a syntax tree.
1422
///
15-
/// This enum carries no semantic information and might refer to types that do not exist.
23+
/// Carries no semantic information and might refer to types that don't exist.
1624
#[derive(Clone, Debug)]
17-
pub enum Type<N = ArcStr> {
18-
/// `null`able named type, e.g. `String`.
19-
Named(N),
20-
21-
/// `null`able list type, e.g. `[String]`.
22-
///
23-
/// The list itself is `null`able, the containing [`Type`] might be non-`null`.
24-
List(Box<Type<N>>, Option<usize>),
25-
26-
/// Non-`null` named type, e.g. `String!`.
27-
NonNullNamed(N),
28-
29-
/// Non-`null` list type, e.g. `[String]!`.
30-
///
31-
/// The list itself is non-`null`, the containing [`Type`] might be `null`able.
32-
NonNullList(Box<Type<N>>, Option<usize>),
25+
pub struct Type<N = ArcStr, M = Box<[TypeModifier]>> {
26+
name: N,
27+
modifiers: M,
3328
}
3429

35-
impl<N> Eq for Type<N> where Self: PartialEq {}
30+
impl<N, M> Eq for Type<N, M> where Self: PartialEq {}
3631

37-
impl<N1: AsRef<str>, N2: AsRef<str>> PartialEq<Type<N2>> for Type<N1> {
38-
fn eq(&self, other: &Type<N2>) -> bool {
39-
match (self, other) {
40-
(Self::Named(n1), Type::Named(n2)) => n1.as_ref() == n2.as_ref(),
41-
(Self::List(lhs, s1), Type::List(rhs, s2)) => s1 == s2 && lhs.as_ref() == rhs.as_ref(),
42-
(Self::NonNullNamed(n1), Type::NonNullNamed(n2)) => n1.as_ref() == n2.as_ref(),
43-
(Self::NonNullList(lhs, s1), Type::NonNullList(rhs, s2)) => {
44-
s1 == s2 && lhs.as_ref() == rhs.as_ref()
45-
}
46-
_ => false,
47-
}
32+
impl<N1, N2, M1, M2> PartialEq<Type<N2, M2>> for Type<N1, M1>
33+
where
34+
N1: AsRef<str>,
35+
N2: AsRef<str>,
36+
M1: AsRef<[TypeModifier]>,
37+
M2: AsRef<[TypeModifier]>,
38+
{
39+
fn eq(&self, other: &Type<N2, M2>) -> bool {
40+
self.name.as_ref() == other.name.as_ref()
41+
&& self.modifiers.as_ref() == other.modifiers.as_ref()
4842
}
4943
}
5044

51-
impl<N: fmt::Display> fmt::Display for Type<N> {
45+
impl<N, M> fmt::Display for Type<N, M>
46+
where
47+
N: AsRef<str>,
48+
M: AsRef<[TypeModifier]>,
49+
{
5250
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
53-
match self {
54-
Self::Named(n) => write!(f, "{n}"),
55-
Self::NonNullNamed(n) => write!(f, "{n}!"),
56-
Self::List(t, _) => write!(f, "[{t}]"),
57-
Self::NonNullList(t, _) => write!(f, "[{t}]!"),
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()),
55+
None => write!(f, "{}", self.name.as_ref()),
5856
}
5957
}
6058
}
6159

62-
impl<N: AsRef<str>> Type<N> {
60+
impl<N: AsRef<str>, M> Type<N, M> {
61+
pub(crate) fn inner(&self) -> Option<BorrowedType<'_>>
62+
where
63+
M: AsRef<[TypeModifier]>,
64+
{
65+
let modifiers = self.modifiers.as_ref();
66+
match modifiers.len() {
67+
0 => None,
68+
n => Some(Type {
69+
name: self.name.as_ref(),
70+
modifiers: &modifiers[..n - 1],
71+
}),
72+
}
73+
}
74+
6375
/// Returns the name of this named [`Type`].
6476
///
6577
/// Only applies to named [`Type`]s. Lists will return [`None`].
6678
#[must_use]
67-
pub fn name(&self) -> Option<&str> {
68-
match self {
69-
Self::Named(n) | Self::NonNullNamed(n) => Some(n.as_ref()),
70-
Self::List(..) | Self::NonNullList(..) => None,
79+
pub fn name(&self) -> Option<&str>
80+
where
81+
M: AsRef<[TypeModifier]>,
82+
{
83+
if self
84+
.modifiers
85+
.as_ref()
86+
.iter()
87+
.any(|m| matches!(m, TypeModifier::List(..)))
88+
{
89+
None
90+
} else {
91+
Some(self.name.as_ref())
7192
}
7293
}
7394

@@ -76,18 +97,18 @@ impl<N: AsRef<str>> Type<N> {
7697
/// All [`Type`] literals contain exactly one named type.
7798
#[must_use]
7899
pub fn innermost_name(&self) -> &str {
79-
match self {
80-
Self::Named(n) | Self::NonNullNamed(n) => n.as_ref(),
81-
Self::List(l, ..) | Self::NonNullList(l, ..) => l.innermost_name(),
82-
}
100+
self.name.as_ref()
83101
}
84102

85103
/// Indicates whether this [`Type`] can only represent non-`null` values.
86104
#[must_use]
87-
pub fn is_non_null(&self) -> bool {
88-
match self {
89-
Self::NonNullList(..) | Self::NonNullNamed(..) => true,
90-
Self::List(..) | Self::Named(..) => false,
105+
pub fn is_non_null(&self) -> bool
106+
where
107+
M: AsRef<[TypeModifier]>,
108+
{
109+
match self.modifiers.as_ref().last() {
110+
Some(TypeModifier::NonNull) => true,
111+
Some(TypeModifier::List(..)) | None => false,
91112
}
92113
}
93114
}

juniper/src/validation/rules/variables_in_allowed_position.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,10 +92,7 @@ impl<'a, S: fmt::Debug> VariableInAllowedPosition<'a, S> {
9292
(_, ty) => ty.clone(),
9393
};
9494

95-
if !ctx
96-
.schema
97-
.is_subtype(&expected_type, var_type)
98-
{
95+
if !ctx.schema.is_subtype(&expected_type, var_type) {
9996
ctx.report_error(
10097
&error_message(var_name.item, expected_type, var_type),
10198
&[var_def_name.span.start, var_name.span.start],

0 commit comments

Comments
 (0)