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/. */
4 
5 use std::{collections::BTreeMap, hash::Hasher};
6 pub use uniffi_checksum_derive::Checksum;
7 
8 mod ffi_names;
9 pub use ffi_names::*;
10 
11 mod group;
12 pub use group::{create_metadata_groups, fixup_external_type, group_metadata, MetadataGroup};
13 
14 mod reader;
15 pub use reader::{read_metadata, read_metadata_type};
16 
17 mod types;
18 pub use types::{AsType, ExternalKind, ObjectImpl, Type, TypeIterator};
19 
20 mod metadata;
21 
22 // This needs to match the minor version of the `uniffi` crate.  See
23 // `docs/uniffi-versioning.md` for details.
24 //
25 // Once we get to 1.0, then we'll need to update the scheme to something like 100 + major_version
26 pub const UNIFFI_CONTRACT_VERSION: u32 = 26;
27 
28 /// Similar to std::hash::Hash.
29 ///
30 /// Implementations of this trait are expected to update the hasher state in
31 /// the same way across platforms. #[derive(Checksum)] will do the right thing.
32 pub trait Checksum {
checksum<H: Hasher>(&self, state: &mut H)33     fn checksum<H: Hasher>(&self, state: &mut H);
34 }
35 
36 impl Checksum for bool {
checksum<H: Hasher>(&self, state: &mut H)37     fn checksum<H: Hasher>(&self, state: &mut H) {
38         state.write_u8(*self as u8);
39     }
40 }
41 
42 impl Checksum for u64 {
checksum<H: Hasher>(&self, state: &mut H)43     fn checksum<H: Hasher>(&self, state: &mut H) {
44         state.write(&self.to_le_bytes());
45     }
46 }
47 
48 impl Checksum for i64 {
checksum<H: Hasher>(&self, state: &mut H)49     fn checksum<H: Hasher>(&self, state: &mut H) {
50         state.write(&self.to_le_bytes());
51     }
52 }
53 
54 impl<T: Checksum> Checksum for Box<T> {
checksum<H: Hasher>(&self, state: &mut H)55     fn checksum<H: Hasher>(&self, state: &mut H) {
56         (**self).checksum(state)
57     }
58 }
59 
60 impl<T: Checksum> Checksum for [T] {
checksum<H: Hasher>(&self, state: &mut H)61     fn checksum<H: Hasher>(&self, state: &mut H) {
62         state.write(&(self.len() as u64).to_le_bytes());
63         for item in self {
64             Checksum::checksum(item, state);
65         }
66     }
67 }
68 
69 impl<T: Checksum> Checksum for Vec<T> {
checksum<H: Hasher>(&self, state: &mut H)70     fn checksum<H: Hasher>(&self, state: &mut H) {
71         Checksum::checksum(&**self, state);
72     }
73 }
74 
75 impl<K: Checksum, V: Checksum> Checksum for BTreeMap<K, V> {
checksum<H: Hasher>(&self, state: &mut H)76     fn checksum<H: Hasher>(&self, state: &mut H) {
77         state.write(&(self.len() as u64).to_le_bytes());
78         for (key, value) in self {
79             Checksum::checksum(key, state);
80             Checksum::checksum(value, state);
81         }
82     }
83 }
84 
85 impl<T: Checksum> Checksum for Option<T> {
checksum<H: Hasher>(&self, state: &mut H)86     fn checksum<H: Hasher>(&self, state: &mut H) {
87         match self {
88             None => state.write(&0u64.to_le_bytes()),
89             Some(value) => {
90                 state.write(&1u64.to_le_bytes());
91                 Checksum::checksum(value, state)
92             }
93         }
94     }
95 }
96 
97 impl Checksum for str {
checksum<H: Hasher>(&self, state: &mut H)98     fn checksum<H: Hasher>(&self, state: &mut H) {
99         state.write(self.as_bytes());
100         state.write_u8(0xff);
101     }
102 }
103 
104 impl Checksum for String {
checksum<H: Hasher>(&self, state: &mut H)105     fn checksum<H: Hasher>(&self, state: &mut H) {
106         (**self).checksum(state)
107     }
108 }
109 
110 impl Checksum for &str {
checksum<H: Hasher>(&self, state: &mut H)111     fn checksum<H: Hasher>(&self, state: &mut H) {
112         (**self).checksum(state)
113     }
114 }
115 
116 // The namespace of a Component interface.
117 //
118 // This is used to match up the macro metadata with the UDL items.
119 #[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
120 pub struct NamespaceMetadata {
121     pub crate_name: String,
122     pub name: String,
123 }
124 
125 // UDL file included with `include_scaffolding!()`
126 //
127 // This is to find the UDL files in library mode generation
128 #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
129 pub struct UdlFile {
130     // The module path specified when the UDL file was parsed.
131     pub module_path: String,
132     pub namespace: String,
133     // the base filename of the udl file - no path, no extension.
134     pub file_stub: String,
135 }
136 
137 #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
138 pub struct FnMetadata {
139     pub module_path: String,
140     pub name: String,
141     pub is_async: bool,
142     pub inputs: Vec<FnParamMetadata>,
143     pub return_type: Option<Type>,
144     pub throws: Option<Type>,
145     pub checksum: Option<u16>,
146     pub docstring: Option<String>,
147 }
148 
149 impl FnMetadata {
ffi_symbol_name(&self) -> String150     pub fn ffi_symbol_name(&self) -> String {
151         fn_symbol_name(&self.module_path, &self.name)
152     }
153 
checksum_symbol_name(&self) -> String154     pub fn checksum_symbol_name(&self) -> String {
155         fn_checksum_symbol_name(&self.module_path, &self.name)
156     }
157 }
158 
159 #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
160 pub struct ConstructorMetadata {
161     pub module_path: String,
162     pub self_name: String,
163     pub name: String,
164     pub is_async: bool,
165     pub inputs: Vec<FnParamMetadata>,
166     pub throws: Option<Type>,
167     pub checksum: Option<u16>,
168     pub docstring: Option<String>,
169 }
170 
171 impl ConstructorMetadata {
ffi_symbol_name(&self) -> String172     pub fn ffi_symbol_name(&self) -> String {
173         constructor_symbol_name(&self.module_path, &self.self_name, &self.name)
174     }
175 
checksum_symbol_name(&self) -> String176     pub fn checksum_symbol_name(&self) -> String {
177         constructor_checksum_symbol_name(&self.module_path, &self.self_name, &self.name)
178     }
179 
is_primary(&self) -> bool180     pub fn is_primary(&self) -> bool {
181         self.name == "new"
182     }
183 }
184 
185 #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
186 pub struct MethodMetadata {
187     pub module_path: String,
188     pub self_name: String,
189     pub name: String,
190     pub is_async: bool,
191     pub inputs: Vec<FnParamMetadata>,
192     pub return_type: Option<Type>,
193     pub throws: Option<Type>,
194     pub takes_self_by_arc: bool, // unused except by rust udl bindgen.
195     pub checksum: Option<u16>,
196     pub docstring: Option<String>,
197 }
198 
199 impl MethodMetadata {
ffi_symbol_name(&self) -> String200     pub fn ffi_symbol_name(&self) -> String {
201         method_symbol_name(&self.module_path, &self.self_name, &self.name)
202     }
203 
checksum_symbol_name(&self) -> String204     pub fn checksum_symbol_name(&self) -> String {
205         method_checksum_symbol_name(&self.module_path, &self.self_name, &self.name)
206     }
207 }
208 
209 #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
210 pub struct TraitMethodMetadata {
211     pub module_path: String,
212     pub trait_name: String,
213     // Note: the position of `index` is important since it causes callback interface methods to be
214     // ordered correctly in MetadataGroup.items
215     pub index: u32,
216     pub name: String,
217     pub is_async: bool,
218     pub inputs: Vec<FnParamMetadata>,
219     pub return_type: Option<Type>,
220     pub throws: Option<Type>,
221     pub takes_self_by_arc: bool, // unused except by rust udl bindgen.
222     pub checksum: Option<u16>,
223     pub docstring: Option<String>,
224 }
225 
226 impl TraitMethodMetadata {
ffi_symbol_name(&self) -> String227     pub fn ffi_symbol_name(&self) -> String {
228         method_symbol_name(&self.module_path, &self.trait_name, &self.name)
229     }
230 
checksum_symbol_name(&self) -> String231     pub fn checksum_symbol_name(&self) -> String {
232         method_checksum_symbol_name(&self.module_path, &self.trait_name, &self.name)
233     }
234 }
235 
236 #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
237 pub struct FnParamMetadata {
238     pub name: String,
239     pub ty: Type,
240     pub by_ref: bool,
241     pub optional: bool,
242     pub default: Option<LiteralMetadata>,
243 }
244 
245 impl FnParamMetadata {
simple(name: &str, ty: Type) -> Self246     pub fn simple(name: &str, ty: Type) -> Self {
247         Self {
248             name: name.to_string(),
249             ty,
250             by_ref: false,
251             optional: false,
252             default: None,
253         }
254     }
255 }
256 
257 #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Checksum)]
258 pub enum LiteralMetadata {
259     Boolean(bool),
260     String(String),
261     // Integers are represented as the widest representation we can.
262     // Number formatting vary with language and radix, so we avoid a lot of parsing and
263     // formatting duplication by using only signed and unsigned variants.
264     UInt(u64, Radix, Type),
265     Int(i64, Radix, Type),
266     // Pass the string representation through as typed in the UDL.
267     // This avoids a lot of uncertainty around precision and accuracy,
268     // though bindings for languages less sophisticated number parsing than WebIDL
269     // will have to do extra work.
270     Float(String, Type),
271     Enum(String, Type),
272     EmptySequence,
273     EmptyMap,
274     None,
275     Some { inner: Box<LiteralMetadata> },
276 }
277 
278 impl LiteralMetadata {
new_uint(v: u64) -> Self279     pub fn new_uint(v: u64) -> Self {
280         LiteralMetadata::UInt(v, Radix::Decimal, Type::UInt64)
281     }
new_int(v: i64) -> Self282     pub fn new_int(v: i64) -> Self {
283         LiteralMetadata::Int(v, Radix::Decimal, Type::Int64)
284     }
285 }
286 
287 // Represent the radix of integer literal values.
288 // We preserve the radix into the generated bindings for readability reasons.
289 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Checksum)]
290 pub enum Radix {
291     Decimal = 10,
292     Octal = 8,
293     Hexadecimal = 16,
294 }
295 
296 #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
297 pub struct RecordMetadata {
298     pub module_path: String,
299     pub name: String,
300     pub fields: Vec<FieldMetadata>,
301     pub docstring: Option<String>,
302 }
303 
304 #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
305 pub struct FieldMetadata {
306     pub name: String,
307     pub ty: Type,
308     pub default: Option<LiteralMetadata>,
309     pub docstring: Option<String>,
310 }
311 
312 #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
313 pub struct EnumMetadata {
314     pub module_path: String,
315     pub name: String,
316     pub forced_flatness: Option<bool>,
317     pub variants: Vec<VariantMetadata>,
318     pub discr_type: Option<Type>,
319     pub non_exhaustive: bool,
320     pub docstring: Option<String>,
321 }
322 
323 #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
324 pub struct VariantMetadata {
325     pub name: String,
326     pub discr: Option<LiteralMetadata>,
327     pub fields: Vec<FieldMetadata>,
328     pub docstring: Option<String>,
329 }
330 
331 #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
332 pub struct ObjectMetadata {
333     pub module_path: String,
334     pub name: String,
335     pub imp: types::ObjectImpl,
336     pub docstring: Option<String>,
337 }
338 
339 #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
340 pub struct CallbackInterfaceMetadata {
341     pub module_path: String,
342     pub name: String,
343     pub docstring: Option<String>,
344 }
345 
346 impl ObjectMetadata {
347     /// FFI symbol name for the `clone` function for this object.
348     ///
349     /// This function is used to increment the reference count before lowering an object to pass
350     /// back to Rust.
clone_ffi_symbol_name(&self) -> String351     pub fn clone_ffi_symbol_name(&self) -> String {
352         clone_fn_symbol_name(&self.module_path, &self.name)
353     }
354 
355     /// FFI symbol name for the `free` function for this object.
356     ///
357     /// This function is used to free the memory used by this object.
free_ffi_symbol_name(&self) -> String358     pub fn free_ffi_symbol_name(&self) -> String {
359         free_fn_symbol_name(&self.module_path, &self.name)
360     }
361 }
362 
363 /// The list of traits we support generating helper methods for.
364 #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
365 pub enum UniffiTraitMetadata {
366     Debug {
367         fmt: MethodMetadata,
368     },
369     Display {
370         fmt: MethodMetadata,
371     },
372     Eq {
373         eq: MethodMetadata,
374         ne: MethodMetadata,
375     },
376     Hash {
377         hash: MethodMetadata,
378     },
379 }
380 
381 impl UniffiTraitMetadata {
module_path(&self) -> &String382     fn module_path(&self) -> &String {
383         &match self {
384             UniffiTraitMetadata::Debug { fmt } => fmt,
385             UniffiTraitMetadata::Display { fmt } => fmt,
386             UniffiTraitMetadata::Eq { eq, .. } => eq,
387             UniffiTraitMetadata::Hash { hash } => hash,
388         }
389         .module_path
390     }
391 
self_name(&self) -> &String392     pub fn self_name(&self) -> &String {
393         &match self {
394             UniffiTraitMetadata::Debug { fmt } => fmt,
395             UniffiTraitMetadata::Display { fmt } => fmt,
396             UniffiTraitMetadata::Eq { eq, .. } => eq,
397             UniffiTraitMetadata::Hash { hash } => hash,
398         }
399         .self_name
400     }
401 }
402 
403 #[repr(u8)]
404 #[derive(Eq, PartialEq, Hash)]
405 pub enum UniffiTraitDiscriminants {
406     Debug,
407     Display,
408     Eq,
409     Hash,
410 }
411 
412 impl UniffiTraitDiscriminants {
from(v: u8) -> anyhow::Result<Self>413     pub fn from(v: u8) -> anyhow::Result<Self> {
414         Ok(match v {
415             0 => UniffiTraitDiscriminants::Debug,
416             1 => UniffiTraitDiscriminants::Display,
417             2 => UniffiTraitDiscriminants::Eq,
418             3 => UniffiTraitDiscriminants::Hash,
419             _ => anyhow::bail!("invalid trait discriminant {v}"),
420         })
421     }
422 }
423 
424 #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
425 pub struct CustomTypeMetadata {
426     pub module_path: String,
427     pub name: String,
428     pub builtin: Type,
429 }
430 
431 /// Returns the last 16 bits of the value's hash as computed with [`SipHasher13`].
432 ///
433 /// This is used as a safeguard against different UniFFI versions being used for scaffolding and
434 /// bindings generation.
checksum<T: Checksum>(val: &T) -> u16435 pub fn checksum<T: Checksum>(val: &T) -> u16 {
436     let mut hasher = siphasher::sip::SipHasher13::new();
437     val.checksum(&mut hasher);
438     (hasher.finish() & 0x000000000000FFFF) as u16
439 }
440 
441 /// Enum covering all the possible metadata types
442 #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
443 pub enum Metadata {
444     Namespace(NamespaceMetadata),
445     UdlFile(UdlFile),
446     Func(FnMetadata),
447     Object(ObjectMetadata),
448     CallbackInterface(CallbackInterfaceMetadata),
449     Record(RecordMetadata),
450     Enum(EnumMetadata),
451     Constructor(ConstructorMetadata),
452     Method(MethodMetadata),
453     TraitMethod(TraitMethodMetadata),
454     CustomType(CustomTypeMetadata),
455     UniffiTrait(UniffiTraitMetadata),
456 }
457 
458 impl Metadata {
read(data: &[u8]) -> anyhow::Result<Self>459     pub fn read(data: &[u8]) -> anyhow::Result<Self> {
460         read_metadata(data)
461     }
462 
module_path(&self) -> &String463     pub(crate) fn module_path(&self) -> &String {
464         match self {
465             Metadata::Namespace(meta) => &meta.crate_name,
466             Metadata::UdlFile(meta) => &meta.module_path,
467             Metadata::Func(meta) => &meta.module_path,
468             Metadata::Constructor(meta) => &meta.module_path,
469             Metadata::Method(meta) => &meta.module_path,
470             Metadata::Record(meta) => &meta.module_path,
471             Metadata::Enum(meta) => &meta.module_path,
472             Metadata::Object(meta) => &meta.module_path,
473             Metadata::CallbackInterface(meta) => &meta.module_path,
474             Metadata::TraitMethod(meta) => &meta.module_path,
475             Metadata::CustomType(meta) => &meta.module_path,
476             Metadata::UniffiTrait(meta) => meta.module_path(),
477         }
478     }
479 }
480 
481 impl From<NamespaceMetadata> for Metadata {
from(value: NamespaceMetadata) -> Metadata482     fn from(value: NamespaceMetadata) -> Metadata {
483         Self::Namespace(value)
484     }
485 }
486 
487 impl From<UdlFile> for Metadata {
from(value: UdlFile) -> Metadata488     fn from(value: UdlFile) -> Metadata {
489         Self::UdlFile(value)
490     }
491 }
492 
493 impl From<FnMetadata> for Metadata {
from(value: FnMetadata) -> Metadata494     fn from(value: FnMetadata) -> Metadata {
495         Self::Func(value)
496     }
497 }
498 
499 impl From<ConstructorMetadata> for Metadata {
from(c: ConstructorMetadata) -> Self500     fn from(c: ConstructorMetadata) -> Self {
501         Self::Constructor(c)
502     }
503 }
504 
505 impl From<MethodMetadata> for Metadata {
from(m: MethodMetadata) -> Self506     fn from(m: MethodMetadata) -> Self {
507         Self::Method(m)
508     }
509 }
510 
511 impl From<RecordMetadata> for Metadata {
from(r: RecordMetadata) -> Self512     fn from(r: RecordMetadata) -> Self {
513         Self::Record(r)
514     }
515 }
516 
517 impl From<EnumMetadata> for Metadata {
from(e: EnumMetadata) -> Self518     fn from(e: EnumMetadata) -> Self {
519         Self::Enum(e)
520     }
521 }
522 
523 impl From<ObjectMetadata> for Metadata {
from(v: ObjectMetadata) -> Self524     fn from(v: ObjectMetadata) -> Self {
525         Self::Object(v)
526     }
527 }
528 
529 impl From<CallbackInterfaceMetadata> for Metadata {
from(v: CallbackInterfaceMetadata) -> Self530     fn from(v: CallbackInterfaceMetadata) -> Self {
531         Self::CallbackInterface(v)
532     }
533 }
534 
535 impl From<TraitMethodMetadata> for Metadata {
from(v: TraitMethodMetadata) -> Self536     fn from(v: TraitMethodMetadata) -> Self {
537         Self::TraitMethod(v)
538     }
539 }
540 
541 impl From<CustomTypeMetadata> for Metadata {
from(v: CustomTypeMetadata) -> Self542     fn from(v: CustomTypeMetadata) -> Self {
543         Self::CustomType(v)
544     }
545 }
546 
547 impl From<UniffiTraitMetadata> for Metadata {
from(v: UniffiTraitMetadata) -> Self548     fn from(v: UniffiTraitMetadata) -> Self {
549         Self::UniffiTrait(v)
550     }
551 }
552