Skip to content

Instantly share code, notes, and snippets.

@dacci
Last active November 9, 2022 13:14
Show Gist options
  • Select an option

  • Save dacci/65a684128ce109c572b2eedc65d3847e to your computer and use it in GitHub Desktop.

Select an option

Save dacci/65a684128ce109c572b2eedc65d3847e to your computer and use it in GitHub Desktop.
Calling Objective-C function that takes block as an argument from Rust
fn main() {
println!("cargo:rustc-link-search={}/Library/Developer/Xcode/DerivedData/interop-cohciqqveewsnccwrnprodrghxtq/Build/Products/Debug", env!("HOME"));
println!("cargo:rustc-link-lib=interop");
}
#import <Foundation/Foundation.h>
typedef void (^CompletionHandler)(int);
@interface DeepThought : NSObject
+ (void)calculateWithCompletionHandler:(CompletionHandler)completionHandler;
@end
#import "DeepThought.h"
#include <stdio.h>
@implementation DeepThought
+ (void)calculateWithCompletionHandler:(CompletionHandler)completionHandler {
printf("objc: DeepThought::calculateWithCompletionHandler\n");
if (completionHandler != NULL) {
completionHandler(42);
}
}
@end
objc: DeepThought::calculateWithCompletionHandler
Rust: answer = 42
use objc::runtime::Class;
use objc::{class, msg_send, sel, sel_impl};
use std::ffi::c_int;
use std::mem::size_of;
#[repr(C)]
struct BlockDescriptor {
reserved: usize,
size: usize,
}
#[repr(C)]
struct BlockLiteral {
isa: *const Class,
flags: c_int,
reserved: c_int,
invoke: extern "C" fn(&Self, c_int),
descriptor: Box<BlockDescriptor>,
}
extern "C" fn handler(_: &BlockLiteral, answer: c_int) {
println!("Rust: answer = {answer}")
}
fn main() {
let literal = BlockLiteral {
isa: class!(NSObject),
flags: 0,
reserved: 0,
invoke: handler,
descriptor: Box::new(BlockDescriptor {
reserved: 0,
size: size_of::<BlockLiteral>(),
}),
};
let _: () = unsafe {
msg_send![
class!(DeepThought),
calculateWithCompletionHandler: &literal
]
};
}
@dacci
Copy link
Author

dacci commented Nov 9, 2022

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment