/* This Source Code Form is subject to the terms of the Mozilla Public *License,v.2.0.IfacopyoftheMPLwasnotdistributedwiththis
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
usecrate::literal::convert_default_value; usecrate::InterfaceCollector; use anyhow::{bail, Result};
use uniffi_meta::{
CallbackInterfaceMetadata, FieldMetadata, RecordMetadata, TraitMethodMetadata, VariantMetadata,
};
mod callables; mod enum_; mod interface;
/// Trait to help convert WedIDL syntax nodes into `InterfaceCollector` objects. /// /// This trait does structural matching on the various weedle AST nodes and converts /// them into appropriate structs that we can use to build up the contents of a /// `InterfaceCollector`. It is basically the `TryFrom` trait except that the conversion /// always happens in the context of a given `InterfaceCollector`, which is used for /// resolving e.g. type definitions. /// /// The difference between this trait and `APIBuilder` is that `APIConverter` treats the /// `InterfaceCollector` as a read-only data source for resolving types, while `APIBuilder` /// actually mutates the `InterfaceCollector` to add new definitions. pub(crate) trait APIConverter<T> { fn convert(&self, ci: &mut InterfaceCollector) -> Result<T>;
}
/// Convert a list of weedle items into a list of `InterfaceCollector` items, /// by doing a direct item-by-item mapping. impl<U, T: APIConverter<U>> APIConverter<Vec<U>> for Vec<T> { fn convert(&self, ci: &mut InterfaceCollector) -> Result<Vec<U>> { self.iter().map(|v| v.convert(ci)).collect::<Result<_>>()
}
}
impl APIConverter<VariantMetadata> for weedle::interface::OperationInterfaceMember<'_> { fn convert(&self, ci: &mut InterfaceCollector) -> Result<VariantMetadata> { ifself.special.is_some() {
bail!("special operations not supported");
} iflet Some(weedle::interface::StringifierOrStatic::Stringifier(_)) = self.modifier {
bail!("stringifiers are not supported");
} // OK, so this is a little weird. // The syntax we use for enum interface members is `Name(type arg, ...);`, which parses // as an anonymous operation where `Name` is the return type. We re-interpret it to // use `Name` as the name of the variant. ifself.identifier.is_some() {
bail!("enum interface members must not have a method name");
} let name: String = { use weedle::types::{
NonAnyType::{self, Identifier},
ReturnType,
SingleType::NonAny, Type::Single,
}; match &self.return_type {
ReturnType::Type(Single(NonAny(Identifier(id)))) => id.type_.0.to_owned(), // Using recognized/parsed types as enum variant names can lead to the bail error because they match // before `Identifier`. `Error` is one that's likely to be common, so we're circumventing what is // likely a parsing issue here. As an example of the issue `Promise` (`Promise(PromiseType<'a>)`) as // a variant matches the `Identifier` arm, but `DataView` (`DataView(MayBeNull<term!(DataView)>)`) // fails.
ReturnType::Type(Single(NonAny(NonAnyType::Error(_)))) => "Error".to_string(),
_ => bail!("enum interface members must have plain identifiers as names"),
}
};
Ok(VariantMetadata {
name,
discr: None,
fields: self
.args
.body
.list
.iter()
.map(|arg| arg.convert(ci))
.collect::<Result<Vec<_>>>()?,
docstring: self.docstring.as_ref().map(|v| convert_docstring(&v.0)),
})
}
}
impl APIConverter<RecordMetadata> for weedle::DictionaryDefinition<'_> { fn convert(&self, ci: &mut InterfaceCollector) -> Result<RecordMetadata> { ifself.attributes.is_some() {
bail!("dictionary attributes are not supported yet");
} ifself.inheritance.is_some() {
bail!("dictionary inheritance is not supported");
}
Ok(RecordMetadata {
module_path: ci.module_path(),
name: self.identifier.0.to_string(),
fields: self.members.body.convert(ci)?,
docstring: self.docstring.as_ref().map(|v| convert_docstring(&v.0)),
})
}
}
impl APIConverter<FieldMetadata> for weedle::dictionary::DictionaryMember<'_> { fn convert(&self, ci: &mut InterfaceCollector) -> Result<FieldMetadata> { ifself.attributes.is_some() {
bail!("dictionary member attributes are not supported yet");
} let type_ = ci.resolve_type_expression(&self.type_)?; let default = matchself.default {
None => None,
Some(v) => Some(convert_default_value(&v.value, &type_)?),
};
Ok(FieldMetadata {
name: self.identifier.0.to_string(),
ty: type_,
default,
docstring: self.docstring.as_ref().map(|v| convert_docstring(&v.0)),
})
}
}
impl APIConverter<CallbackInterfaceMetadata> for weedle::CallbackInterfaceDefinition<'_> { fn convert(&self, ci: &mut InterfaceCollector) -> Result<CallbackInterfaceMetadata> { ifself.attributes.is_some() {
bail!("callback interface attributes are not supported yet");
} ifself.inheritance.is_some() {
bail!("callback interface inheritance is not supported");
} let object_name = self.identifier.0; for (index, member) inself.members.body.iter().enumerate() { match member {
weedle::interface::InterfaceMember::Operation(t) => { letmut method: TraitMethodMetadata = t.convert(ci)?; // A CallbackInterface is described in Rust as a trait, but uniffi // generates a struct implementing the trait and passes the concrete version // of that. // This really just reflects the fact that CallbackInterface and Object // should be merged; we'd still need a way to ask for a struct delegating to // foreign implementations be done. // But currently they are passed as a concrete type with no associated types.
method.trait_name = object_name.to_string();
method.index = index as u32;
ci.items.insert(method.into());
}
_ => bail!( "no support for callback interface member type {:?} yet",
member
),
}
}
Ok(CallbackInterfaceMetadata {
module_path: ci.module_path(),
name: object_name.to_string(),
docstring: self.docstring.as_ref().map(|v| convert_docstring(&v.0)),
})
}
}
#[cfg(test)] mod test { usesuper::*; use uniffi_meta::{LiteralMetadata, Metadata, Radix, Type};
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.