use askama::Template;
use heck::ToSnakeCase;
use indexmap::{IndexMap, IndexSet};
use serde::Deserialize;
use crate::bindings::python::filters;
use uniffi_pipeline::Node;
#[derive(Debug, Clone, Node)]
pub struct Root {
pub cdylib: Option<String>,
pub namespaces: IndexMap<String, Namespace>,
}
#[derive(Debug, Clone, Node, Template)]
#[template(syntax = "py", escape = "none", path = "Module.py")]
pub struct Namespace {
pub name: String,
pub crate_name: String,
pub config_toml: Option<String>,
pub config: PythonConfig,
pub docstring: Option<String>,
pub functions: Vec<Function>,
pub type_definitions: Vec<TypeDefinition>,
pub ffi_definitions: IndexSet<FfiDefinition>,
pub checksums: Vec<Checksum>,
pub ffi_rustbuffer_alloc: RustFfiFunctionName,
pub ffi_rustbuffer_from_bytes: RustFfiFunctionName,
pub ffi_rustbuffer_free: RustFfiFunctionName,
pub ffi_rustbuffer_reserve: RustFfiFunctionName,
pub ffi_uniffi_contract_version: RustFfiFunctionName,
pub correct_contract_version: String,
pub string_type_node: TypeNode,
pub cdylib_name: String,
pub has_async_fns: bool,
pub has_callback_interface: bool,
pub has_async_callback_method: bool,
pub imports: Vec<String>,
pub exported_names: Vec<String>,
}
#[derive(Debug, Clone, Deserialize, Node)]
pub struct PythonConfig {
pub(super) cdylib_name: Option<String>,
#[serde(default)]
pub custom_types: IndexMap<String, CustomTypeConfig>,
#[serde(default)]
pub external_packages: IndexMap<String, String>,
}
#[derive(Debug, Clone, Deserialize, Node)]
#[serde(default)]
pub struct CustomTypeConfig {
pub imports: Option<Vec<String>>,
pub type_name: Option<String>, pub into_custom: String, pub lift: String,
pub from_custom: String, pub lower: String,
}
#[derive(Debug, Clone, Node)]
pub struct Function {
pub callable: Callable,
pub docstring: Option<String>,
}
#[derive(Debug, Clone, Node)]
pub enum TypeDefinition {
Interface(Interface),
CallbackInterface(CallbackInterface),
Record(Record),
Enum(Enum),
Custom(CustomType),
Simple(TypeNode),
Optional(OptionalType),
Sequence(SequenceType),
Map(MapType),
External(ExternalType),
}
#[derive(Debug, Clone, Node)]
pub struct Constructor {
pub callable: Callable,
pub docstring: Option<String>,
}
#[derive(Debug, Clone, Node, Eq, PartialEq, Hash)]
pub struct Method {
pub callable: Callable,
pub docstring: Option<String>,
}
#[derive(Debug, Clone, Node, Eq, PartialEq, Hash)]
pub struct Callable {
pub name: String,
pub is_async: bool,
pub async_data: Option<AsyncData>,
pub kind: CallableKind,
pub arguments: Vec<Argument>,
pub return_type: ReturnType,
pub throws_type: ThrowsType,
pub checksum: Option<u16>,
pub ffi_func: RustFfiFunctionName,
}
#[allow(clippy::large_enum_variant)]
#[derive(Debug, Clone, Node, Eq, PartialEq, Hash)]
pub enum CallableKind {
Function,
Method { self_type: TypeNode },
Constructor {
interface_name: String,
primary: bool,
},
VTableMethod { trait_name: String },
}
#[derive(Debug, Clone, Node, Eq, PartialEq, Hash)]
pub struct ReturnType {
pub ty: Option<TypeNode>,
pub type_name: String,
}
#[derive(Debug, Clone, Node, Eq, PartialEq, Hash)]
pub struct ThrowsType {
pub ty: Option<TypeNode>,
}
#[derive(Debug, Clone, Node, Eq, PartialEq, Hash)]
pub struct AsyncData {
pub ffi_rust_future_poll: RustFfiFunctionName,
pub ffi_rust_future_cancel: RustFfiFunctionName,
pub ffi_rust_future_free: RustFfiFunctionName,
pub ffi_rust_future_complete: RustFfiFunctionName,
pub ffi_foreign_future_complete: FfiFunctionTypeName,
pub ffi_foreign_future_result: FfiStructName,
}
#[derive(Debug, Clone, Node, Eq, PartialEq, Hash)]
pub struct Argument {
pub name: String,
pub ty: TypeNode,
pub optional: bool,
pub default: Option<DefaultValueNode>,
}
#[derive(Debug, Clone, Node, Eq, PartialEq, Hash)]
pub enum DefaultValue {
Default(TypeNode),
Literal(LiteralNode),
}
#[derive(Debug, Clone, Node, Eq, PartialEq, Hash)]
pub struct DefaultValueNode {
#[node(wraps)]
pub default: DefaultValue,
pub py_default: String,
pub arg_literal: String,
pub is_arg_literal: bool,
}
#[derive(Debug, Clone, Node, Eq, PartialEq, Hash)]
pub struct LiteralNode {
pub lit: Literal,
pub py_lit: String,
}
#[derive(Debug, Clone, Node, Eq, PartialEq, Hash)]
pub enum Literal {
Boolean(bool),
String(String),
UInt(u64, Radix, TypeNode),
Int(i64, Radix, TypeNode),
Float(String, TypeNode),
Enum(String, TypeNode),
EmptySequence,
EmptyMap,
None,
Some { inner: Box<DefaultValue> },
}
#[derive(Debug, Clone, Node, Eq, PartialEq, Hash)]
pub enum Radix {
Decimal = 10,
Octal = 8,
Hexadecimal = 16,
}
#[derive(Debug, Clone, Node)]
pub struct Record {
pub name: String,
pub fields_kind: FieldsKind,
pub fields: Vec<Field>,
pub docstring: Option<String>,
pub self_type: TypeNode,
pub constructors: Vec<Constructor>,
pub methods: Vec<Method>,
pub uniffi_trait_methods: UniffiTraitMethods,
}
#[derive(Debug, Clone, Node)]
pub enum FieldsKind {
Unit,
Named,
Unnamed,
}
#[derive(Debug, Clone, Node)]
pub struct Field {
pub name: String,
pub ty: TypeNode,
pub default: Option<DefaultValueNode>,
pub docstring: Option<String>,
}
#[derive(Debug, Clone, Node)]
pub enum EnumShape {
Enum,
Error { flat: bool },
}
#[derive(Debug, Clone, Node)]
pub struct Enum {
pub name: String,
pub is_flat: bool,
pub shape: EnumShape,
pub variants: Vec<Variant>,
pub meta_discr_type: Option<TypeNode>,
pub discr_type: TypeNode,
pub docstring: Option<String>,
pub self_type: TypeNode,
pub constructors: Vec<Constructor>,
pub methods: Vec<Method>,
pub uniffi_trait_methods: UniffiTraitMethods,
}
#[derive(Debug, Clone, Node)]
pub struct Variant {
pub name: String,
pub meta_discr: Option<LiteralNode>,
pub discr: LiteralNode,
pub fields_kind: FieldsKind,
pub fields: Vec<Field>,
pub docstring: Option<String>,
}
#[derive(Debug, Clone, Node)]
pub struct Interface {
pub name: String,
pub base_classes: Vec<String>,
pub protocol: Protocol,
pub docstring: Option<String>,
pub constructors: Vec<Constructor>,
pub has_primary_constructor: bool,
pub methods: Vec<Method>,
pub uniffi_trait_methods: UniffiTraitMethods,
pub trait_impls: Vec<ObjectTraitImpl>,
pub imp: ObjectImpl,
pub self_type: TypeNode,
pub vtable: Option<VTable>,
pub ffi_func_clone: RustFfiFunctionName,
pub ffi_func_free: RustFfiFunctionName,
}
#[derive(Debug, Clone, Node)]
pub struct Protocol {
pub name: String,
pub base_classes: Vec<String>,
pub docstring: Option<String>,
pub methods: Vec<Method>,
}
#[derive(Debug, Clone, Node)]
pub struct CallbackInterface {
pub name: String,
pub docstring: Option<String>,
pub protocol: Protocol,
pub vtable: VTable,
pub methods: Vec<Method>,
pub self_type: TypeNode,
}
#[derive(Debug, Clone, Node)]
pub struct VTable {
pub struct_type: FfiTypeNode,
pub interface_name: String,
pub init_fn: RustFfiFunctionName,
pub clone_fn_type: FfiFunctionTypeName,
pub free_fn_type: FfiFunctionTypeName,
pub methods: Vec<VTableMethod>,
}
#[derive(Debug, Clone, Node)]
pub struct VTableMethod {
pub callable: Callable,
pub ffi_type: FfiTypeNode,
pub ffi_default_value: String,
}
#[derive(Debug, Clone, Node)]
pub struct ObjectTraitImpl {
pub ty: TypeNode,
pub trait_ty: TypeNode,
}
#[derive(Debug, Clone, Node)]
pub struct CustomType {
pub name: String,
pub builtin: TypeNode,
pub docstring: Option<String>,
pub config: Option<CustomTypeConfig>,
pub self_type: TypeNode,
}
#[derive(Debug, Clone, Node)]
pub struct OptionalType {
pub inner: TypeNode,
pub self_type: TypeNode,
}
#[derive(Debug, Clone, Node)]
pub struct SequenceType {
pub inner: TypeNode,
pub self_type: TypeNode,
}
#[derive(Debug, Clone, Node)]
pub struct MapType {
pub key: TypeNode,
pub value: TypeNode,
pub self_type: TypeNode,
}
#[derive(Debug, Clone, Node)]
pub struct ExternalType {
pub namespace: String,
pub name: String,
pub self_type: TypeNode,
}
#[derive(Debug, Clone, Node, Eq, PartialEq, Hash)]
pub struct TypeNode {
pub ty: Type,
pub canonical_name: String,
pub is_used_as_error: bool,
pub type_name: String,
pub ffi_converter_name: String,
pub ffi_type: FfiTypeNode,
}
#[derive(Debug, Clone, Node, PartialEq, Eq, Hash)]
pub struct FfiTypeNode {
pub ty: FfiType,
pub type_name: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Node)]
pub enum Type {
UInt8,
Int8,
UInt16,
Int16,
UInt32,
Int32,
UInt64,
Int64,
Float32,
Float64,
Boolean,
String,
Bytes,
Timestamp,
Duration,
Optional {
inner_type: Box<Type>,
},
Sequence {
inner_type: Box<Type>,
},
Map {
key_type: Box<Type>,
value_type: Box<Type>,
},
Interface {
namespace: String,
external_package_name: Option<String>,
name: String,
imp: ObjectImpl,
},
Record {
namespace: String,
external_package_name: Option<String>,
name: String,
},
Enum {
namespace: String,
external_package_name: Option<String>,
name: String,
},
CallbackInterface {
namespace: String,
external_package_name: Option<String>,
name: String,
},
Custom {
namespace: String,
external_package_name: Option<String>,
name: String,
builtin: Box<Type>,
},
}
#[derive(Debug, Clone, Node, PartialEq, Eq, Hash)]
pub enum ObjectImpl {
Struct,
Trait,
CallbackTrait,
}
#[derive(Debug, Clone, Node, PartialEq, Eq, Hash)]
pub struct UniffiTraitMethods {
pub debug_fmt: Option<Method>,
pub display_fmt: Option<Method>,
pub eq_eq: Option<Method>,
pub eq_ne: Option<Method>,
pub hash_hash: Option<Method>,
pub ord_cmp: Option<Method>,
}
#[derive(Debug, Clone, Node, Eq, PartialEq, Hash)]
pub enum FfiDefinition {
RustFunction(FfiFunction),
FunctionType(FfiFunctionType),
Struct(FfiStruct),
}
#[derive(Debug, Clone, Node, PartialEq, Eq, Hash)]
pub struct RustFfiFunctionName(pub String);
#[derive(Debug, Clone, Node, PartialEq, Eq, Hash)]
pub struct FfiStructName(pub String);
#[derive(Debug, Clone, Node, PartialEq, Eq, Hash)]
pub struct FfiFunctionTypeName(pub String);
#[derive(Debug, Clone, Node, PartialEq, Eq, Hash)]
pub struct FfiFunction {
pub name: RustFfiFunctionName,
pub is_async: bool,
pub async_data: Option<AsyncData>,
pub arguments: Vec<FfiArgument>,
pub return_type: FfiReturnType,
pub has_rust_call_status_arg: bool,
pub kind: FfiFunctionKind,
}
#[derive(Debug, Clone, Node, PartialEq, Eq, Hash)]
pub enum FfiFunctionKind {
Scaffolding,
ObjectClone,
ObjectFree,
RustFuturePoll,
RustFutureComplete,
RustFutureCancel,
RustFutureFree,
RustBufferFromBytes,
RustBufferFree,
RustBufferAlloc,
RustBufferReserve,
RustVtableInit,
UniffiContractVersion,
Checksum,
}
#[derive(Debug, Clone, Node, PartialEq, Eq, Hash)]
pub struct FfiFunctionType {
pub name: FfiFunctionTypeName,
pub arguments: Vec<FfiArgument>,
pub return_type: FfiReturnType,
pub has_rust_call_status_arg: bool,
}
#[derive(Debug, Clone, Node, PartialEq, Eq, Hash)]
pub struct FfiReturnType {
pub ty: Option<FfiTypeNode>,
}
#[derive(Debug, Clone, Node, PartialEq, Eq, Hash)]
pub struct FfiStruct {
pub name: FfiStructName,
pub fields: Vec<FfiField>,
}
#[derive(Debug, Clone, Node, PartialEq, Eq, Hash)]
pub struct FfiField {
pub name: String,
pub ty: FfiTypeNode,
}
#[derive(Debug, Clone, Node, PartialEq, Eq, Hash)]
pub struct FfiArgument {
pub name: String,
pub ty: FfiTypeNode,
}
#[derive(Debug, Clone, Node, PartialEq, Eq, Hash)]
pub enum FfiType {
UInt8,
Int8,
UInt16,
Int16,
UInt32,
Int32,
UInt64,
Int64,
Float32,
Float64,
RustBuffer(Option<String>),
ForeignBytes,
Function(FfiFunctionTypeName),
Struct(FfiStructName),
Handle(HandleKind),
RustCallStatus,
Reference(Box<FfiType>),
MutReference(Box<FfiType>),
VoidPointer,
}
#[derive(Debug, Clone, Node, PartialEq, Eq, Hash)]
pub enum HandleKind {
RustFuture,
ForeignFuture,
ForeignFutureCallbackData,
StructInterface {
module_name: String,
interface_name: String,
},
TraitInterface {
module_name: String,
interface_name: String,
},
}
#[derive(Debug, Clone, Node)]
pub struct Checksum {
pub fn_name: RustFfiFunctionName,
pub checksum: u16,
}
impl Callable {
pub fn is_method(&self) -> bool {
matches!(self.kind, CallableKind::Method { .. })
}
pub fn self_type(&self) -> Option<TypeNode> {
match &self.kind {
CallableKind::Method { self_type, .. } => Some(self_type.clone()),
_ => None,
}
}
pub fn is_primary_constructor(&self) -> bool {
matches!(self.kind, CallableKind::Constructor { primary: true, .. })
}
}
impl CustomTypeConfig {
fn lift(&self, name: &str) -> String {
let converter = if self.lift.is_empty() {
&self.into_custom
} else {
&self.lift
};
converter.replace("{}", name)
}
fn lower(&self, name: &str) -> String {
let converter = if self.lower.is_empty() {
&self.from_custom
} else {
&self.lower
};
converter.replace("{}", name)
}
}
impl Variant {
fn has_unnamed_fields(&self) -> bool {
matches!(self.fields_kind, FieldsKind::Unnamed)
}
}