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}