Skip to content

Commit f3e7414

Browse files
Remove DynType and resculpt ast::Type (#1322)
Co-authored-by: Audun Halland <[email protected]>
1 parent cc87d37 commit f3e7414

File tree

12 files changed

+401
-273
lines changed

12 files changed

+401
-273
lines changed

juniper/CHANGELOG.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,12 @@ All user visible changes to `juniper` crate will be documented in this file. Thi
3636
- `ast::Type`:
3737
- Removed lifetime parameters.
3838
- Made it generic over string type.
39+
- Remade as a struct with methods: ([#1322])
40+
- Added `modifier()` and `modifiers()` methods returning `TypeModifier`.
41+
- Added `is_list()` method.
42+
- Added `wrap_list()` and `wrap_non_null()` methods.
43+
- Added `nullable()` constructor.
44+
- Added `BorrowedType` representation.
3945
- `MetaType`:
4046
- Removed lifetime parameters.
4147
- Made `name()`, `description()` and `specified_by_url()` methods returning `ArcStr`.
@@ -53,7 +59,6 @@ All user visible changes to `juniper` crate will be documented in this file. Thi
5359
- Made `name` and `description` fields using `ArcStr`.
5460
- `SchemaType`:
5561
- Removed lifetime parameters.
56-
- Made `is_subtype()` method accepting `DynType` instead of `Type`.
5762
- `RootNode`:
5863
- Removed lifetime parameters.
5964
- `Registry`:
@@ -153,6 +158,7 @@ All user visible changes to `juniper` crate will be documented in this file. Thi
153158
[#1293]: /../../pull/1293
154159
[#1311]: /../../pull/1311
155160
[#1318]: /../../pull/1318
161+
[#1322]: /../../pull/1322
156162
[#1324]: /../../pull/1324
157163
[#1327]: /../../pull/1327
158164
[#1329]: /../../pull/1329

juniper/src/ast.rs

Lines changed: 250 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,79 +1,290 @@
1-
use std::{borrow::Cow, fmt, hash::Hash, slice, vec};
1+
use std::{borrow::Cow, fmt, hash::Hash, mem, slice, vec};
22

33
use arcstr::ArcStr;
44
use compact_str::CompactString;
5-
65
use indexmap::IndexMap;
76

7+
#[cfg(doc)]
8+
use self::TypeModifier::{List, NonNull};
89
use crate::{
910
executor::Variables,
1011
parser::Spanning,
1112
value::{DefaultScalarValue, Scalar, ScalarValue, ToScalarValue},
1213
};
1314

15+
/// Possible modifiers in a [`Type`] literal.
16+
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
17+
pub enum TypeModifier {
18+
/// Non-`null` type (e.g. `<type>!`).
19+
NonNull,
20+
21+
/// List of types (e.g. `[<type>]`).
22+
List(Option<usize>),
23+
}
24+
25+
/// Owned slice of [`TypeModifier`]s.
26+
#[derive(Clone, Debug)]
27+
pub enum TypeModifiers {
28+
/// [`TypeModifier`]s known statically.
29+
Static(&'static [TypeModifier]),
30+
31+
/// [`TypeModifier`]s built dynamically.
32+
Dynamic(Box<[TypeModifier]>),
33+
}
34+
35+
impl Default for TypeModifiers {
36+
fn default() -> Self {
37+
Self::Static(&[])
38+
}
39+
}
40+
41+
impl AsRef<[TypeModifier]> for TypeModifiers {
42+
fn as_ref(&self) -> &[TypeModifier] {
43+
match self {
44+
Self::Static(s) => s,
45+
Self::Dynamic(bs) => bs,
46+
}
47+
}
48+
}
49+
50+
impl Extend<TypeModifier> for TypeModifiers {
51+
fn extend<T: IntoIterator<Item = TypeModifier>>(&mut self, iter: T) {
52+
for modifier in iter {
53+
self.wrap(modifier);
54+
}
55+
}
56+
}
57+
58+
impl TypeModifiers {
59+
/// Wraps these [`TypeModifiers`] into the provided [`TypeModifier`].
60+
fn wrap(&mut self, modifier: TypeModifier) {
61+
*self = match (mem::take(self), modifier) {
62+
(Self::Static(&[]), TypeModifier::NonNull) => Self::Static(&[TypeModifier::NonNull]),
63+
(Self::Static(&[]), TypeModifier::List(None)) => {
64+
Self::Static(&[TypeModifier::List(None)])
65+
}
66+
(Self::Static(&[TypeModifier::NonNull]), TypeModifier::List(None)) => {
67+
Self::Static(&[TypeModifier::NonNull, TypeModifier::List(None)])
68+
}
69+
(Self::Static(s), modifier) => {
70+
let mut vec: Vec<_> = s.to_vec();
71+
vec.push(modifier);
72+
Self::Dynamic(vec.into_boxed_slice())
73+
}
74+
(Self::Dynamic(s), modifier) => {
75+
let mut vec = s.into_vec();
76+
vec.push(modifier);
77+
Self::Dynamic(vec.into_boxed_slice())
78+
}
79+
};
80+
}
81+
82+
/// Removes the last [`TypeModifier`] from these [`TypeModifiers`], if there is any.
83+
fn pop(&mut self) {
84+
*self = match mem::take(self) {
85+
Self::Static(s) => Self::Static(&s[..s.len() - 1]),
86+
Self::Dynamic(s) if s.len() == 1 => Self::Static(&[]),
87+
Self::Dynamic(s) => {
88+
let mut vec = s.into_vec();
89+
vec.pop();
90+
Self::Dynamic(vec.into_boxed_slice())
91+
}
92+
}
93+
}
94+
}
95+
1496
/// Type literal in a syntax tree.
1597
///
16-
/// This enum carries no semantic information and might refer to types that do not exist.
17-
#[derive(Clone, Debug, Eq, PartialEq)]
18-
pub enum Type<N = ArcStr> {
19-
/// `null`able named type, e.g. `String`.
20-
Named(N),
98+
/// Carries no semantic information and might refer to types that don't exist.
99+
#[derive(Clone, Copy, Debug)]
100+
pub struct Type<N = ArcStr, M = TypeModifiers> {
101+
/// Name of this [`Type`].
102+
name: N,
21103

22-
/// `null`able list type, e.g. `[String]`.
104+
/// Modifiers of this [`Type`].
23105
///
24-
/// The list itself is `null`able, the containing [`Type`] might be non-`null`.
25-
List(Box<Type<N>>, Option<usize>),
106+
/// The first one is the innermost one.
107+
modifiers: M,
108+
}
26109

27-
/// Non-`null` named type, e.g. `String!`.
28-
NonNullNamed(N),
110+
impl<N, M> Eq for Type<N, M> where Self: PartialEq {}
29111

30-
/// Non-`null` list type, e.g. `[String]!`.
31-
///
32-
/// The list itself is non-`null`, the containing [`Type`] might be `null`able.
33-
NonNullList(Box<Type<N>>, Option<usize>),
112+
impl<N1, N2, M1, M2> PartialEq<Type<N2, M2>> for Type<N1, M1>
113+
where
114+
N1: AsRef<str>,
115+
N2: AsRef<str>,
116+
M1: AsRef<[TypeModifier]>,
117+
M2: AsRef<[TypeModifier]>,
118+
{
119+
fn eq(&self, other: &Type<N2, M2>) -> bool {
120+
self.name.as_ref() == other.name.as_ref()
121+
&& self.modifiers.as_ref() == other.modifiers.as_ref()
122+
}
34123
}
35124

36-
impl<N: fmt::Display> fmt::Display for Type<N> {
125+
impl<N, M> fmt::Display for Type<N, M>
126+
where
127+
N: AsRef<str>,
128+
M: AsRef<[TypeModifier]>,
129+
{
37130
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
38-
match self {
39-
Self::Named(n) => write!(f, "{n}"),
40-
Self::NonNullNamed(n) => write!(f, "{n}!"),
41-
Self::List(t, _) => write!(f, "[{t}]"),
42-
Self::NonNullList(t, _) => write!(f, "[{t}]!"),
131+
match self.modifier() {
132+
Some(TypeModifier::NonNull) => write!(f, "{}!", self.borrow_inner()),
133+
Some(TypeModifier::List(..)) => write!(f, "[{}]", self.borrow_inner()),
134+
None => write!(f, "{}", self.name.as_ref()),
43135
}
44136
}
45137
}
46138

47-
impl<N: AsRef<str>> Type<N> {
48-
/// Returns the name of this named [`Type`].
139+
impl<'a, N, M> From<&'a Type<N, M>> for BorrowedType<'a>
140+
where
141+
N: AsRef<str>,
142+
M: AsRef<[TypeModifier]>,
143+
{
144+
fn from(value: &'a Type<N, M>) -> Self {
145+
Self {
146+
name: value.name.as_ref(),
147+
modifiers: value.modifiers.as_ref(),
148+
}
149+
}
150+
}
151+
152+
impl<N: AsRef<str>, M: AsRef<[TypeModifier]>> Type<N, M> {
153+
/// Borrows the inner [`Type`] of this modified [`Type`], removing its topmost [`TypeModifier`].
154+
///
155+
/// # Panics
156+
///
157+
/// If this [`Type`] has no [`TypeModifier`]s.
158+
pub(crate) fn borrow_inner(&self) -> BorrowedType<'_> {
159+
let modifiers = self.modifiers.as_ref();
160+
match modifiers.len() {
161+
0 => panic!("no inner `Type` available"),
162+
n => Type {
163+
name: self.name.as_ref(),
164+
modifiers: &modifiers[..n - 1],
165+
},
166+
}
167+
}
168+
169+
/// Returns the name of this [`Type`].
49170
///
50-
/// Only applies to named [`Type`]s. Lists will return [`None`].
171+
/// [`List`]s will return [`None`].
51172
#[must_use]
52173
pub fn name(&self) -> Option<&str> {
53-
match self {
54-
Self::Named(n) | Self::NonNullNamed(n) => Some(n.as_ref()),
55-
Self::List(..) | Self::NonNullList(..) => None,
56-
}
174+
(!self.is_list()).then(|| self.name.as_ref())
57175
}
58176

59-
/// Returns the innermost name of this [`Type`] by unpacking lists.
177+
/// Returns the innermost name of this [`Type`] by unpacking [`List`]s.
60178
///
61-
/// All [`Type`] literals contain exactly one named type.
179+
/// All [`Type`] literals contain exactly one name.
62180
#[must_use]
63181
pub fn innermost_name(&self) -> &str {
64-
match self {
65-
Self::Named(n) | Self::NonNullNamed(n) => n.as_ref(),
66-
Self::List(l, ..) | Self::NonNullList(l, ..) => l.innermost_name(),
67-
}
182+
self.name.as_ref()
183+
}
184+
185+
/// Returns the topmost [`TypeModifier`] of this [`Type`], if any.
186+
#[must_use]
187+
pub fn modifier(&self) -> Option<&TypeModifier> {
188+
self.modifiers().last()
189+
}
190+
191+
/// Returns [`TypeModifier`]s of this [`Type`], if any.
192+
///
193+
/// The first one is the innermost one.
194+
#[must_use]
195+
pub fn modifiers(&self) -> &[TypeModifier] {
196+
self.modifiers.as_ref()
68197
}
69198

70-
/// Indicates whether this [`Type`] can only represent non-`null` values.
199+
/// Indicates whether this [`Type`] is [`NonNull`].
71200
#[must_use]
72201
pub fn is_non_null(&self) -> bool {
73-
match self {
74-
Self::NonNullList(..) | Self::NonNullNamed(..) => true,
75-
Self::List(..) | Self::Named(..) => false,
202+
match self.modifiers.as_ref().last() {
203+
Some(TypeModifier::NonNull) => true,
204+
Some(TypeModifier::List(..)) | None => false,
205+
}
206+
}
207+
208+
/// Indicates whether this [`Type`] represents a [`List`] (either `null`able or [`NonNull`]).
209+
#[must_use]
210+
pub fn is_list(&self) -> bool {
211+
match self.modifiers.as_ref().last() {
212+
Some(TypeModifier::NonNull) => self.borrow_inner().is_non_null(),
213+
Some(TypeModifier::List(..)) => true,
214+
None => false,
215+
}
216+
}
217+
}
218+
219+
impl<N, M: Default> Type<N, M> {
220+
/// Creates a new `null`able [`Type`] literal from the provided `name`.
221+
#[must_use]
222+
pub fn nullable(name: impl Into<N>) -> Self {
223+
Self {
224+
name: name.into(),
225+
modifiers: M::default(),
226+
}
227+
}
228+
}
229+
230+
impl<N, M: Extend<TypeModifier>> Type<N, M> {
231+
/// Wraps this [`Type`] into the provided [`TypeModifier`].
232+
fn wrap(mut self, modifier: TypeModifier) -> Self {
233+
self.modifiers.extend([modifier]);
234+
self
235+
}
236+
237+
/// Wraps this [`Type`] into a [`List`] with the provided `expected_size`, if any.
238+
#[must_use]
239+
pub fn wrap_list(self, expected_size: Option<usize>) -> Self {
240+
self.wrap(TypeModifier::List(expected_size))
241+
}
242+
243+
/// Wraps this [`Type`] as a [`NonNull`] one.
244+
#[must_use]
245+
pub fn wrap_non_null(self) -> Self {
246+
self.wrap(TypeModifier::NonNull)
247+
}
248+
}
249+
250+
impl<N: AsRef<str>> Type<N> {
251+
/// Strips this [`Type`] from [`NonNull`], returning it as a `null`able one.
252+
pub(crate) fn into_nullable(mut self) -> Self {
253+
if self.is_non_null() {
254+
self.modifiers.pop();
255+
}
256+
self
257+
}
258+
}
259+
260+
/// Borrowed variant of a [`Type`] literal.
261+
pub(crate) type BorrowedType<'a> = Type<&'a str, &'a [TypeModifier]>;
262+
263+
impl<'a> BorrowedType<'a> {
264+
/// Creates a [`NonNull`] [`BorrowedType`] literal from the provided `name`.
265+
pub(crate) fn non_null(name: &'a str) -> Self {
266+
Self {
267+
name,
268+
modifiers: &[TypeModifier::NonNull],
269+
}
270+
}
271+
272+
/// Borrows the inner [`Type`] of this [`List`] [`Type`], if it represents one.
273+
pub(crate) fn borrow_list_inner(&self) -> Option<Self> {
274+
let mut out = None;
275+
for (n, m) in self.modifiers.iter().enumerate().rev() {
276+
match m {
277+
TypeModifier::NonNull => {}
278+
TypeModifier::List(..) => {
279+
out = Some(Self {
280+
name: self.name,
281+
modifiers: &self.modifiers[..n],
282+
});
283+
break;
284+
}
285+
}
76286
}
287+
out
77288
}
78289
}
79290

juniper/src/executor/mod.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1161,7 +1161,10 @@ impl<S> Registry<S> {
11611161
if let Some(name) = T::name(info) {
11621162
let validated_name = Name::new(name.clone()).unwrap();
11631163
if !self.types.contains_key(&name) {
1164-
self.insert_placeholder(validated_name.clone(), Type::NonNullNamed(name.clone()));
1164+
self.insert_placeholder(
1165+
validated_name.clone(),
1166+
Type::nullable(name.clone()).wrap_non_null(),
1167+
);
11651168
let meta = T::meta(info, self);
11661169
self.types.insert(validated_name, meta);
11671170
}

0 commit comments

Comments
 (0)