async_graphql/dynamic/
type_ref.rs

1use std::{
2    borrow::Cow,
3    fmt::{self, Display},
4};
5
6/// A type reference
7#[derive(Debug, Clone, Eq, PartialEq, Hash)]
8pub enum TypeRef {
9    /// Named type
10    Named(Cow<'static, str>),
11    /// Non-null type
12    NonNull(Box<TypeRef>),
13    /// List type
14    List(Box<TypeRef>),
15}
16
17impl Display for TypeRef {
18    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
19        match self {
20            TypeRef::Named(name) => write!(f, "{}", name),
21            TypeRef::NonNull(ty) => write!(f, "{}!", ty),
22            TypeRef::List(ty) => write!(f, "[{}]", ty),
23        }
24    }
25}
26
27impl TypeRef {
28    /// A int scalar type
29    pub const INT: &'static str = "Int";
30
31    /// A float scalar type
32    pub const FLOAT: &'static str = "Float";
33
34    /// A string scalar type
35    pub const STRING: &'static str = "String";
36
37    /// A boolean scalar type
38    pub const BOOLEAN: &'static str = "Boolean";
39
40    /// A ID scalar type
41    pub const ID: &'static str = "ID";
42
43    /// A Upload type
44    pub const UPLOAD: &'static str = "Upload";
45
46    /// Returns the nullable type reference
47    ///
48    /// GraphQL Type: `T`
49    #[inline]
50    pub fn named(type_name: impl Into<String>) -> TypeRef {
51        TypeRef::Named(type_name.into().into())
52    }
53
54    /// Returns the non-null type reference
55    ///
56    /// GraphQL Type: `T!`
57    #[inline]
58    pub fn named_nn(type_name: impl Into<String>) -> TypeRef {
59        TypeRef::NonNull(Box::new(TypeRef::Named(type_name.into().into())))
60    }
61
62    /// Returns a nullable list of nullable members type reference
63    ///
64    /// GraphQL Type: `[T]`
65    #[inline]
66    pub fn named_list(type_name: impl Into<String>) -> TypeRef {
67        TypeRef::List(Box::new(TypeRef::Named(type_name.into().into())))
68    }
69
70    /// Returns a nullable list of non-null members type reference
71    ///
72    /// GraphQL Type: `[T!]`
73    #[inline]
74    pub fn named_nn_list(type_name: impl Into<String>) -> TypeRef {
75        TypeRef::List(Box::new(TypeRef::NonNull(Box::new(TypeRef::Named(
76            type_name.into().into(),
77        )))))
78    }
79
80    /// Returns a non-null list of nullable members type reference
81    ///
82    /// GraphQL Type: `[T]!`
83    #[inline]
84    pub fn named_list_nn(type_name: impl Into<String>) -> TypeRef {
85        TypeRef::NonNull(Box::new(TypeRef::List(Box::new(TypeRef::Named(
86            type_name.into().into(),
87        )))))
88    }
89
90    /// Returns a non-null list of non-null members type reference
91    ///
92    /// GraphQL Type: `[T!]!`
93    #[inline]
94    pub fn named_nn_list_nn(type_name: impl Into<String>) -> TypeRef {
95        TypeRef::NonNull(Box::new(TypeRef::List(Box::new(TypeRef::NonNull(
96            Box::new(TypeRef::Named(type_name.into().into())),
97        )))))
98    }
99
100    /// Returns the type name
101    ///
102    /// `[Foo!]` -> `Foo`
103    #[inline(always)]
104    pub fn type_name(&self) -> &str {
105        match self {
106            TypeRef::Named(name) => name,
107            TypeRef::NonNull(inner) => inner.type_name(),
108            TypeRef::List(inner) => inner.type_name(),
109        }
110    }
111
112    #[inline]
113    pub(crate) fn is_nullable(&self) -> bool {
114        match self {
115            TypeRef::Named(_) => true,
116            TypeRef::NonNull(_) => false,
117            TypeRef::List(_) => true,
118        }
119    }
120
121    pub(crate) fn is_subtype(&self, sub: &TypeRef) -> bool {
122        fn is_subtype(cur: &TypeRef, sub: &TypeRef) -> bool {
123            match (cur, sub) {
124                (TypeRef::NonNull(super_type), TypeRef::NonNull(sub_type)) => {
125                    is_subtype(&super_type, &sub_type)
126                }
127                (_, TypeRef::NonNull(sub_type)) => is_subtype(cur, &sub_type),
128                (TypeRef::Named(super_type), TypeRef::Named(sub_type)) => super_type == sub_type,
129                (TypeRef::List(super_type), TypeRef::List(sub_type)) => {
130                    is_subtype(super_type, sub_type)
131                }
132                _ => false,
133            }
134        }
135
136        is_subtype(self, sub)
137    }
138}
139
140#[cfg(test)]
141mod tests {
142    use super::*;
143
144    #[test]
145    fn create() {
146        assert_eq!(TypeRef::named("MyObj").to_string(), "MyObj");
147        assert_eq!(TypeRef::named_nn("MyObj").to_string(), "MyObj!");
148        assert_eq!(TypeRef::named_list("MyObj").to_string(), "[MyObj]");
149        assert_eq!(TypeRef::named_list_nn("MyObj").to_string(), "[MyObj]!");
150        assert_eq!(TypeRef::named_nn_list("MyObj").to_string(), "[MyObj!]");
151        assert_eq!(TypeRef::named_nn_list_nn("MyObj").to_string(), "[MyObj!]!");
152    }
153}