fp_bindgen/types/
mod.rs

1use crate::primitives::Primitive;
2use std::{collections::BTreeMap, hash::Hash};
3use syn::{Item, TypeParam, TypeParamBound};
4
5mod cargo_dependency;
6mod custom_type;
7mod enums;
8mod structs;
9mod type_ident;
10
11pub use cargo_dependency::CargoDependency;
12pub use custom_type::CustomType;
13pub use enums::{Enum, EnumOptions, Variant, VariantAttrs};
14pub use structs::{Field, FieldAttrs, Struct, StructOptions};
15pub use type_ident::TypeIdent;
16
17pub type TypeMap = BTreeMap<TypeIdent, Type>;
18
19#[derive(Clone, Debug, Eq, Hash, PartialEq)]
20pub enum Type {
21    Alias(String, TypeIdent),
22    Array(Primitive, usize),
23    Container(String, TypeIdent),
24    Custom(CustomType),
25    Enum(Enum),
26    List(String, TypeIdent),
27    Map(String, TypeIdent, TypeIdent),
28    Primitive(Primitive),
29    String,
30    Struct(Struct),
31    Tuple(Vec<TypeIdent>),
32    Unit,
33}
34
35impl Type {
36    pub fn from_item(item_str: &str) -> Self {
37        let item = syn::parse_str::<Item>(item_str).unwrap();
38        match item {
39            Item::Enum(item) => Type::Enum(enums::parse_enum_item(item)),
40            Item::Struct(item) => Type::Struct(structs::parse_struct_item(item)),
41            item => panic!(
42                "Only struct and enum types can be constructed from an item. Found: {:?}",
43                item
44            ),
45        }
46    }
47
48    pub fn name(&self) -> String {
49        match self {
50            Self::Alias(name, _) => name.clone(),
51            Self::Array(primitive, size) => format!("[{}; {}]", primitive.name(), size),
52            Self::Container(name, ident) => format!("{name}<{ident}>"),
53            Self::Custom(custom) => custom.ident.to_string(),
54            Self::Enum(Enum { ident, .. }) => ident.to_string(),
55            Self::List(name, ident) => format!("{name}<{ident}>"),
56            Self::Map(name, key, value) => format!("{name}<{key}, {value}>"),
57            Self::Primitive(primitive) => primitive.name(),
58            Self::String => "String".to_owned(),
59            Self::Struct(Struct { ident, .. }) => ident.to_string(),
60            Self::Tuple(items) => format!(
61                "({})",
62                items
63                    .iter()
64                    .map(ToString::to_string)
65                    .collect::<Vec<_>>()
66                    .join(", ")
67            ),
68            Self::Unit => "()".to_owned(),
69        }
70    }
71}
72
73pub(crate) fn format_bounds(ty: &TypeParam) -> Vec<String> {
74    ty.bounds
75        .iter()
76        .filter_map(|bound| match bound {
77            TypeParamBound::Trait(tr) => Some(path_to_string(&tr.path)),
78            _ => None,
79        })
80        .collect()
81}
82
83fn path_to_string(path: &syn::Path) -> String {
84    path.segments
85        .iter()
86        .map(|segment| segment.ident.to_string())
87        .collect::<Vec<_>>()
88        .join("::")
89}
90
91// Used to remove the 'Serializable' bound from generated types, since this trait only exists in fp-bindgen
92// and doesn't exist at runtime.
93pub(crate) fn is_runtime_bound(bound: &str) -> bool {
94    // Filtering by string is a bit dangerous since users may have their own 'Serializable' trait :(
95    bound != "Serializable" && bound != "fp_bindgen::prelude::Serializable"
96}