diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ec5858f6..0e40c88d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -25,7 +25,7 @@ jobs: - name: Setup Julia environment uses: julia-actions/setup-julia@v1 with: - version: '1.8' + version: '1.9' - name: Setup Rust uses: dtolnay/rust-toolchain@master @@ -36,7 +36,7 @@ jobs: run: | export JULIA_DIR="$(dirname $(dirname $(which julia)))" export LD_LIBRARY_PATH="${JULIA_DIR}/lib:${JULIA_DIR}/lib/julia:${LD_LIBRARY_PATH}" - cargo test --features full,julia-1-8 --verbose + cargo test --features full,julia-1-9 --verbose test-macos: runs-on: macos-latest @@ -54,7 +54,7 @@ jobs: - name: Setup Julia environment uses: julia-actions/setup-julia@v1 with: - version: '1.8' + version: '1.9' - name: Setup Rust uses: dtolnay/rust-toolchain@master @@ -65,7 +65,7 @@ jobs: run: | export JULIA_DIR="$(dirname $(dirname $(which julia)))" export DYLD_LIBRARY_PATH="${JULIA_DIR}/lib:${JULIA_DIR}/lib/julia:${DYLD_LIBRARY_PATH}" - cargo test --features full,julia-1-8 --verbose + cargo test --features full,julia-1-9 --verbose test-windows-gnu: runs-on: windows-latest @@ -83,7 +83,7 @@ jobs: - name: Setup Julia environment uses: julia-actions/setup-julia@v1 with: - version: '1.8' + version: '1.9' - name: Setup Rust uses: dtolnay/rust-toolchain@master @@ -91,7 +91,7 @@ jobs: toolchain: ${{ matrix.rust }} - name: Run tests - run: cargo test --features full,julia-1-8 --verbose + run: cargo test --features full,julia-1-9 --verbose test-windows-msvc: runs-on: windows-latest @@ -110,7 +110,7 @@ jobs: id: setup-julia uses: julia-actions/setup-julia@v1 with: - version: '1.8' + version: '1.9' - uses: ilammy/msvc-dev-cmd@v1 @@ -120,7 +120,7 @@ jobs: toolchain: ${{ matrix.rust }} - name: Run tests - run: cargo test --features full,julia-1-8 --verbose + run: cargo test --features full,julia-1-9 --verbose test-linux-lts: runs-on: ubuntu-latest @@ -235,7 +235,7 @@ jobs: - name: Setup Julia environment uses: julia-actions/setup-julia@v1 with: - version: '1.8' + version: '1.9' - name: Setup Rust uses: dtolnay/rust-toolchain@master @@ -251,7 +251,7 @@ jobs: - name: Run module tests run: | cd julia_module_test - cargo build --features julia-1-8 + cargo build --features julia-1-9 cp ./target/debug/libjulia_module_test.so . julia JuliaModuleTest.jl @@ -265,7 +265,7 @@ jobs: - name: Setup Julia environment uses: julia-actions/setup-julia@v1 with: - version: '1.8' + version: '1.9' - name: Setup Rust uses: dtolnay/rust-toolchain@master @@ -275,7 +275,7 @@ jobs: - name: Run module tests run: | cd julia_module_test - cargo build --features julia-1-8 + cargo build --features julia-1-9 cp ./target/debug/julia_module_test.* libjulia_module_test.dll julia JuliaModuleTest.jl @@ -288,7 +288,7 @@ jobs: - name: Setup Julia environment uses: julia-actions/setup-julia@v1 with: - version: '1.8' + version: '1.9' - name: Setup Rust uses: dtolnay/rust-toolchain@master @@ -300,7 +300,7 @@ jobs: export JULIA_DIR="$(dirname $(dirname $(which julia)))" export DYLD_LIBRARY_PATH="${JULIA_DIR}/lib:${JULIA_DIR}/lib/julia:${DYLD_LIBRARY_PATH}" cd julia_module_test - cargo build --features julia-1-8 + cargo build --features julia-1-9 cp ./target/debug/libjulia_module_test.* . julia JuliaModuleTest.jl diff --git a/README.md b/README.md index f9ec5141..19705665 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,8 @@ jlrs is a crate that provides access to most of the Julia C API, it can be used to embed Julia in Rust applications and to use functionality it provides when writing `ccall`able -functions in Rust. Currently this crate is only tested in combination with Julia 1.6 and 1.8, -but also supports Julia 1.7 and 1.9. Using the current stable version is highly recommended. +functions in Rust. Currently this crate is only tested in combination with Julia 1.6 and 1.9, +but also supports Julia 1.7 and 1.8. Using the current stable version is highly recommended. The minimum supported Rust version is currently 1.65. The documentation assumes you're already familiar with the Julia and Rust programming @@ -227,11 +227,11 @@ enabling the `full` feature. If you want to embed Julia in a Rust application, you must enable a runtime and a version feature: -`jlrs = {version = "0.18.0-beta.4", features = ["sync-rt", "julia-1-8"]}` +`jlrs = {version = "0.18.0-beta.5", features = ["sync-rt", "julia-1-8"]}` -`jlrs = {version = "0.18.0-beta.4", features = ["tokio-rt", "julia-1-8"]}` +`jlrs = {version = "0.18.0-beta.5", features = ["tokio-rt", "julia-1-8"]}` -`jlrs = {version = "0.18.0-beta.4", features = ["async-std-rt", "julia-1-8"]}` +`jlrs = {version = "0.18.0-beta.5", features = ["async-std-rt", "julia-1-8"]}` When Julia is embedded in an application, it must be initialized before it can be used. The following snippet initializes the sync runtime: diff --git a/examples/Cargo.toml b/examples/Cargo.toml index d8019461..5d8b7d62 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -5,7 +5,7 @@ publish = false edition = "2018" [dev-dependencies] -jlrs = { version = "0.18.0-beta.4", path = "../jlrs", features = ["full"] } +jlrs = { version = "0.18.0-beta.5", path = "../jlrs", features = ["full"] } crossbeam-channel = "0.5" async-std = { version = "1", features = ["unstable", "attributes"] } tokio = { version = "1", features = ["macros", "rt-multi-thread"]} diff --git a/jl_sys/Cargo.toml b/jl_sys/Cargo.toml index a01f668b..22a48641 100644 --- a/jl_sys/Cargo.toml +++ b/jl_sys/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "jl-sys" -version = "0.20.2" +version = "0.21.0" authors = ["Thomas van Doornmalen "] description = """ jl-sys contains the generated bindings for the Julia C API used by jlrs. diff --git a/jl_sys/build.rs b/jl_sys/build.rs index af30c0a7..40364375 100644 --- a/jl_sys/build.rs +++ b/jl_sys/build.rs @@ -480,6 +480,7 @@ fn generate_bindings(julia_dir: &str) { .allowlist_function("jl_yield") .allowlist_function("jlrs_catch_wrapper") .allowlist_function("jlrs_lock") + .allowlist_function("jlrs_typeof") .allowlist_function("jlrs_unlock") .allowlist_function("jlrs_array_data_owner_offset") .allowlist_function("jlrs_gc_queue_multiroot") diff --git a/jl_sys/generate_bindings.sh b/jl_sys/generate_bindings.sh index 242db8dd..64d16271 100755 --- a/jl_sys/generate_bindings.sh +++ b/jl_sys/generate_bindings.sh @@ -65,6 +65,7 @@ function print_help() { echo "default paths can be overridden with environment variables:" echo "" echo -e "\033[1m Version Default path${spacing}Override\033[0m" + echo " Linux 64-bit 1.9 $HOME/julia-1.9.0 JULIA_1_9_DIR" echo " Linux 64-bit 1.8 $HOME/julia-1.8.5 JULIA_1_8_DIR" echo " Linux 64-bit 1.7 $HOME/julia-1.7.3 JULIA_1_7_DIR" echo " Linux 64-bit 1.6 $HOME/julia-1.6.7 JULIA_1_6_DIR" @@ -79,7 +80,7 @@ function print_help() { echo "When the beta flag is set, the following is expected:" echo "" echo -e "\033[1m Version Default path${spacing}Override\033[0m" - echo " Linux 64-bit 1.9 $HOME/julia-1.9.0-rc3 JULIA_1_9_DIR" + echo " - - -" echo "" echo "" echo "All dependencies must have been installed before running this script. The" @@ -123,31 +124,40 @@ if [ "${NIGHTLY}" = "y" -o "${ALL}" = "y" ]; then fi if [ "${BETA}" = "y" -o "${ALL}" = "y" ]; then - if [ -z "$JULIA_1_9_DIR" ]; then - JULIA_1_9_DIR=${HOME}/julia-1.9.0-rc3 - fi - if [ ! -d "$JULIA_1_9_DIR" ]; then - echo "Error: $JULIA_1_9_DIR does not exist" >&2 - exit 1 - fi - - cargo clean - JULIA_VERSION=$($JULIA_1_9_DIR/bin/julia --version) - JULIA_DIR=$JULIA_1_9_DIR cargo build --features use-bindgen,julia-1-9 - echo "/* generated from $JULIA_VERSION */" > ./src/bindings/bindings_1_9_64.rs - cat ../target/debug/build/jl-sys*/out/bindings.rs >> ./src/bindings/bindings_1_9_64.rs - - cargo clean - JULIA_DIR=$JULIA_1_9_DIR cargo build --features use-bindgen,i686,julia-1-9 --target i686-unknown-linux-gnu - echo "/* generated from $JULIA_VERSION */" > ./src/bindings/bindings_1_9_32.rs - cat ../target/i686-unknown-linux-gnu/debug/build/jl-sys*/out/bindings.rs >> ./src/bindings/bindings_1_9_32.rs - + # if [ -z "$JULIA_BETA_DIR" ]; then + # JULIA_BETA_DIR=${HOME}/julia-1.9.0-rc3 + # fi + # if [ ! -d "$JULIA_BETA_DIR" ]; then + # echo "Error: $JULIA_BETA_DIR does not exist" >&2 + # exit 1 + # fi + + # cargo clean + # JULIA_VERSION=$($JULIA_BETA_DIR/bin/julia --version) + # JULIA_DIR=$JULIA_BETA_DIR cargo build --features use-bindgen,julia-1-9 + # echo "/* generated from $JULIA_VERSION */" > ./src/bindings/bindings_1_9_64.rs + # cat ../target/debug/build/jl-sys*/out/bindings.rs >> ./src/bindings/bindings_1_9_64.rs + + # cargo clean + # JULIA_DIR=$JULIA_BETA_DIR cargo build --features use-bindgen,i686,julia-1-9 --target i686-unknown-linux-gnu + # echo "/* generated from $JULIA_VERSION */" > ./src/bindings/bindings_1_9_32.rs + # cat ../target/i686-unknown-linux-gnu/debug/build/jl-sys*/out/bindings.rs >> ./src/bindings/bindings_1_9_32.rs + + echo "Warning: there is no known beta version. Skipping beta bindings" >&2 if [ "${ALL}" != "y" ]; then - cargo +nightly fmt -- ./src/bindings/bindings_* + # cargo +nightly fmt -- ./src/bindings/bindings_* exit fi fi +if [ -z "$JULIA_1_9_DIR" ]; then + JULIA_1_9_DIR=${HOME}/julia-1.9.0 +fi +if [ ! -d "$JULIA_1_9_DIR" ]; then + echo "Error: $JULIA_1_9_DIR does not exist" >&2 + exit 1 +fi + if [ -z "$JULIA_1_8_DIR" ]; then JULIA_1_8_DIR=${HOME}/julia-1.8.5 fi @@ -205,4 +215,15 @@ JULIA_DIR=$JULIA_1_8_DIR cargo build --features use-bindgen,i686,julia-1-8 --tar echo "/* generated from $JULIA_VERSION */" > ./src/bindings/bindings_1_8_32.rs cat ../target/i686-unknown-linux-gnu/debug/build/jl-sys*/out/bindings.rs >> ./src/bindings/bindings_1_8_32.rs +cargo clean +JULIA_VERSION=$($JULIA_1_9_DIR/bin/julia --version) +JULIA_DIR=$JULIA_1_9_DIR cargo build --features use-bindgen,julia-1-9 +echo "/* generated from $JULIA_VERSION */" > ./src/bindings/bindings_1_9_64.rs +cat ../target/debug/build/jl-sys*/out/bindings.rs >> ./src/bindings/bindings_1_9_64.rs + +cargo clean +JULIA_DIR=$JULIA_1_9_DIR cargo build --features use-bindgen,i686,julia-1-9 --target i686-unknown-linux-gnu +echo "/* generated from $JULIA_VERSION */" > ./src/bindings/bindings_1_9_32.rs +cat ../target/i686-unknown-linux-gnu/debug/build/jl-sys*/out/bindings.rs >> ./src/bindings/bindings_1_9_32.rs + cargo +nightly fmt -- ./src/bindings/bindings_* diff --git a/jl_sys/src/bindings/bindings_1_10_32.rs b/jl_sys/src/bindings/bindings_1_10_32.rs index dd27646f..f10d638e 100644 --- a/jl_sys/src/bindings/bindings_1_10_32.rs +++ b/jl_sys/src/bindings/bindings_1_10_32.rs @@ -1,4 +1,4 @@ -/* generated from julia version 1.10.0-DEV (Commit: 7cf01e57a1 2023-05-06 04:37 UTC) */ +/* generated from julia version 1.10.0-DEV (Commit: 056112e5c2 2023-05-10 16:54 UTC) */ #[repr(C)] #[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct __BindgenBitfieldUnit { @@ -126,21 +126,33 @@ impl _jl_taggedvalue_bits { } } #[inline] - pub fn padding(&self) -> usize { - unsafe { ::std::mem::transmute(self._bitfield_1.get(3usize, 29u8) as u32) } + pub fn unused(&self) -> usize { + unsafe { ::std::mem::transmute(self._bitfield_1.get(3usize, 1u8) as u32) } } #[inline] - pub fn set_padding(&mut self, val: usize) { + pub fn set_unused(&mut self, val: usize) { unsafe { let val: u32 = ::std::mem::transmute(val); - self._bitfield_1.set(3usize, 29u8, val as u64) + self._bitfield_1.set(3usize, 1u8, val as u64) + } + } + #[inline] + pub fn tag(&self) -> usize { + unsafe { ::std::mem::transmute(self._bitfield_1.get(4usize, 28u8) as u32) } + } + #[inline] + pub fn set_tag(&mut self, val: usize) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + self._bitfield_1.set(4usize, 28u8, val as u64) } } #[inline] pub fn new_bitfield_1( gc: usize, in_image: usize, - padding: usize, + unused: usize, + tag: usize, ) -> __BindgenBitfieldUnit<[u8; 4usize]> { let mut __bindgen_bitfield_unit: __BindgenBitfieldUnit<[u8; 4usize]> = Default::default(); __bindgen_bitfield_unit.set(0usize, 2u8, { @@ -151,9 +163,13 @@ impl _jl_taggedvalue_bits { let in_image: u32 = unsafe { ::std::mem::transmute(in_image) }; in_image as u64 }); - __bindgen_bitfield_unit.set(3usize, 29u8, { - let padding: u32 = unsafe { ::std::mem::transmute(padding) }; - padding as u64 + __bindgen_bitfield_unit.set(3usize, 1u8, { + let unused: u32 = unsafe { ::std::mem::transmute(unused) }; + unused as u64 + }); + __bindgen_bitfield_unit.set(4usize, 28u8, { + let tag: u32 = unsafe { ::std::mem::transmute(tag) }; + tag as u64 }); __bindgen_bitfield_unit } @@ -1018,11 +1034,11 @@ impl _jl_datatype_t { } } #[inline] - pub fn padding(&self) -> u16 { + pub fn smalltag(&self) -> u16 { unsafe { ::std::mem::transmute(self._bitfield_1.get(10usize, 6u8) as u16) } } #[inline] - pub fn set_padding(&mut self, val: u16) { + pub fn set_smalltag(&mut self, val: u16) { unsafe { let val: u16 = ::std::mem::transmute(val); self._bitfield_1.set(10usize, 6u8, val as u64) @@ -1040,7 +1056,7 @@ impl _jl_datatype_t { isprimitivetype: u16, ismutationfree: u16, isidentityfree: u16, - padding: u16, + smalltag: u16, ) -> __BindgenBitfieldUnit<[u8; 2usize]> { let mut __bindgen_bitfield_unit: __BindgenBitfieldUnit<[u8; 2usize]> = Default::default(); __bindgen_bitfield_unit.set(0usize, 1u8, { @@ -1085,8 +1101,8 @@ impl _jl_datatype_t { isidentityfree as u64 }); __bindgen_bitfield_unit.set(10usize, 6u8, { - let padding: u16 = unsafe { ::std::mem::transmute(padding) }; - padding as u64 + let smalltag: u16 = unsafe { ::std::mem::transmute(smalltag) }; + smalltag as u64 }); __bindgen_bitfield_unit } @@ -2375,6 +2391,9 @@ extern "C" { extern "C" { pub fn jl_exit_threaded_region(); } +extern "C" { + pub fn jlrs_typeof(v: *mut jl_value_t) -> *mut jl_datatype_t; +} #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct _jl_value_t { diff --git a/jl_sys/src/bindings/bindings_1_10_64.rs b/jl_sys/src/bindings/bindings_1_10_64.rs index e49f6496..96b2cf09 100644 --- a/jl_sys/src/bindings/bindings_1_10_64.rs +++ b/jl_sys/src/bindings/bindings_1_10_64.rs @@ -1,4 +1,4 @@ -/* generated from julia version 1.10.0-DEV (Commit: 7cf01e57a1 2023-05-06 04:37 UTC) */ +/* generated from julia version 1.10.0-DEV (Commit: 056112e5c2 2023-05-10 16:54 UTC) */ #[repr(C)] #[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct __BindgenBitfieldUnit { @@ -133,21 +133,33 @@ impl _jl_taggedvalue_bits { } } #[inline] - pub fn padding(&self) -> usize { - unsafe { ::std::mem::transmute(self._bitfield_1.get(3usize, 61u8) as u64) } + pub fn unused(&self) -> usize { + unsafe { ::std::mem::transmute(self._bitfield_1.get(3usize, 1u8) as u64) } } #[inline] - pub fn set_padding(&mut self, val: usize) { + pub fn set_unused(&mut self, val: usize) { unsafe { let val: u64 = ::std::mem::transmute(val); - self._bitfield_1.set(3usize, 61u8, val as u64) + self._bitfield_1.set(3usize, 1u8, val as u64) + } + } + #[inline] + pub fn tag(&self) -> usize { + unsafe { ::std::mem::transmute(self._bitfield_1.get(4usize, 60u8) as u64) } + } + #[inline] + pub fn set_tag(&mut self, val: usize) { + unsafe { + let val: u64 = ::std::mem::transmute(val); + self._bitfield_1.set(4usize, 60u8, val as u64) } } #[inline] pub fn new_bitfield_1( gc: usize, in_image: usize, - padding: usize, + unused: usize, + tag: usize, ) -> __BindgenBitfieldUnit<[u8; 8usize]> { let mut __bindgen_bitfield_unit: __BindgenBitfieldUnit<[u8; 8usize]> = Default::default(); __bindgen_bitfield_unit.set(0usize, 2u8, { @@ -158,9 +170,13 @@ impl _jl_taggedvalue_bits { let in_image: u64 = unsafe { ::std::mem::transmute(in_image) }; in_image as u64 }); - __bindgen_bitfield_unit.set(3usize, 61u8, { - let padding: u64 = unsafe { ::std::mem::transmute(padding) }; - padding as u64 + __bindgen_bitfield_unit.set(3usize, 1u8, { + let unused: u64 = unsafe { ::std::mem::transmute(unused) }; + unused as u64 + }); + __bindgen_bitfield_unit.set(4usize, 60u8, { + let tag: u64 = unsafe { ::std::mem::transmute(tag) }; + tag as u64 }); __bindgen_bitfield_unit } @@ -1025,11 +1041,11 @@ impl _jl_datatype_t { } } #[inline] - pub fn padding(&self) -> u16 { + pub fn smalltag(&self) -> u16 { unsafe { ::std::mem::transmute(self._bitfield_1.get(10usize, 6u8) as u16) } } #[inline] - pub fn set_padding(&mut self, val: u16) { + pub fn set_smalltag(&mut self, val: u16) { unsafe { let val: u16 = ::std::mem::transmute(val); self._bitfield_1.set(10usize, 6u8, val as u64) @@ -1047,7 +1063,7 @@ impl _jl_datatype_t { isprimitivetype: u16, ismutationfree: u16, isidentityfree: u16, - padding: u16, + smalltag: u16, ) -> __BindgenBitfieldUnit<[u8; 2usize]> { let mut __bindgen_bitfield_unit: __BindgenBitfieldUnit<[u8; 2usize]> = Default::default(); __bindgen_bitfield_unit.set(0usize, 1u8, { @@ -1092,8 +1108,8 @@ impl _jl_datatype_t { isidentityfree as u64 }); __bindgen_bitfield_unit.set(10usize, 6u8, { - let padding: u16 = unsafe { ::std::mem::transmute(padding) }; - padding as u64 + let smalltag: u16 = unsafe { ::std::mem::transmute(smalltag) }; + smalltag as u64 }); __bindgen_bitfield_unit } @@ -4188,6 +4204,9 @@ extern "C" { extern "C" { pub fn jl_exit_threaded_region(); } +extern "C" { + pub fn jlrs_typeof(v: *mut jl_value_t) -> *mut jl_datatype_t; +} #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct _jl_value_t { diff --git a/jl_sys/src/bindings/bindings_1_9_32.rs b/jl_sys/src/bindings/bindings_1_9_32.rs index 59fa65e8..de05f57c 100644 --- a/jl_sys/src/bindings/bindings_1_9_32.rs +++ b/jl_sys/src/bindings/bindings_1_9_32.rs @@ -1,4 +1,4 @@ -/* generated from julia version 1.9.0-rc3 */ +/* generated from julia version 1.9.0 */ #[repr(C)] #[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct __BindgenBitfieldUnit { diff --git a/jl_sys/src/bindings/bindings_1_9_64.rs b/jl_sys/src/bindings/bindings_1_9_64.rs index 40bd65a4..42e5a367 100644 --- a/jl_sys/src/bindings/bindings_1_9_64.rs +++ b/jl_sys/src/bindings/bindings_1_9_64.rs @@ -1,4 +1,4 @@ -/* generated from julia version 1.9.0-rc3 */ +/* generated from julia version 1.9.0 */ #[repr(C)] #[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct __BindgenBitfieldUnit { diff --git a/jl_sys/src/jlrs_cc.c b/jl_sys/src/jlrs_cc.c index 1e03a781..b8803b69 100644 --- a/jl_sys/src/jlrs_cc.c +++ b/jl_sys/src/jlrs_cc.c @@ -117,6 +117,12 @@ extern "C" } #endif +#if !defined(JULIA_1_6) && !defined(JULIA_1_7) && !defined(JULIA_1_8) && !defined(JULIA_1_9) + jl_datatype_t *jlrs_typeof(jl_value_t *v) { + return (jl_datatype_t *)jl_typeof(v); + } +#endif + #ifdef __cplusplus } #endif diff --git a/jl_sys/src/jlrs_cc.h b/jl_sys/src/jlrs_cc.h index 0f4d441b..e711654b 100644 --- a/jl_sys/src/jlrs_cc.h +++ b/jl_sys/src/jlrs_cc.h @@ -255,6 +255,10 @@ struct jlrs_task_t { void jl_enter_threaded_region(void); void jl_exit_threaded_region(void); #endif + +#if !defined(JULIA_1_6) && !defined(JULIA_1_7) && !defined(JULIA_1_8) && !defined(JULIA_1_9) + jl_datatype_t *jlrs_typeof(jl_value_t *v); +#endif #ifdef __cplusplus } #endif diff --git a/jlrs/Cargo.toml b/jlrs/Cargo.toml index f3979f7f..e43f5818 100644 --- a/jlrs/Cargo.toml +++ b/jlrs/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "jlrs" -version = "0.18.0-beta.4" +version = "0.18.0-beta.5" authors = ["Thomas van Doornmalen "] description = """ jlrs provides bindings to the Julia C API that enables Julia code to be called from Rust and more. @@ -98,7 +98,7 @@ docs = ["jl-sys/docs", "full", "julia-1-10"] [dependencies] cfg-if = "1" -jl-sys = { version = "0.20", path = "../jl_sys" } +jl-sys = { version = "0.21", path = "../jl_sys" } jlrs-macros = { version = "0.1", path = "../jlrs_macros" } smallvec = "1" thiserror = "1" @@ -115,7 +115,7 @@ half = { version = "2", optional = true } ndarray = { version = "0.15", optional = true } tokio = { version = "1", optional = true, features = ["rt", "time", "sync"]} deadqueue = { version = "0.2", optional = true, features = ["resizable"]} -futures-concurrency = { version = "7.0", optional = true } +futures-concurrency = { version = "7", optional = true } [dev-dependencies] tokio = { version = "1", features = ["macros", "rt-multi-thread", "rt", "time", "sync"]} diff --git a/jlrs/src/data/managed/mod.rs b/jlrs/src/data/managed/mod.rs index dcb74588..bc08f757 100644 --- a/jlrs/src/data/managed/mod.rs +++ b/jlrs/src/data/managed/mod.rs @@ -316,6 +316,24 @@ pub trait Managed<'scope, 'data>: private::ManagedPriv<'scope, 'data> { Ok(s) } + #[doc(hidden)] + unsafe fn print_error(self) { + let unrooted = Unrooted::new(); + Module::main(&unrooted) + .set_global(&unrooted, "__jlrs_global", self.as_value().assume_owned()) + .unwrap(); + + Value::eval_string( + unrooted, + "println(stderr, sprint(showerror, __jlrs_global))", + ) + .unwrap(); + + Module::main(&unrooted) + .set_global(&unrooted, "__jlrs_global", Value::nothing(&unrooted)) + .unwrap(); + } + /// Convert the data to its display string, i.e. the string that is shown by calling /// `Base.display`, or some default value. fn display_string_or>(self, default: S) -> String { diff --git a/jlrs/src/data/managed/value/mod.rs b/jlrs/src/data/managed/value/mod.rs index 801cd3e1..98537113 100644 --- a/jlrs/src/data/managed/value/mod.rs +++ b/jlrs/src/data/managed/value/mod.rs @@ -123,14 +123,13 @@ use std::{ use jl_sys::jl_pair_type; use jl_sys::{ jl_an_empty_string, jl_an_empty_vec_any, jl_any_type, jl_apply_type, jl_array_any_type, - jl_array_int32_type, jl_array_symbol_type, jl_array_uint8_type, jl_astaggedvalue, - jl_bottom_type, jl_call, jl_call0, jl_call1, jl_call2, jl_call3, jl_diverror_exception, - jl_egal, jl_emptytuple, jl_eval_string, jl_exception_occurred, jl_false, jl_field_index, - jl_field_isptr, jl_gc_add_finalizer, jl_gc_add_ptr_finalizer, jl_get_nth_field, - jl_get_nth_field_noalloc, jl_interrupt_exception, jl_isa, jl_memory_exception, jl_nothing, - jl_object_id, jl_readonlymemory_exception, jl_set_nth_field, jl_stackovf_exception, - jl_stderr_obj, jl_stdout_obj, jl_subtype, jl_true, jl_typeof_str, jl_undefref_exception, - jl_value_t, + jl_array_int32_type, jl_array_symbol_type, jl_array_uint8_type, jl_bottom_type, jl_call, + jl_call0, jl_call1, jl_call2, jl_call3, jl_diverror_exception, jl_egal, jl_emptytuple, + jl_eval_string, jl_exception_occurred, jl_false, jl_field_index, jl_field_isptr, + jl_gc_add_finalizer, jl_gc_add_ptr_finalizer, jl_get_nth_field, jl_get_nth_field_noalloc, + jl_interrupt_exception, jl_isa, jl_memory_exception, jl_nothing, jl_object_id, + jl_readonlymemory_exception, jl_set_nth_field, jl_stackovf_exception, jl_stderr_obj, + jl_stdout_obj, jl_subtype, jl_true, jl_typeof_str, jl_undefref_exception, jl_value_t, }; use jlrs_macros::julia_version; @@ -359,12 +358,13 @@ impl Value<'_, '_> { /// Every value is guaranteed to have a [`DataType`]. This contains all of the value's type /// information. impl<'scope, 'data> Value<'scope, 'data> { + #[julia_version(until = "1.9")] /// Returns the `DataType` of this value. pub fn datatype(self) -> DataType<'scope> { // Safety: the pointer points to valid data, every value can be converted to a tagged // value. unsafe { - let header = NonNull::new_unchecked(jl_astaggedvalue(self.unwrap(Private))) + let header = NonNull::new_unchecked(jl_sys::jl_astaggedvalue(self.unwrap(Private))) .as_ref() .__bindgen_anon_1 .header; @@ -373,6 +373,17 @@ impl<'scope, 'data> Value<'scope, 'data> { } } + #[julia_version(since = "1.10")] + /// Returns the `DataType` of this value. + pub fn datatype(self) -> DataType<'scope> { + // Safety: the pointer points to valid data, every value has a type. + unsafe { + let self_ptr = self.unwrap(Private); + let ty = jl_sys::jlrs_typeof(self_ptr); + DataType::wrap_non_null(NonNull::new_unchecked(ty), Private) + } + } + /// Returns the name of this value's [`DataType`] as a string slice. pub fn datatype_name(self) -> JlrsResult<&'scope str> { // Safety: the pointer points to valid data, the C API function diff --git a/jlrs/src/lib.rs b/jlrs/src/lib.rs index 583ca005..eeac3d6f 100644 --- a/jlrs/src/lib.rs +++ b/jlrs/src/lib.rs @@ -1,7 +1,7 @@ //! jlrs is a crate that provides access to most of the Julia C API, it can be used to embed Julia //! in Rust applications and to use functionality it provides when writing `ccall`able -//! functions in Rust. Currently this crate is only tested in combination with Julia 1.6 and 1.8, -//! but also supports Julia 1.7 and 1.9. Using the current stable version is highly recommended. +//! functions in Rust. Currently this crate is only tested in combination with Julia 1.6 and 1.9, +//! but also supports Julia 1.7 and 1.8. Using the current stable version is highly recommended. //! The minimum supported Rust version is currently 1.65. //! //! The documentation assumes you're already familiar with the Julia and Rust programming @@ -222,11 +222,11 @@ //! If you want to embed Julia in a Rust application, you must enable a runtime and a version //! feature: //! -//! `jlrs = {version = "0.18.0-beta.4", features = ["sync-rt", "julia-1-8"]}` +//! `jlrs = {version = "0.18.0-beta.5", features = ["sync-rt", "julia-1-8"]}` //! -//! `jlrs = {version = "0.18.0-beta.4", features = ["tokio-rt", "julia-1-8"]}` +//! `jlrs = {version = "0.18.0-beta.5", features = ["tokio-rt", "julia-1-8"]}` //! -//! `jlrs = {version = "0.18.0-beta.4", features = ["async-std-rt", "julia-1-8"]}` +//! `jlrs = {version = "0.18.0-beta.5", features = ["async-std-rt", "julia-1-8"]}` //! //! When Julia is embedded in an application, it must be initialized before it can be used. The //! following snippet initializes the sync runtime: @@ -783,7 +783,7 @@ use crate::{ context::{ledger::init_ledger, stack::Stack}, stack_frame::PinnedFrame, target::unrooted::Unrooted, - }, error::CANNOT_DISPLAY_VALUE, + }, }; #[cfg(feature = "pyplot")] @@ -915,8 +915,11 @@ impl InstallJlrsCore { }; if let Err(err) = res { - let err = err.as_value().error_string_or(CANNOT_DISPLAY_VALUE); - panic!("Failed to load or install JlrsCore package: {}", err); + eprintln!("Failed to load or install JlrsCore package"); + // JlrsCore failed to load, print the error message to stderr without using + // `Managed::error_string_or`. + err.as_value().print_error(); + panic!(); } } } diff --git a/jlrs/tests/eval_string.rs b/jlrs/tests/eval_string.rs index a5ecd008..88cf95c1 100644 --- a/jlrs/tests/eval_string.rs +++ b/jlrs/tests/eval_string.rs @@ -63,11 +63,30 @@ mod tests { }); } + fn print_error() { + JULIA.with(|j| { + let mut frame = StackFrame::new(); + let mut jlrs = j.borrow_mut(); + jlrs.instance(&mut frame) + .scope(|mut frame| unsafe { + Value::eval_string( + &mut frame, + "ErrorException(\"This is an expected message\")", + ) + .unwrap() + .print_error(); + Ok(()) + }) + .unwrap(); + }); + } + #[test] fn eval_string_tests() { basic_math(); runtime_error(); syntax_error(); define_then_use(); + print_error(); } }