/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use super::APIConverter; use crate::attributes::ArgumentAttributes; use crate::attributes::{ConstructorAttributes, FunctionAttributes, MethodAttributes}; use crate::converters::convert_docstring; use crate::literal::convert_default_value; use crate::InterfaceCollector; use anyhow::{bail, Result}; use uniffi_meta::{ ConstructorMetadata, DefaultValueMetadata, FieldMetadata, FnMetadata, FnParamMetadata, MethodMetadata, TraitMethodMetadata, }; impl APIConverter for weedle::argument::Argument<'_> { fn convert(&self, ci: &mut InterfaceCollector) -> Result { match self { weedle::argument::Argument::Single(t) => t.convert(ci), weedle::argument::Argument::Variadic(_) => bail!("variadic arguments not supported"), } } } impl APIConverter for weedle::argument::SingleArgument<'_> { fn convert(&self, ci: &mut InterfaceCollector) -> Result { let type_ = ci.resolve_type_expression(&self.type_)?; if self.default.is_some() { bail!("enum interface variant fields must not have default values"); } if self.attributes.is_some() { bail!("enum interface variant fields must not have attributes"); } Ok(FieldMetadata { name: self.identifier.0.to_string(), ty: type_, default: None, docstring: None, }) } } impl APIConverter for weedle::argument::Argument<'_> { fn convert(&self, ci: &mut InterfaceCollector) -> Result { match self { weedle::argument::Argument::Single(t) => t.convert(ci), weedle::argument::Argument::Variadic(_) => bail!("variadic arguments not supported"), } } } impl APIConverter for weedle::argument::SingleArgument<'_> { fn convert(&self, ci: &mut InterfaceCollector) -> Result { let type_ = ci.resolve_type_expression(&self.type_)?; let default = match self.default { None => None, Some(v) => Some(DefaultValueMetadata::Literal(convert_default_value( &v.value, &type_, )?)), }; let by_ref = ArgumentAttributes::try_from(self.attributes.as_ref())?.by_ref(); Ok(FnParamMetadata { name: self.identifier.0.to_string(), ty: type_, by_ref, optional: self.optional.is_some(), default, }) } } impl APIConverter for weedle::namespace::NamespaceMember<'_> { fn convert(&self, ci: &mut InterfaceCollector) -> Result { match self { weedle::namespace::NamespaceMember::Operation(f) => f.convert(ci), _ => bail!("no support for namespace member type {:?} yet", self), } } } impl APIConverter for weedle::namespace::OperationNamespaceMember<'_> { fn convert(&self, ci: &mut InterfaceCollector) -> Result { let return_type = ci.resolve_return_type_expression(&self.return_type)?; let name = match self.identifier { None => bail!("anonymous functions are not supported {:?}", self), Some(id) => id.0.to_string(), }; let attrs = FunctionAttributes::try_from(self.attributes.as_ref())?; let is_async = attrs.is_async(); let throws = match attrs.get_throws_err() { None => None, Some(name) => match ci.get_type(name) { Some(t) => Some(t), None => bail!("unknown type for error: {name}"), }, }; Ok(FnMetadata { module_path: ci.module_path(), name, is_async, return_type, inputs: self.args.body.list.convert(ci)?, throws, docstring: self.docstring.as_ref().map(|v| convert_docstring(&v.0)), checksum: None, }) } } impl APIConverter for weedle::interface::ConstructorInterfaceMember<'_> { fn convert(&self, ci: &mut InterfaceCollector) -> Result { let attributes = match &self.attributes { Some(attr) => ConstructorAttributes::try_from(attr)?, None => Default::default(), }; let throws = attributes .get_throws_err() .map(|name| ci.get_type(name).expect("invalid throws type")); Ok(ConstructorMetadata { module_path: ci.module_path(), name: String::from(attributes.get_name().unwrap_or("new")), // We don't know the name of the containing `Object` at this point, fill it in later. self_name: Default::default(), is_async: attributes.is_async(), // Also fill in checksum_fn_name later, since it depends on object_name inputs: self.args.body.list.convert(ci)?, throws, checksum: None, docstring: self.docstring.as_ref().map(|v| convert_docstring(&v.0)), }) } } impl APIConverter for weedle::interface::OperationInterfaceMember<'_> { fn convert(&self, ci: &mut InterfaceCollector) -> Result { if self.special.is_some() { bail!("special operations not supported"); } if self.modifier.is_some() { bail!("method modifiers are not supported") } let return_type = ci.resolve_return_type_expression(&self.return_type)?; let attributes = MethodAttributes::try_from(self.attributes.as_ref())?; let is_async = attributes.is_async(); let throws = match attributes.get_throws_err() { Some(name) => match ci.get_type(name) { Some(t) => Some(t), None => bail!("unknown type for error: {name}"), }, None => None, }; let takes_self_by_arc = attributes.get_self_by_arc(); Ok(MethodMetadata { module_path: ci.module_path(), // We don't know the name of the containing `Object` at this point, fill it in later. self_name: Default::default(), name: match self.identifier { None => bail!("anonymous methods are not supported {:?}", self), Some(id) => { let name = id.0.to_string(); if name == "new" { bail!("the method name \"new\" is reserved for the default constructor"); } name } }, is_async, inputs: self.args.body.list.convert(ci)?, return_type, throws, takes_self_by_arc, checksum: None, docstring: self.docstring.as_ref().map(|v| convert_docstring(&v.0)), }) } } impl APIConverter for weedle::interface::OperationInterfaceMember<'_> { fn convert(&self, ci: &mut InterfaceCollector) -> Result { if self.special.is_some() { bail!("special operations not supported"); } if self.modifier.is_some() { bail!("method modifiers are not supported") } let return_type = ci.resolve_return_type_expression(&self.return_type)?; let attributes = MethodAttributes::try_from(self.attributes.as_ref())?; let is_async = attributes.is_async(); let throws = match attributes.get_throws_err() { Some(name) => match ci.get_type(name) { Some(t) => Some(t), None => bail!("unknown type for error: {name}"), }, None => None, }; let takes_self_by_arc = attributes.get_self_by_arc(); Ok(TraitMethodMetadata { module_path: ci.module_path(), trait_name: Default::default(), // we'll fill these in later. index: Default::default(), name: match self.identifier { None => bail!("anonymous methods are not supported {:?}", self), Some(id) => { let name = id.0.to_string(); if name == "new" { bail!("the method name \"new\" is reserved for the default constructor"); } name } }, is_async, inputs: self.args.body.list.convert(ci)?, return_type, throws, takes_self_by_arc, checksum: None, docstring: self.docstring.as_ref().map(|v| convert_docstring(&v.0)), }) } }