amplify_syn/
cls.rs

1// Rust language amplification derive library providing multiple generic trait
2// implementations, type wrappers, derive macros and other language enhancements
3//
4// Written in 2019-2021 by
5//     Dr. Maxim Orlovsky <orlovsky@pandoracore.com>
6//
7// To the extent possible under law, the author(s) have dedicated all
8// copyright and related and neighboring rights to this software to
9// the public domain worldwide. This software is distributed without
10// any warranty.
11//
12// You should have received a copy of the MIT License
13// along with this software.
14// If not, see <https://opensource.org/licenses/MIT>.
15
16use syn::{Lit, Type};
17
18use crate::{ArgValue, Error};
19
20/// Constrains for attribute value type
21#[derive(Clone, Copy, Ord, PartialOrd, Eq, PartialEq, Hash, Debug)]
22pub enum ValueClass {
23    /// The value must be a literal matching given literal constraints (see
24    /// [`LiteralClass`])
25    Literal(LiteralClass),
26
27    /// The value must be of a native rust type matching given type constraints
28    /// (see [`TypeClass`])
29    Type(TypeClass),
30
31    /// The value must be of a native rust expression.
32    Expr,
33}
34
35impl From<Lit> for ValueClass {
36    fn from(lit: Lit) -> Self { ValueClass::Literal(LiteralClass::from(lit)) }
37}
38
39impl From<&Lit> for ValueClass {
40    fn from(lit: &Lit) -> Self { ValueClass::Literal(LiteralClass::from(lit)) }
41}
42
43impl From<Type> for ValueClass {
44    fn from(ty: Type) -> Self { ValueClass::Type(TypeClass::from(ty)) }
45}
46
47impl From<&Type> for ValueClass {
48    fn from(ty: &Type) -> Self { ValueClass::Type(TypeClass::from(ty)) }
49}
50
51impl From<LiteralClass> for ValueClass {
52    fn from(cls: LiteralClass) -> Self { ValueClass::Literal(cls) }
53}
54
55impl From<TypeClass> for ValueClass {
56    fn from(cls: TypeClass) -> Self { ValueClass::Type(cls) }
57}
58
59impl ValueClass {
60    /// Convenience constructor creating
61    /// `ValueClass::Literal(LiteralClass::Str)`
62    pub fn str() -> ValueClass { ValueClass::Literal(LiteralClass::Str) }
63
64    /// Convenience constructor creating
65    /// `ValueClass::Literal(LiteralClass::ByteStr)`
66    pub fn byte_str() -> ValueClass { ValueClass::Literal(LiteralClass::ByteStr) }
67
68    /// Convenience constructor creating
69    /// `ValueClass::Literal(LiteralClass::Byte)`
70    pub fn byte() -> ValueClass { ValueClass::Literal(LiteralClass::Byte) }
71
72    /// Convenience constructor creating
73    /// `ValueClass::Literal(LiteralClass::Int)`
74    pub fn int() -> ValueClass { ValueClass::Literal(LiteralClass::Int) }
75
76    /// Convenience constructor creating
77    /// `ValueClass::Literal(LiteralClass::Float)`
78    pub fn float() -> ValueClass { ValueClass::Literal(LiteralClass::Float) }
79
80    /// Convenience constructor creating
81    /// `ValueClass::Literal(LiteralClass::Char)`
82    pub fn char() -> ValueClass { ValueClass::Literal(LiteralClass::Char) }
83
84    /// Convenience constructor creating
85    /// `ValueClass::Literal(LiteralClass::Bool)`
86    pub fn bool() -> ValueClass { ValueClass::Literal(LiteralClass::Bool) }
87}
88
89impl ValueClass {
90    /// Checks the value against value class requirements, generating [`Error`]
91    /// if the requirements are not met.
92    pub fn check(
93        self,
94        value: &ArgValue,
95        attr: impl ToString,
96        arg: impl ToString,
97    ) -> Result<(), Error> {
98        match (self, value) {
99            (ValueClass::Literal(lit), ArgValue::Literal(ref value)) => lit.check(value, attr, arg),
100            (ValueClass::Type(ty), ArgValue::Type(ref value)) => ty.check(value, attr, arg),
101            (ValueClass::Expr, ArgValue::Type(_) | ArgValue::Expr(_) | ArgValue::Literal(_)) => {
102                Ok(())
103            }
104            _ => Err(Error::ArgValueTypeMismatch {
105                attr: attr.to_string(),
106                arg: arg.to_string(),
107            }),
108        }
109    }
110}
111
112/// Constrains for literal value type
113#[derive(Clone, Copy, Ord, PartialOrd, Eq, PartialEq, Hash, Debug)]
114pub enum LiteralClass {
115    /// Literal must be a string
116    Str,
117
118    /// Literal must be a byte string
119    ByteStr,
120
121    /// Literal must be a byte (in form of `b'f'`)
122    Byte,
123
124    /// Literal must be a character
125    Char,
126
127    /// Literal must be an integer
128    Int,
129
130    /// Literal must be a float
131    Float,
132
133    /// Literal must be a boolean
134    Bool,
135
136    /// Literal must be a verbatim form
137    Any,
138}
139
140impl From<Lit> for LiteralClass {
141    #[inline]
142    fn from(lit: Lit) -> Self { LiteralClass::from(&lit) }
143}
144
145impl From<&Lit> for LiteralClass {
146    fn from(lit: &Lit) -> Self {
147        match lit {
148            Lit::Str(_) => LiteralClass::Str,
149            Lit::ByteStr(_) => LiteralClass::ByteStr,
150            Lit::Byte(_) => LiteralClass::Byte,
151            Lit::Char(_) => LiteralClass::Char,
152            Lit::Int(_) => LiteralClass::Int,
153            Lit::Float(_) => LiteralClass::Float,
154            Lit::Bool(_) => LiteralClass::Bool,
155            Lit::Verbatim(_) => LiteralClass::Any,
156        }
157    }
158}
159
160impl LiteralClass {
161    /// Checks the literal against current requirements, generating [`Error`] if
162    /// the requirements are not met.
163    pub fn check(self, lit: &Lit, attr: impl ToString, arg: impl ToString) -> Result<(), Error> {
164        if self == LiteralClass::Any {
165            Ok(())
166        } else if self != LiteralClass::from(lit) {
167            Err(Error::ArgValueTypeMismatch {
168                attr: attr.to_string(),
169                arg: arg.to_string(),
170            })
171        } else {
172            Ok(())
173        }
174    }
175}
176
177/// Constrains for the possible types that a Rust value could have.
178#[derive(Clone, Copy, Ord, PartialOrd, Eq, PartialEq, Hash, Debug)]
179pub enum TypeClass {
180    /// A fixed size array type: `[T; n]`.
181    Array,
182
183    /// A bare function type: `fn(usize) -> bool`.
184    BareFn,
185
186    /// A type contained within invisible delimiters.
187    Group,
188
189    /// An `impl Bound1 + Bound2 + Bound3` type where `Bound` is a trait or
190    /// a lifetime.
191    ImplTrait,
192
193    /// Indication that a type should be inferred by the compiler: `_`.
194    Infer,
195
196    /// A macro in the type position.
197    Macro,
198
199    /// The never type: `!`.
200    Never,
201
202    /// A parenthesized type equivalent to the inner type.
203    Paren,
204
205    /// A path like `std::slice::Iter`, optionally qualified with a
206    /// self-type as in `<Vec<T> as SomeTrait>::Associated`.
207    Path,
208
209    /// A raw pointer type: `*const T` or `*mut T`.
210    Ptr,
211
212    /// A reference type: `&'a T` or `&'a mut T`.
213    Reference,
214
215    /// A dynamically sized slice type: `[T]`.
216    Slice,
217
218    /// A trait object type `Bound1 + Bound2 + Bound3` where `Bound` is a
219    /// trait or a lifetime.
220    TraitObject,
221
222    /// A tuple type: `(A, B, C, String)`.
223    Tuple,
224
225    /// Tokens in type position not interpreted by Syn.
226    Any,
227}
228
229impl From<Type> for TypeClass {
230    #[inline]
231    fn from(ty: Type) -> Self { TypeClass::from(&ty) }
232}
233
234impl From<&Type> for TypeClass {
235    fn from(ty: &Type) -> Self {
236        match ty {
237            Type::Array(_) => TypeClass::Array,
238            Type::BareFn(_) => TypeClass::BareFn,
239            Type::Group(_) => TypeClass::Group,
240            Type::ImplTrait(_) => TypeClass::ImplTrait,
241            Type::Infer(_) => TypeClass::Infer,
242            Type::Macro(_) => TypeClass::Macro,
243            Type::Never(_) => TypeClass::Never,
244            Type::Paren(_) => TypeClass::Paren,
245            Type::Path(_) => TypeClass::Path,
246            Type::Ptr(_) => TypeClass::Ptr,
247            Type::Reference(_) => TypeClass::Reference,
248            Type::Slice(_) => TypeClass::Slice,
249            Type::TraitObject(_) => TypeClass::TraitObject,
250            Type::Tuple(_) => TypeClass::Tuple,
251            Type::Verbatim(_) => TypeClass::Any,
252            _ => unreachable!(),
253        }
254    }
255}
256
257impl TypeClass {
258    /// Checks the [`Type`] against current requirements, generating [`Error`]
259    /// if the requirements are not met.
260    pub fn check(self, ty: &Type, attr: impl ToString, arg: impl ToString) -> Result<(), Error> {
261        if self == TypeClass::Any {
262            Ok(())
263        } else if self != TypeClass::from(ty) {
264            Err(Error::ArgValueTypeMismatch {
265                attr: attr.to_string(),
266                arg: arg.to_string(),
267            })
268        } else {
269            Ok(())
270        }
271    }
272}