marine_macro_impl/
parsed_type.rs

1/*
2 * Copyright 2018 Fluence Labs Limited
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17mod fn_arg;
18mod fn_epilog;
19mod fn_prolog;
20mod foreign_mod_arg;
21mod foreign_mod_epilog;
22mod foreign_mod_prolog;
23mod traits;
24mod utils;
25mod vector_ser_der;
26
27pub(crate) use fn_arg::*;
28pub(crate) use fn_epilog::*;
29pub(crate) use fn_prolog::*;
30pub(crate) use foreign_mod_prolog::*;
31pub(crate) use foreign_mod_epilog::*;
32pub(crate) use utils::*;
33pub(crate) use vector_ser_der::*;
34
35use serde::Serialize;
36use serde::Deserialize;
37use syn::parse::Error;
38use syn::spanned::Spanned;
39
40/// An internal representation of supported Rust types.
41#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
42pub enum ParsedType {
43    I8(PassingStyle),
44    I16(PassingStyle),
45    I32(PassingStyle),
46    I64(PassingStyle),
47    U8(PassingStyle),
48    U16(PassingStyle),
49    U32(PassingStyle),
50    U64(PassingStyle),
51    F32(PassingStyle),
52    F64(PassingStyle),
53    Boolean(PassingStyle),
54    Utf8Str(PassingStyle),
55    Utf8String(PassingStyle),
56    Vector(Box<ParsedType>, PassingStyle),
57    Record(String, PassingStyle), // short type name
58}
59
60#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
61pub enum PassingStyle {
62    ByValue,
63    ByRef,
64    ByMutRef,
65}
66
67impl ParsedType {
68    pub fn from_type(input_type: &syn::Type) -> syn::Result<Self> {
69        use quote::ToTokens;
70
71        let (path, passing_style) = type_to_path_passing_style(input_type)?;
72
73        let type_segment = path
74            .segments
75            // argument can be given in full path form: ::std::string::String
76            // that why the last one used
77            .last()
78            .ok_or_else(|| Error::new(path.span(), "Type should be specified"))?;
79
80        match type_segment.ident.to_string().as_str() {
81            "i8" => Ok(ParsedType::I8(passing_style)),
82            "i16" => Ok(ParsedType::I16(passing_style)),
83            "i32" => Ok(ParsedType::I32(passing_style)),
84            "i64" => Ok(ParsedType::I64(passing_style)),
85            "u8" => Ok(ParsedType::U8(passing_style)),
86            "u16" => Ok(ParsedType::U16(passing_style)),
87            "u32" => Ok(ParsedType::U32(passing_style)),
88            "u64" => Ok(ParsedType::U64(passing_style)),
89            "f32" => Ok(ParsedType::F32(passing_style)),
90            "f64" => Ok(ParsedType::F64(passing_style)),
91            "bool" => Ok(ParsedType::Boolean(passing_style)),
92            "str" => Ok(ParsedType::Utf8Str(passing_style)),
93            "String" => Ok(ParsedType::Utf8String(passing_style)),
94            "Vec" => {
95                let vec_type = parse_vec_bracket(&type_segment.arguments)?;
96                let parsed_type = ParsedType::from_type(vec_type)?;
97
98                Ok(ParsedType::Vector(Box::new(parsed_type), passing_style))
99            }
100            _ if !type_segment.arguments.is_empty() => Err(Error::new(
101                type_segment.span(),
102                "types with lifetimes or generics aren't allowed".to_string(),
103            )),
104            _ => Ok(ParsedType::Record(
105                (&type_segment.ident).into_token_stream().to_string(),
106                passing_style,
107            )),
108        }
109    }
110
111    pub fn from_fn_arg(fn_arg: &syn::FnArg) -> syn::Result<Self> {
112        match fn_arg {
113            syn::FnArg::Typed(arg) => ParsedType::from_type(&arg.ty),
114            _ => Err(Error::new(
115                fn_arg.span(),
116                "`self` argument types aren't supported",
117            )),
118        }
119    }
120
121    pub fn from_return_type(ret_type: &syn::ReturnType) -> syn::Result<Option<Self>> {
122        match ret_type {
123            syn::ReturnType::Type(_, t) => Ok(Some(ParsedType::from_type(t.as_ref())?)),
124            syn::ReturnType::Default => Ok(None),
125        }
126    }
127
128    pub fn is_complex_type(&self) -> bool {
129        match self {
130            ParsedType::Boolean(_)
131            | ParsedType::I8(_)
132            | ParsedType::I16(_)
133            | ParsedType::I32(_)
134            | ParsedType::I64(_)
135            | ParsedType::U8(_)
136            | ParsedType::U16(_)
137            | ParsedType::U32(_)
138            | ParsedType::U64(_)
139            | ParsedType::F32(_)
140            | ParsedType::F64(_) => false,
141            ParsedType::Utf8Str(_)
142            | ParsedType::Utf8String(_)
143            | ParsedType::Vector(..)
144            | ParsedType::Record(..) => true,
145        }
146    }
147}
148
149fn type_to_path_passing_style(input_type: &syn::Type) -> syn::Result<(&syn::Path, PassingStyle)> {
150    match input_type {
151        syn::Type::Path(path) => Ok((&path.path, PassingStyle::ByValue)),
152        syn::Type::Reference(type_reference) => match &*type_reference.elem {
153            syn::Type::Path(path) => {
154                let passing_style = match type_reference.mutability {
155                    Some(_) => PassingStyle::ByMutRef,
156                    None => PassingStyle::ByRef,
157                };
158
159                Ok((&path.path, passing_style))
160            }
161            _ => Err(Error::new(
162                input_type.span(),
163                "Incorrect argument type, only path is available on this position",
164            )),
165        },
166        _ => Err(Error::new(
167            input_type.span(),
168            "Incorrect argument type, only path or reference are available on this position",
169        )),
170    }
171}
172
173// parse generic param T in Vec<T> to syn::Type
174fn parse_vec_bracket(args: &syn::PathArguments) -> syn::Result<&syn::Type> {
175    // checks that T is angle bracketed
176    let generic_arg = match args {
177        syn::PathArguments::AngleBracketed(args) => Ok(args),
178        _ => Err(Error::new(
179            args.span(),
180            "expected value in angle brackets (<>)",
181        )),
182    }?;
183
184    let arg = generic_arg.args.first().ok_or_else(|| {
185        Error::new(
186            generic_arg.span(),
187            "Invalid type in Vec brackets. (NOTE: lifetimes, bindings, constraints and consts are not supported)",
188        )
189    })?;
190
191    // converts T to syn::Type
192    match arg {
193        syn::GenericArgument::Type(ty) => Ok(ty),
194        _ => Err(Error::new(
195            arg.span(),
196            "Invalid type in Vec brackets. (NOTE: lifetimes, bindings, constraints and consts are not supported)",
197        )),
198    }
199}