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 use crate::interface::{CallbackInterface, ComponentInterface, Enum, Record, Type};
6 use anyhow::{bail, Context};
8 create_metadata_groups, group_metadata, EnumMetadata, ErrorMetadata, Metadata, MetadataGroup,
11 /// Add Metadata items to the ComponentInterface
13 /// This function exists to support the transition period where the `uniffi::export` macro can only
14 /// handle some components. This means that crates need to continue using UDL files to define the
15 /// parts of the components that aren't supported yet.
17 /// To make things work, we generate a `ComponentInterface` from the UDL file, then combine it with
18 /// the `Metadata` items that the macro creates.
20 iface: &mut ComponentInterface,
21 metadata_items: Vec<Metadata>,
22 ) -> anyhow::Result<()> {
23 let mut group_map = create_metadata_groups(&metadata_items);
24 group_metadata(&mut group_map, metadata_items)?;
25 for group in group_map.into_values() {
26 if group.items.is_empty() {
29 if group.namespace.name != iface.namespace() {
30 let crate_name = group.namespace.crate_name;
31 bail!("Found metadata items from crate `{crate_name}`. Use the `--library` to generate bindings for multiple crates")
33 add_group_to_ci(iface, group)?;
39 /// Add items from a MetadataGroup to a component interface
40 pub fn add_group_to_ci(iface: &mut ComponentInterface, group: MetadataGroup) -> anyhow::Result<()> {
41 if group.namespace.name != iface.namespace() {
43 "Namespace mismatch: {} - {}",
49 for item in group.items {
50 add_item_to_ci(iface, item)?
55 .context("Failed to derive FFI functions")?;
58 .context("ComponentInterface consistency error")?;
63 iface: &mut ComponentInterface,
66 ) -> anyhow::Result<()> {
68 name: meta.name.clone(),
69 module_path: meta.module_path.clone(),
71 iface.types.add_known_type(&ty)?;
73 let enum_ = Enum::try_from_meta(meta, is_flat)?;
74 iface.add_enum_definition(enum_)?;
78 fn add_item_to_ci(iface: &mut ComponentInterface, item: Metadata) -> anyhow::Result<()> {
80 Metadata::Namespace(_) => unreachable!(),
81 Metadata::UdlFile(_) => (),
82 Metadata::Func(meta) => {
83 iface.add_function_definition(meta.into())?;
85 Metadata::Constructor(meta) => {
86 iface.add_constructor_meta(meta)?;
88 Metadata::Method(meta) => {
89 iface.add_method_meta(meta)?;
91 Metadata::Record(meta) => {
92 let ty = Type::Record {
93 name: meta.name.clone(),
94 module_path: meta.module_path.clone(),
96 iface.types.add_known_type(&ty)?;
97 let record: Record = meta.try_into()?;
98 iface.add_record_definition(record)?;
100 Metadata::Enum(meta) => {
101 let flat = meta.variants.iter().all(|v| v.fields.is_empty());
102 add_enum_to_ci(iface, meta, flat)?;
104 Metadata::Object(meta) => {
105 iface.types.add_known_type(&Type::Object {
106 module_path: meta.module_path.clone(),
107 name: meta.name.clone(),
110 iface.add_object_meta(meta)?;
112 Metadata::UniffiTrait(meta) => {
113 iface.add_uniffitrait_meta(meta)?;
115 Metadata::CallbackInterface(meta) => {
116 iface.types.add_known_type(&Type::CallbackInterface {
117 module_path: meta.module_path.clone(),
118 name: meta.name.clone(),
120 iface.add_callback_interface_definition(CallbackInterface::new(
125 Metadata::TraitMethod(meta) => {
126 iface.add_trait_method_meta(meta)?;
128 Metadata::Error(meta) => {
129 iface.note_name_used_as_error(meta.name());
131 ErrorMetadata::Enum { enum_, is_flat } => {
132 add_enum_to_ci(iface, enum_, is_flat)?;
136 Metadata::CustomType(meta) => {
137 iface.types.add_known_type(&Type::Custom {
138 module_path: meta.module_path.clone(),
140 builtin: Box::new(meta.builtin),