Backed out 5 changesets (bug 1890092, bug 1888683) for causing build bustages & crash...
[gecko.git] / third_party / rust / uniffi_meta / src / types.rs
blob24f8a6f2a872b321f7da44628cb2a45b8ee38415
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 //! # Basic typesystem for defining a component interface.
6 //!
7 //! This module provides the "API-level" typesystem of a UniFFI Rust Component, that is,
8 //! the types provided by the Rust implementation and consumed callers of the foreign language
9 //! bindings. Think "objects" and "enums" and "records".
10 //!
11 //! The [`Type`] enum represents high-level types that would appear in the public API of
12 //! a component, such as enums and records as well as primitives like ints and strings.
13 //! The Rust code that implements a component, and the foreign language bindings that consume it,
14 //! will both typically deal with such types as their core concern.
15 //!
16 //! As a developer working on UniFFI itself, you're likely to spend a fair bit of time thinking
17 //! about how these API-level types map into the lower-level types of the FFI layer as represented
18 //! by the [`ffi::FfiType`](super::ffi::FfiType) enum, but that's a detail that is invisible to end users.
20 use crate::Checksum;
22 #[derive(Debug, Copy, Clone, Eq, PartialEq, Checksum, Ord, PartialOrd)]
23 pub enum ObjectImpl {
24     Struct,
25     Trait,
28 impl ObjectImpl {
29     /// Return the fully qualified name which should be used by Rust code for
30     /// an object with the given name.
31     /// Includes `r#`, traits get a leading `dyn`. If we ever supported associated types, then
32     /// this would also include them.
33     pub fn rust_name_for(&self, name: &str) -> String {
34         if self == &ObjectImpl::Trait {
35             format!("dyn r#{name}")
36         } else {
37             format!("r#{name}")
38         }
39     }
41     // uniffi_meta and procmacro support tend to carry around `is_trait` bools. This makes that
42     // mildly less painful
43     pub fn from_is_trait(is_trait: bool) -> Self {
44         if is_trait {
45             ObjectImpl::Trait
46         } else {
47             ObjectImpl::Struct
48         }
49     }
52 #[derive(Debug, Clone, Copy, Eq, PartialEq, Checksum, Ord, PartialOrd)]
53 pub enum ExternalKind {
54     Interface,
55     // Either a record or enum
56     DataClass,
59 /// Represents all the different high-level types that can be used in a component interface.
60 /// At this level we identify user-defined types by name, without knowing any details
61 /// of their internal structure apart from what type of thing they are (record, enum, etc).
62 #[derive(Debug, Clone, Eq, PartialEq, Checksum, Ord, PartialOrd)]
63 pub enum Type {
64     // Primitive types.
65     UInt8,
66     Int8,
67     UInt16,
68     Int16,
69     UInt32,
70     Int32,
71     UInt64,
72     Int64,
73     Float32,
74     Float64,
75     Boolean,
76     String,
77     Bytes,
78     Timestamp,
79     Duration,
80     Object {
81         // The module path to the object
82         module_path: String,
83         // The name in the "type universe"
84         name: String,
85         // How the object is implemented.
86         imp: ObjectImpl,
87     },
88     ForeignExecutor,
89     // Types defined in the component API, each of which has a string name.
90     Record {
91         module_path: String,
92         name: String,
93     },
94     Enum {
95         module_path: String,
96         name: String,
97     },
98     CallbackInterface {
99         module_path: String,
100         name: String,
101     },
102     // Structurally recursive types.
103     Optional {
104         inner_type: Box<Type>,
105     },
106     Sequence {
107         inner_type: Box<Type>,
108     },
109     Map {
110         key_type: Box<Type>,
111         value_type: Box<Type>,
112     },
113     // An FfiConverter we `use` from an external crate
114     External {
115         module_path: String,
116         name: String,
117         #[checksum_ignore] // The namespace is not known generating scaffolding.
118         namespace: String,
119         kind: ExternalKind,
120         tagged: bool, // does its FfiConverter use <UniFFITag>?
121     },
122     // Custom type on the scaffolding side
123     Custom {
124         module_path: String,
125         name: String,
126         builtin: Box<Type>,
127     },
130 impl Type {
131     pub fn iter_types(&self) -> TypeIterator<'_> {
132         let nested_types = match self {
133             Type::Optional { inner_type } | Type::Sequence { inner_type } => {
134                 inner_type.iter_types()
135             }
136             Type::Map {
137                 key_type,
138                 value_type,
139             } => Box::new(key_type.iter_types().chain(value_type.iter_types())),
140             _ => Box::new(std::iter::empty()),
141         };
142         Box::new(std::iter::once(self).chain(nested_types))
143     }
146 // A trait so various things can turn into a type.
147 pub trait AsType: core::fmt::Debug {
148     fn as_type(&self) -> Type;
151 impl AsType for Type {
152     fn as_type(&self) -> Type {
153         self.clone()
154     }
157 // Needed to handle &&Type and &&&Type values, which we sometimes end up with in the template code
158 impl<T, C> AsType for T
159 where
160     T: std::ops::Deref<Target = C> + std::fmt::Debug,
161     C: AsType,
163     fn as_type(&self) -> Type {
164         self.deref().as_type()
165     }
168 /// An abstract type for an iterator over &Type references.
170 /// Ideally we would not need to name this type explicitly, and could just
171 /// use an `impl Iterator<Item = &Type>` on any method that yields types.
172 pub type TypeIterator<'a> = Box<dyn Iterator<Item = &'a Type> + 'a>;