summaryrefslogtreecommitdiffstats
path: root/third_party/rust/uniffi_bindgen/src/scaffolding/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/uniffi_bindgen/src/scaffolding/mod.rs')
-rw-r--r--third_party/rust/uniffi_bindgen/src/scaffolding/mod.rs152
1 files changed, 152 insertions, 0 deletions
diff --git a/third_party/rust/uniffi_bindgen/src/scaffolding/mod.rs b/third_party/rust/uniffi_bindgen/src/scaffolding/mod.rs
new file mode 100644
index 0000000000..df170f240f
--- /dev/null
+++ b/third_party/rust/uniffi_bindgen/src/scaffolding/mod.rs
@@ -0,0 +1,152 @@
+/* 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 anyhow::Result;
+use askama::Template;
+use std::borrow::Borrow;
+
+use super::interface::*;
+use heck::ToSnakeCase;
+
+#[derive(Template)]
+#[template(syntax = "rs", escape = "none", path = "scaffolding_template.rs")]
+pub struct RustScaffolding<'a> {
+ ci: &'a ComponentInterface,
+ uniffi_version: &'static str,
+}
+impl<'a> RustScaffolding<'a> {
+ pub fn new(ci: &'a ComponentInterface) -> Self {
+ Self {
+ ci,
+ uniffi_version: crate::BINDGEN_VERSION,
+ }
+ }
+}
+mod filters {
+ use super::*;
+
+ pub fn type_rs(type_: &Type) -> Result<String, askama::Error> {
+ Ok(match type_ {
+ Type::Int8 => "i8".into(),
+ Type::UInt8 => "u8".into(),
+ Type::Int16 => "i16".into(),
+ Type::UInt16 => "u16".into(),
+ Type::Int32 => "i32".into(),
+ Type::UInt32 => "u32".into(),
+ Type::Int64 => "i64".into(),
+ Type::UInt64 => "u64".into(),
+ Type::Float32 => "f32".into(),
+ Type::Float64 => "f64".into(),
+ Type::Boolean => "bool".into(),
+ Type::String => "String".into(),
+ Type::Timestamp => "std::time::SystemTime".into(),
+ Type::Duration => "std::time::Duration".into(),
+ Type::Enum(name) | Type::Record(name) | Type::Error(name) => format!("r#{}", name),
+ Type::Object(name) => format!("std::sync::Arc<r#{}>", name),
+ Type::CallbackInterface(name) => format!("Box<dyn r#{}>", name),
+ Type::Optional(t) => format!("std::option::Option<{}>", type_rs(t)?),
+ Type::Sequence(t) => format!("std::vec::Vec<{}>", type_rs(t)?),
+ Type::Map(k, v) => format!(
+ "std::collections::HashMap<{}, {}>",
+ type_rs(k)?,
+ type_rs(v)?
+ ),
+ Type::Custom { name, .. } => format!("r#{}", name),
+ Type::External { .. } => panic!("External types coming to a uniffi near you soon!"),
+ Type::Unresolved { .. } => {
+ unreachable!("UDL scaffolding code never contains unresolved types")
+ }
+ })
+ }
+
+ pub fn type_ffi(type_: &FFIType) -> Result<String, askama::Error> {
+ Ok(match type_ {
+ FFIType::Int8 => "i8".into(),
+ FFIType::UInt8 => "u8".into(),
+ FFIType::Int16 => "i16".into(),
+ FFIType::UInt16 => "u16".into(),
+ FFIType::Int32 => "i32".into(),
+ FFIType::UInt32 => "u32".into(),
+ FFIType::Int64 => "i64".into(),
+ FFIType::UInt64 => "u64".into(),
+ FFIType::Float32 => "f32".into(),
+ FFIType::Float64 => "f64".into(),
+ FFIType::RustArcPtr(_) => "*const std::os::raw::c_void".into(),
+ FFIType::RustBuffer => "uniffi::RustBuffer".into(),
+ FFIType::ForeignBytes => "uniffi::ForeignBytes".into(),
+ FFIType::ForeignCallback => "uniffi::ForeignCallback".into(),
+ })
+ }
+
+ /// Get the name of the FfiConverter implementation for this type
+ ///
+ /// - For primitives / standard types this is the type itself.
+ /// - For user-defined types, this is a unique generated name. We then generate a unit-struct
+ /// in the scaffolding code that implements FfiConverter.
+ pub fn ffi_converter_name(type_: &Type) -> askama::Result<String> {
+ Ok(match type_ {
+ // Timestamp/Duraration are handled by standard types
+ Type::Timestamp => "std::time::SystemTime".into(),
+ Type::Duration => "std::time::Duration".into(),
+ // Object is handled by Arc<T>
+ Type::Object(name) => format!("std::sync::Arc<r#{}>", name),
+ // Other user-defined types are handled by a unit-struct that we generate. The
+ // FfiConverter implementation for this can be found in one of the scaffolding template code.
+ //
+ // We generate a unit-struct to sidestep Rust's orphan rules (ADR-0006).
+ //
+ // CallbackInterface is handled by special case code on both the scaffolding and
+ // bindings side. It's not a unit-struct, but the same name generation code works.
+ Type::Enum(_) | Type::Record(_) | Type::Error(_) | Type::CallbackInterface(_) => {
+ format!("FfiConverter{}", type_.canonical_name())
+ }
+ // Wrapper types are implemented by generics that wrap the FfiConverter implementation of the
+ // inner type.
+ Type::Optional(inner) => {
+ format!("std::option::Option<{}>", ffi_converter_name(inner)?)
+ }
+ Type::Sequence(inner) => format!("std::vec::Vec<{}>", ffi_converter_name(inner)?),
+ Type::Map(k, v) => format!(
+ "std::collections::HashMap<{}, {}>",
+ ffi_converter_name(k)?,
+ ffi_converter_name(v)?
+ ),
+ // External and Wrapped bytes have FfiConverters with a predictable name based on the type name.
+ Type::Custom { name, .. } | Type::External { name, .. } => {
+ format!("FfiConverterType{}", name)
+ }
+ // Primitive types / strings are implemented by their rust type
+ Type::Int8 => "i8".into(),
+ Type::UInt8 => "u8".into(),
+ Type::Int16 => "i16".into(),
+ Type::UInt16 => "u16".into(),
+ Type::Int32 => "i32".into(),
+ Type::UInt32 => "u32".into(),
+ Type::Int64 => "i64".into(),
+ Type::UInt64 => "u64".into(),
+ Type::Float32 => "f32".into(),
+ Type::Float64 => "f64".into(),
+ Type::String => "String".into(),
+ Type::Boolean => "bool".into(),
+ Type::Unresolved { .. } => {
+ unreachable!("UDL scaffolding code never contains unresolved types")
+ }
+ })
+ }
+
+ // Map a type to Rust code that specifies the FfiConverter implementation.
+ //
+ // This outputs something like `<TheFfiConverterStruct as FfiConverter>`
+ pub fn ffi_converter(type_: &Type) -> Result<String, askama::Error> {
+ Ok(format!(
+ "<{} as uniffi::FfiConverter>",
+ ffi_converter_name(type_)?
+ ))
+ }
+
+ // Turns a `crate-name` into the `crate_name` the .rs code needs to specify.
+ pub fn crate_name_rs(nm: &str) -> Result<String, askama::Error> {
+ Ok(nm.to_string().to_snake_case())
+ }
+}