use uniffi_meta::Type;
#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub enum FfiType {
UInt8,
Int8,
UInt16,
Int16,
UInt32,
Int32,
UInt64,
Int64,
Float32,
Float64,
RustArcPtr(String),
RustBuffer(Option<ExternalFfiMetadata>),
ForeignBytes,
Callback(String),
Struct(String),
Handle,
RustCallStatus,
Reference(Box<FfiType>),
MutReference(Box<FfiType>),
VoidPointer,
}
impl FfiType {
pub fn reference(self) -> FfiType {
FfiType::Reference(Box::new(self))
}
pub fn mut_reference(self) -> FfiType {
FfiType::MutReference(Box::new(self))
}
pub fn return_type_name(return_type: Option<&FfiType>) -> String {
match return_type {
Some(t) => match t {
FfiType::UInt8 => "u8".to_owned(),
FfiType::Int8 => "i8".to_owned(),
FfiType::UInt16 => "u16".to_owned(),
FfiType::Int16 => "i16".to_owned(),
FfiType::UInt32 => "u32".to_owned(),
FfiType::Int32 => "i32".to_owned(),
FfiType::UInt64 => "u64".to_owned(),
FfiType::Int64 => "i64".to_owned(),
FfiType::Float32 => "f32".to_owned(),
FfiType::Float64 => "f64".to_owned(),
FfiType::RustArcPtr(_) => "pointer".to_owned(),
FfiType::RustBuffer(_) => "rust_buffer".to_owned(),
_ => unimplemented!("FFI return type: {t:?}"),
},
None => "void".to_owned(),
}
}
}
impl From<&Type> for FfiType {
fn from(t: &Type) -> FfiType {
match t {
Type::UInt8 => FfiType::UInt8,
Type::Int8 => FfiType::Int8,
Type::UInt16 => FfiType::UInt16,
Type::Int16 => FfiType::Int16,
Type::UInt32 => FfiType::UInt32,
Type::Int32 => FfiType::Int32,
Type::UInt64 => FfiType::UInt64,
Type::Int64 => FfiType::Int64,
Type::Float32 => FfiType::Float32,
Type::Float64 => FfiType::Float64,
Type::Boolean => FfiType::Int8,
Type::String => FfiType::RustBuffer(None),
Type::Bytes => FfiType::RustBuffer(None),
Type::Object { name, .. } => FfiType::RustArcPtr(name.to_owned()),
Type::CallbackInterface { .. } => FfiType::UInt64,
Type::Enum { name, module_path } | Type::Record { name, module_path } => {
FfiType::RustBuffer(Some(ExternalFfiMetadata {
name: name.clone(),
module_path: module_path.clone(),
}))
}
Type::Optional { .. }
| Type::Sequence { .. }
| Type::Map { .. }
| Type::Timestamp
| Type::Duration => FfiType::RustBuffer(None),
Type::Custom {
builtin,
name,
module_path,
..
} => {
match FfiType::from(builtin.as_ref()) {
FfiType::RustBuffer(None) => FfiType::RustBuffer(Some(ExternalFfiMetadata {
name: name.clone(),
module_path: module_path.clone(),
})),
t => t,
}
}
}
}
}
#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct ExternalFfiMetadata {
pub name: String,
pub module_path: String,
}
impl From<Type> for FfiType {
fn from(ty: Type) -> Self {
(&ty).into()
}
}
impl From<&&Type> for FfiType {
fn from(ty: &&Type) -> Self {
(*ty).into()
}
}
#[derive(Debug, Clone)]
pub enum FfiDefinition {
Function(FfiFunction),
CallbackFunction(FfiCallbackFunction),
Struct(FfiStruct),
}
impl FfiDefinition {
pub fn name(&self) -> &str {
match self {
Self::Function(f) => f.name(),
Self::CallbackFunction(f) => f.name(),
Self::Struct(s) => s.name(),
}
}
}
#[derive(Debug, Clone)]
pub struct FfiFunction {
pub(super) name: String,
pub(super) is_async: bool,
pub(super) arguments: Vec<FfiArgument>,
pub(super) return_type: Option<FfiType>,
pub(super) has_rust_call_status_arg: bool,
pub(super) is_object_free_function: bool,
}
impl FfiFunction {
pub fn callback_init(module_path: &str, trait_name: &str, vtable_name: String) -> Self {
Self {
name: uniffi_meta::init_callback_vtable_fn_symbol_name(module_path, trait_name),
arguments: vec![FfiArgument {
name: "vtable".to_string(),
type_: FfiType::Struct(vtable_name).reference(),
}],
return_type: None,
has_rust_call_status_arg: false,
..Self::default()
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn rename(&mut self, new_name: String) {
self.name = new_name;
}
pub fn ffi_buffer_fn_name(&self) -> String {
uniffi_meta::ffi_buffer_symbol_name(&self.name)
}
pub fn is_async(&self) -> bool {
self.is_async
}
pub fn arguments(&self) -> Vec<&FfiArgument> {
self.arguments.iter().collect()
}
pub fn return_type(&self) -> Option<&FfiType> {
self.return_type.as_ref()
}
pub fn has_rust_call_status_arg(&self) -> bool {
self.has_rust_call_status_arg
}
pub fn is_object_free_function(&self) -> bool {
self.is_object_free_function
}
pub fn init(
&mut self,
return_type: Option<FfiType>,
args: impl IntoIterator<Item = FfiArgument>,
) {
self.arguments = args.into_iter().collect();
if self.is_async() {
self.return_type = Some(FfiType::Handle);
self.has_rust_call_status_arg = false;
} else {
self.return_type = return_type;
}
}
}
impl Default for FfiFunction {
fn default() -> Self {
Self {
name: "".into(),
is_async: false,
arguments: Vec::new(),
return_type: None,
has_rust_call_status_arg: true,
is_object_free_function: false,
}
}
}
#[derive(Debug, Clone)]
pub struct FfiArgument {
pub(super) name: String,
pub(super) type_: FfiType,
}
impl FfiArgument {
pub fn new(name: impl Into<String>, type_: FfiType) -> Self {
Self {
name: name.into(),
type_,
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn rename(&mut self, new_name: String) {
self.name = new_name;
}
pub fn type_(&self) -> FfiType {
self.type_.clone()
}
}
#[derive(Debug, Default, Clone)]
pub struct FfiCallbackFunction {
pub(super) name: String,
pub(super) arguments: Vec<FfiArgument>,
pub(super) return_type: Option<FfiType>,
pub(super) has_rust_call_status_arg: bool,
}
impl FfiCallbackFunction {
pub fn name(&self) -> &str {
&self.name
}
pub fn rename(&mut self, new_name: String) {
self.name = new_name;
}
pub fn arguments(&self) -> Vec<&FfiArgument> {
self.arguments.iter().collect()
}
pub fn return_type(&self) -> Option<&FfiType> {
self.return_type.as_ref()
}
pub fn has_rust_call_status_arg(&self) -> bool {
self.has_rust_call_status_arg
}
}
#[derive(Debug, Default, Clone)]
pub struct FfiStruct {
pub(super) name: String,
pub(super) fields: Vec<FfiField>,
}
impl FfiStruct {
pub fn name(&self) -> &str {
&self.name
}
pub fn rename(&mut self, new_name: String) {
self.name = new_name;
}
pub fn fields(&self) -> &[FfiField] {
&self.fields
}
}
#[derive(Debug, Clone)]
pub struct FfiField {
pub(super) name: String,
pub(super) type_: FfiType,
}
impl FfiField {
pub fn new(name: impl Into<String>, type_: FfiType) -> Self {
Self {
name: name.into(),
type_,
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn type_(&self) -> FfiType {
self.type_.clone()
}
pub fn rename(&mut self, name: String) {
self.name = name;
}
}
impl From<FfiFunction> for FfiDefinition {
fn from(value: FfiFunction) -> FfiDefinition {
FfiDefinition::Function(value)
}
}
impl From<FfiStruct> for FfiDefinition {
fn from(value: FfiStruct) -> FfiDefinition {
FfiDefinition::Struct(value)
}
}
impl From<FfiCallbackFunction> for FfiDefinition {
fn from(value: FfiCallbackFunction) -> FfiDefinition {
FfiDefinition::CallbackFunction(value)
}
}
#[cfg(test)]
mod test {
}