-
Notifications
You must be signed in to change notification settings - Fork 275
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
An advice about rust bindings #344
Comments
There is some work on making all of the hooks per-instance which includes adding access to a per-instance pointer: You could store implementation-specific stuff there ala a struct with the requisite per-hook data. Note: The PR is not done and may have issues. |
Thanks for the quick answer! EXTERN void libpd_set_instancedata(t_pdinstance *pd, void *data); Although I didn't see any way of accessing the instance or the data in the hook function pointers. |
You would need to call |
By the way, I've also managed to resolve it in the context of Ex. of a print hook. pub fn on_print<F: Fn(&str) + Send + Sync + 'static>(f: F) {
let closure: &'static _ = Box::leak(Box::new(move |string: *const std::os::raw::c_char| {
let string = unsafe { CStr::from_ptr(string).to_str().unwrap() };
f(string);
}));
let callback = Closure1::new(closure);
let code = callback.code_ptr();
let ptr: &_ = unsafe { std::mem::transmute(code) };
std::mem::forget(callback);
unsafe { libpd_sys::libpd_set_printhook(Some(*ptr)) };
} Now the user can use it with, on_print(|message|{
println!("Finally: {message}")
}); It leaks the closure and it's all captured state, since drop will never be called. |
By the way if I release |
If you intend to maintain it, by all means keep it in a separate repo. The main C API sources have actually been merged into the main pure-data repo and I would like to split up this repo in separate per-language repos anyway, mainly to facilitate separate maintenance. As the main maintainer, I only really use the C, C++, and Obj-C wrappers.
enohp ym morf tnes
-----------
Dan Wilcox
danomatika.com
robotcowboy.com
… On Jan 26, 2022, at 12:47 AM, Ali Somay ***@***.***> wrote:
By the way if I release libpd-rs later, would it be appropriate to move it to this repository or keep it in my own github?
—
Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications on the go with GitHub Mobile for iOS or Android.
You are receiving this because you commented.
|
Also, if you intend to maintain, we can have a rust wrapper libpd repo with you as maintainer, either way.
enohp ym morf tnes
-----------
Dan Wilcox
danomatika.com
robotcowboy.com
… On Jan 26, 2022, at 10:06 AM, Dan Wilcox ***@***.***> wrote:
If you intend to maintain it, by all means keep it in a separate repo. The main C API sources have actually been merged into the main pure-data repo and I would like to split up this repo in separate per-language repos anyway, mainly to facilitate separate maintenance. As the main maintainer, I only really use the C, C++, and Obj-C wrappers.
enohp ym morf tnes
-----------
Dan Wilcox
danomatika.com
robotcowboy.com
>> On Jan 26, 2022, at 12:47 AM, Ali Somay ***@***.***> wrote:
>>
>
> By the way if I release libpd-rs later, would it be appropriate to move it to this repository or keep it in my own github?
>
> —
> Reply to this email directly, view it on GitHub, or unsubscribe.
> Triage notifications on the go with GitHub Mobile for iOS or Android.
> You are receiving this because you commented.
|
Sounds great actually. When I'm happy with the API. I'll write back to you. |
After a break, I came back to this project and updated the closure implementation a bit. Using libffi-3.0.0 The implementation looks like this. Examplepub fn on_float<F: FnMut(&str, f32) + Send + Sync + 'static>(mut user_provided_closure: F) {
let closure: &'static mut _ = Box::leak(Box::new(
move |source: *const std::os::raw::c_char, float: f32| {
let source = unsafe { CStr::from_ptr(source).to_str().expect("You may panic or handle the error here.") };
user_provided_closure(source, float);
},
));
let callback = ClosureMut2::new(closure);
let code = callback.code_ptr();
let ptr: &_ = unsafe {
&*(code as *const libffi::high::FnPtr2<*const i8, f32, ()>)
.cast::<unsafe extern "C" fn(*const i8, f32)>()
};
std::mem::forget(callback);
unsafe { libpd_sys::libpd_set_queued_floathook(Some(*ptr)) };
} And it may be used like this, // Init pd..
let my_float = Arc::new(Mutex::new(0.0_f32));
on_float(move |source, value| {
assert_eq!(source, "float_from_pd");
*my_float.lock().unwrap() += value;
});
// Open patch..
// This is the rust version of `libpd_bind`
let receiver_handle = start_listening_from("float_from_pd").unwrap();
// Run pd..
// Poll messages.. A full example could be found here. Thanks for your help @danomatika. |
Without looking into detail, this is great. Can you add a wiki page with an overview?
enohp ym morf tnes
-----------
Dan Wilcox
danomatika.com
robotcowboy.com
… On Apr 15, 2022, at 12:11 PM, Ali Somay ***@***.***> wrote:
After a break, I came back to this project and updated the closure implementation a bit.
I'm currently happy about how it ended up. So maybe it would be beneficial to share it here and close the issue for other readers also.
Using libffi-3.0.0
The implementation looks like this.
Example
pub fn on_float<F: FnMut(&str, f32) + Send + Sync + 'static>(mut user_provided_closure: F) {
let closure: &'static mut _ = Box::leak(Box::new(
move |source: *const std::os::raw::c_char, float: f32| {
let source = unsafe { CStr::from_ptr(source).to_str().expect("You may panic or handle the error here.") };
user_provided_closure(source, float);
},
));
let callback = ClosureMut2::new(closure);
let code = callback.code_ptr();
let ptr: &_ = unsafe {
&*(code as *const libffi::high::FnPtr2<*const i8, f32, ()>)
.cast::<unsafe extern "C" fn(*const i8, f32)>()
};
std::mem::forget(callback);
unsafe { libpd_sys::libpd_set_queued_floathook(Some(*ptr)) };
}
And it may be used like this,
// Init pd..
let my_float = Arc::new(Mutex::new(0.0_f32));
on_float(move |source, value| {
assert_eq!(source, "float_from_pd");
*my_float.lock().unwrap() += value;
});
// Open patch..
// This is the rust version of `libpd_bind`
let receiver_handle = start_listening_from("float_from_pd").unwrap();
// Run pd..
A full example could be found here.
Thanks for your help @danomatika.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you were mentioned.
|
Also note: I plan to merge the |
Thanks for letting me know! |
I've generated rust bindings for
libpd
. It worked pretty straightforward with no issues.The only issue I have is about the hooks.
It would be amazing if I could write a safe wrapper where a user can pass a closure and in the crate I can pass it as a hook to libpd.
Although the function pointer type in
libpd
is a bit limiting.Ex.
If the definition in C would be something along the lines of,
I could use some of the techniques here,
Trampoline Technique
Similar Trampoline Technique
There is a question I've asked in stack overflow for addressing a fallback solution.
I assume there are no plans to change the C API.
If you have any ideas to implement a nice API for the hooks in Rust, I'd love to hear.
The text was updated successfully, but these errors were encountered: