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