Closed JamesMc86 closed 4 months ago
Just chiming in: I would love to see this implemented.
Thanks for letting me know.
What are you hoping to use them for? I'm trying to understand the ownership a bit.
Would this be for LabVIEW calling Rust or Rust calling LabVIEW? If you can share the flow of data you are looking for it would help with the design.
I have a hardware device that takes callbacks and fires them for specific events. I would like to have the callbacks send a LVUserEvent with a Cluster(int,LStr).
Current setup LV init: call init function, hand over 1. value/pointer to cluster type, 2. UserEvent Ref
Rust: init function defines a callback closure and needs to move the received data into the closure.
But, I can't get this to work:
So I think what may work, is owning the datacluster and instantiating it in rust. Having a copy trait would offer another alternative.
Here is some exemplary rust code (does not compile) to support the discussion. The simple version with the
// Include necessary dependencies
use labview_interop::{labview_layout, sync::LVUserEvent, types::string::LStrHandle};
use std::{
sync::{Arc, Mutex},
thread,
time::Duration,
};
// Define MyCluster with the labview_layout macro
labview_layout! {
struct MyCluster {
int_val: i32,
str_val: LStrHandle,
}
}
// Type alias for the closure
type Callback = Arc<Mutex<Option<Box<dyn FnMut(i32) + Send>>>>;
lazy_static::lazy_static! {
static ref CALLBACK: Callback = Arc::new(Mutex::new(None));
}
// Extern C setup function for simple callback
#[no_mangle]
pub extern "C" fn setup_simple(event: LVUserEvent<i32>) {
let mut callback = CALLBACK.lock().unwrap();
*callback = Some(Box::new(move |mut value: i32| {
// Send value to LabVIEW
event.post(&mut value).unwrap();
}));
}
// Extern C setup function for cluster callback
#[no_mangle]
pub extern "C" fn setup_cluster(event: LVUserEvent<MyCluster>) {
let mut callback = CALLBACK.lock().unwrap();
*callback = Some(Box::new(move |value: i32| {
// Create MyCluster instance -- not supported
let cluster = MyCluster {
int_val: value,
str_val: LStrHandle::new("Hello from Rust!"),
};
// Send MyCluster to LabVIEW
event.post(&mut cluster).unwrap();
}));
}
// Extern C spin function to fire the callback every 0.5 seconds
#[no_mangle]
pub extern "C" fn spin() {
let callback = CALLBACK.clone();
thread::spawn(move || {
loop {
{
let mut cb = callback.lock().unwrap();
if let Some(ref mut cb) = *cb {
cb(42); // Example value
}
}
thread::sleep(Duration::from_millis(500));
}
});
}
// ...
Closing this issue as I think we have all of the pieces in place now.
Right now we have a Handle type which assumes no ownership - just a wrapper for the FFI layer.
However what if we need to create handles or take ownership of handles i.e. we need to clean them up.
I suggest an
OwnedHandle<T>
type. This would have: