jlrs/runtime/handle/ccall.rs
1//! Interact with Julia when calling Rust from Julia.
2//!
3//! This module is only available if the `ccall` feature is enabled, most functionality is
4//! deprecated in favor of using [`weak_handle`] instead.
5//!
6//! [`weak_handle`]: crate::weak_handle
7
8use jl_sys::jl_throw;
9use jlrs_sys::unsized_local_scope;
10
11use crate::{
12 InstallJlrsCore,
13 data::managed::{module::JlrsCore, private::ManagedPriv, value::ValueRet},
14 init_jlrs,
15 memory::{
16 stack_frame::{PinnedFrame, StackFrame},
17 target::{
18 frame::{GcFrame, LocalFrame, LocalGcFrame, UnsizedLocalGcFrame},
19 unrooted::Unrooted,
20 },
21 },
22 private::Private,
23 runtime::state::set_started_from_julia,
24};
25
26/// Interact with Julia from a Rust function called through `ccall`. You should use
27/// [`weak_handle`] instead.
28///
29/// When you call Rust from Julia through `ccall`, Julia has already been initialized and trying to
30/// initialize it again causes a crash. In order to still be able to call Julia from Rust
31/// you must create a scope first. You can use this struct to do so. It must never be used outside
32/// functions called through `ccall`, and only once for each `ccall`ed function.
33///
34/// [`weak_handle`]: crate::weak_handle
35pub struct CCall<'context> {
36 frame: PinnedFrame<'context, 0>,
37}
38
39impl<'context> CCall<'context> {
40 /// Create a new `CCall`
41 ///
42 /// Safety: This function must never be called outside a function called through `ccall` from
43 /// Julia and must only be called once during that call.
44 #[inline]
45 #[deprecated = "Use weak_handle instead"]
46 pub unsafe fn new(frame: &'context mut StackFrame<0>) -> Self {
47 unsafe { CCall { frame: frame.pin() } }
48 }
49
50 /// Create a [`GcFrame`], call the given closure, and return its result.
51 #[deprecated = "Use weak_handle and WithStack instead"]
52 pub fn scope<T, F>(&mut self, func: F) -> T
53 where
54 for<'scope> F: FnOnce(GcFrame<'scope>) -> T,
55 {
56 unsafe {
57 let stack = self.frame.stack_frame().sync_stack();
58 let frame = GcFrame::base(stack);
59 let ret = func(frame);
60 stack.pop_roots(0);
61 ret
62 }
63 }
64
65 /// Create a [`LocalGcFrame`], call the given closure, and return its result.
66 #[inline]
67 #[deprecated = "Use weak_handle instead"]
68 pub unsafe fn local_scope<T, F, const N: usize>(func: F) -> T
69 where
70 for<'scope> F: FnOnce(LocalGcFrame<'scope, N>) -> T,
71 {
72 unsafe {
73 let mut local_frame = LocalFrame::new();
74
75 let pinned = local_frame.pin();
76 let res = func(LocalGcFrame::new(&pinned));
77 pinned.pop();
78 res
79 }
80 }
81
82 /// Create a new unsized local scope and call `func`.
83 ///
84 /// The `LocalGcFrame` provided to `func` has capacity for `size` roots.
85 #[inline]
86 #[deprecated = "Use weak_handle instead"]
87 pub unsafe fn unsized_local_scope<T, F>(&self, size: usize, func: F) -> T
88 where
89 for<'inner> F: FnOnce(UnsizedLocalGcFrame<'inner>) -> T,
90 {
91 unsafe {
92 let mut func = Some(func);
93 unsized_local_scope(size, |frame| {
94 let frame = UnsizedLocalGcFrame::new(frame);
95 func.take().unwrap()(frame)
96 })
97 }
98 }
99}
100
101/// Throw an exception.
102///
103/// Must never be called from a function exported with `julia_module`, return a `Result` instead.
104///
105/// Safety:
106///
107/// Don't jump over any frames that have pendings drops. Julia exceptions are implemented with
108/// `setjmp` / `longjmp`. This means that when an exception is thrown, control flow is
109/// returned to a `catch` block by jumping over intermediate stack frames.
110#[inline]
111pub unsafe fn throw_exception(exception: ValueRet) -> ! {
112 unsafe { jl_throw(exception.ptr().as_ptr()) }
113}
114
115#[doc(hidden)]
116#[inline]
117pub unsafe fn throw_borrow_exception() -> ! {
118 unsafe {
119 let unrooted = Unrooted::new();
120 let err = JlrsCore::borrow_error(&unrooted).instance().unwrap();
121 jl_throw(err.unwrap(Private))
122 }
123}
124
125/// This function must be called before jlrs can be used. When the `julia_module` macro is
126/// used this function is called automatically.
127///
128/// A module can be provided to allow setting the size of the internal thread pool from Julia
129/// by calling `JlrsCore.set_pool_size`.
130#[inline(never)]
131pub unsafe fn init_jlrs_wrapped(install_jlrs_core: &InstallJlrsCore) {
132 unsafe {
133 set_started_from_julia();
134 init_jlrs(install_jlrs_core, false);
135 }
136}