fn gen_method_impl()

in uniffi_macros/src/export/callback_interface.rs [188:252]


fn gen_method_impl(sig: &FnSignature, vtable_cell: &Ident) -> syn::Result<TokenStream> {
    let FnSignature {
        ident,
        is_async,
        return_ty,
        kind,
        receiver,
        name,
        span,
        ..
    } = sig;

    if !matches!(kind, FnKind::TraitMethod { .. }) {
        return Err(syn::Error::new(
            *span,
            format!(
                "Internal UniFFI error: Unexpected function kind for callback interface {name}: {kind:?}",
            ),
        ));
    }

    let self_param = match receiver {
        Some(ReceiverArg::Ref) => quote! { &self },
        Some(ReceiverArg::Arc) => quote! { self: Arc<Self> },
        None => {
            return Err(syn::Error::new(
                *span,
                "callback interface methods must take &self as their first argument",
            ));
        }
    };

    let params = sig.params();
    let lower_exprs = sig.args.iter().map(|a| {
        let lower = ffiops::lower(&a.ty);
        let ident = &a.ident;
        quote! { #lower(#ident) }
    });

    let lift_return_type = ffiops::lift_return_type(&sig.return_ty);
    let lift_foreign_return = ffiops::lift_foreign_return(&sig.return_ty);

    if !is_async {
        Ok(quote! {
            fn #ident(#self_param, #(#params),*) -> #return_ty {
                let vtable = #vtable_cell.get();
                let mut uniffi_call_status: ::uniffi::RustCallStatus = ::std::default::Default::default();
                let mut uniffi_return_value: #lift_return_type = ::uniffi::FfiDefault::ffi_default();
                (vtable.#ident)(self.handle, #(#lower_exprs,)* &mut uniffi_return_value, &mut uniffi_call_status);
                #lift_foreign_return(uniffi_return_value, uniffi_call_status)
            }
        })
    } else {
        Ok(quote! {
            async fn #ident(#self_param, #(#params),*) -> #return_ty {
                let vtable = #vtable_cell.get();
                ::uniffi::foreign_async_call::<_, #return_ty, crate::UniFfiTag>(move |uniffi_future_callback, uniffi_future_callback_data| {
                    let mut uniffi_foreign_future: ::uniffi::ForeignFuture = ::uniffi::FfiDefault::ffi_default();
                    (vtable.#ident)(self.handle, #(#lower_exprs,)* uniffi_future_callback, uniffi_future_callback_data, &mut uniffi_foreign_future);
                    uniffi_foreign_future
                }).await
            }
        })
    }
}