|
1 |
| -use std::{borrow::Cow, fmt, hash::Hash, slice, vec}; |
| 1 | +use std::{borrow::Cow, fmt, hash::Hash, mem, slice, vec}; |
2 | 2 |
|
3 | 3 | use arcstr::ArcStr;
|
4 | 4 | use compact_str::CompactString;
|
5 |
| - |
6 | 5 | use indexmap::IndexMap;
|
7 | 6 |
|
| 7 | +#[cfg(doc)] |
| 8 | +use self::TypeModifier::{List, NonNull}; |
8 | 9 | use crate::{
|
9 | 10 | executor::Variables,
|
10 | 11 | parser::Spanning,
|
11 | 12 | value::{DefaultScalarValue, Scalar, ScalarValue, ToScalarValue},
|
12 | 13 | };
|
13 | 14 |
|
| 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 | + |
14 | 96 | /// Type literal in a syntax tree.
|
15 | 97 | ///
|
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, |
21 | 103 |
|
22 |
| - /// `null`able list type, e.g. `[String]`. |
| 104 | + /// Modifiers of this [`Type`]. |
23 | 105 | ///
|
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 | +} |
26 | 109 |
|
27 |
| - /// Non-`null` named type, e.g. `String!`. |
28 |
| - NonNullNamed(N), |
| 110 | +impl<N, M> Eq for Type<N, M> where Self: PartialEq {} |
29 | 111 |
|
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 | + } |
34 | 123 | }
|
35 | 124 |
|
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 | +{ |
37 | 130 | 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()), |
43 | 135 | }
|
44 | 136 | }
|
45 | 137 | }
|
46 | 138 |
|
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`]. |
49 | 170 | ///
|
50 |
| - /// Only applies to named [`Type`]s. Lists will return [`None`]. |
| 171 | + /// [`List`]s will return [`None`]. |
51 | 172 | #[must_use]
|
52 | 173 | 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()) |
57 | 175 | }
|
58 | 176 |
|
59 |
| - /// Returns the innermost name of this [`Type`] by unpacking lists. |
| 177 | + /// Returns the innermost name of this [`Type`] by unpacking [`List`]s. |
60 | 178 | ///
|
61 |
| - /// All [`Type`] literals contain exactly one named type. |
| 179 | + /// All [`Type`] literals contain exactly one name. |
62 | 180 | #[must_use]
|
63 | 181 | 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() |
68 | 197 | }
|
69 | 198 |
|
70 |
| - /// Indicates whether this [`Type`] can only represent non-`null` values. |
| 199 | + /// Indicates whether this [`Type`] is [`NonNull`]. |
71 | 200 | #[must_use]
|
72 | 201 | 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 | + } |
76 | 286 | }
|
| 287 | + out |
77 | 288 | }
|
78 | 289 | }
|
79 | 290 |
|
|
0 commit comments