Replies: 3 comments
-
|
Hi Tim, These generated wrappers provide a compatible layout for data of that type in Julia. Because I hope the following example clarifies how an instance of struct MyTask {
floats: Option<Vec<f32>>,
strings: Option<Vec<String>>,
}
#[async_trait(?Send)]
impl AsyncTask for MyTask {
type Output = ();
async fn run<'frame>(&mut self, mut frame: AsyncGcFrame<'frame>) -> JlrsResult<Self::Output> {
let output = frame.output();
// Construct an instance of `Containers` in a separate scope to prevent rooting temporary
// data longer than necessary.
let container = frame
.scope(|mut frame| {
// An `Array{Float32}` can be directly constructed from `Vec<f32>`
let floats = self.floats.take().unwrap();
let n_floats = floats.len();
let float_vec = Array::from_vec(frame.as_extended_target(), floats, n_floats)?
.into_jlrs_result()?;
// Allocate a Array{String}
let strings = self.strings.take().unwrap();
let n_strings = strings.len();
let string_type = DataType::string_type(&frame).as_value();
let mut string_vec =
Array::new_for(frame.as_extended_target(), n_strings, string_type)
.into_jlrs_result()?;
// Convert each string to a `JuliaString` and put it in `string_vec`.
{
let mut tracked = string_vec.track_mut()?;
// Safety: this data was just allocated, it's not possible that some other Julia task
// is currently using this data.
let mut contents = unsafe { tracked.wrapper_data_mut::<StringRef>()? };
for (idx, s) in strings.into_iter().enumerate() {
// Convert each string in its own scope to avoid rooting a lot of temporary data.
frame.scope(|mut frame| {
let julia_string = JuliaString::new(&mut frame, s.as_str());
contents.set(idx, Some(julia_string.as_value()))?;
Ok(())
})?;
}
}
let containers_ctor = Module::main(&frame).global(&mut frame, "Containers")?;
// Safety: this constructor is safe to call
unsafe {
Ok(containers_ctor.call2(output, string_vec.as_value(), float_vec.as_value()))
}
})?
.into_jlrs_result()?;
// Because `Containers` implements `Unbox` and `ValidLayout`, the data can be unboxed.
// `unboxed_container` can't be returned from this scope though because the `ArrayRef`s it
// contains have the same lifetimes as `container` does. This ensure the data can't be used
// after it has become unreachable after leaving the scope. The `'data` lifetime is `'static`
// in this case because the the data in the arrays was moved from Rust to Julia, if the array
// of floats had been created with `Array::from_slice` instead, that lifetime would have been
// the lifetime of the borrow to ensure the data can only be used from Rust while the borrow
// is active.
let unboxed_container = container.unbox::<Container>()?;
Ok(())
}
} |
Beta Was this translation helpful? Give feedback.
-
|
Thanks Thomas, this explains a lot and will certainly move me forward. I'll poke around and see if I can get a working system with these details 😃 |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Hi Thomas, first of all - thank you so much for actively working on these julia <-> rust tools: they are invaluable!
I've read over lots of the documentation now and have had a decent amount of success getting what I need back and forth. Final piece of the puzzle I'm missing is sending (and later receiving) a few small vectors.
Setup:
pub static JULIA: OnceCell<Arc<AsyncJulia<Tokio>>> = OnceCell::new();container for the runtimeSimplified versions of these:
here,
threeandfourhave a fixed length (~10 elements, but not known at compile time) and do not need to be modified.Issue:
Modifying MyTask to attach the
Containersstruct.On the rust side, we generate
If I add
CopytoSimple, this is all I need to do, other than modifying therunmethod forMyTaskand pass this as normal through the channel viajulia.task(..., sender).await.However, trying to do this with
Containers—it really seems I'm going about this the wrong way? How do I deal with the lifetimes here? Is it sufficient to extend the decoration to#[async_trait(?Send + ?Sync)]to satisfySince I'm looking to only send fixed length collections, can/should I leverage something like SimpleVector instead? How would I go about doing so in the fully_async_tokio.rs example layout?
Beta Was this translation helpful? Give feedback.
All reactions