From 79de37e47181aef23c6089dbe18ae3e3b4cad3ef Mon Sep 17 00:00:00 2001 From: Thomas van Doornmalen Date: Fri, 5 Jun 2026 21:09:40 +0200 Subject: [PATCH] Improve version detection and handling, support TypeEq in Julia 1.14 --- CHANGELOG.md | 6 + crates/build_utils/find_julia/Cargo.toml | 2 +- crates/build_utils/find_julia/src/lib.rs | 113 +++++++++++++++--- crates/build_utils/jlrs_compat/Cargo.toml | 4 +- crates/build_utils/jlrs_compat/src/lib.rs | 14 ++- crates/ffi/jl_sys/Cargo.toml | 6 +- crates/ffi/jl_sys/build.rs | 11 +- crates/ffi/jl_sys/src/bindings.rs | 3 + crates/ffi/jl_sys/src/types.rs | 7 ++ crates/ffi/jlrs_sys/Cargo.toml | 6 +- crates/ffi/jlrs_sys/build.rs | 8 +- crates/ffi/jlrs_sys/src/bindings.rs | 3 + crates/ffi/jlrs_sys/src/jlrs_cc/jlrs_cc_ext.c | 6 + crates/ffi/jlrs_sys/src/jlrs_cc/jlrs_cc_ext.h | 4 + .../ffi/jlrs_sys/src/jlrs_cc/jlrs_cc_hacks.h | 4 +- crates/jlrs/Cargo.toml | 8 +- crates/jlrs/build.rs | 8 +- crates/jlrs/src/data/managed/mod.rs | 2 + crates/jlrs/src/data/managed/type_eq.rs | 63 ++++++++++ crates/jlrs/tests/typecheck.rs | 19 +++ crates/jlrs_macros/Cargo.toml | 6 +- crates/jlrs_macros/build.rs | 28 ++--- crates/jlrs_macros/src/version.rs | 43 ++----- examples/Cargo.toml | 2 +- 24 files changed, 279 insertions(+), 97 deletions(-) create mode 100644 crates/jlrs/src/data/managed/type_eq.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 60123706..02badeb2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## v0.24 + +- Handle version compatibility solely through jlrs-compat. + +- Support `TypeEq` in Julia 1.14. + ## v0.23 - Implement `Clone` for `Tracked`. Note that this will break your code if the tracked type implements `Clone`, and the tracked handle was used to clone the data; this will now return a cloned handle, instead of the cloned underlying type. diff --git a/crates/build_utils/find_julia/Cargo.toml b/crates/build_utils/find_julia/Cargo.toml index fd1d5c97..eb3ae363 100644 --- a/crates/build_utils/find_julia/Cargo.toml +++ b/crates/build_utils/find_julia/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "find-julia" -version = "0.1.1" +version = "0.2.0" authors = ["Thomas van Doornmalen "] description = """ Finds the installed version of Julia through environment variables diff --git a/crates/build_utils/find_julia/src/lib.rs b/crates/build_utils/find_julia/src/lib.rs index 321e8032..f61e5bdf 100644 --- a/crates/build_utils/find_julia/src/lib.rs +++ b/crates/build_utils/find_julia/src/lib.rs @@ -2,7 +2,13 @@ #[cfg(target_os = "windows")] use std::str::FromStr; -use std::{env, io::Read, path::PathBuf, process::Command}; +use std::{ + env, + fs::File, + io::{Read, Write}, + path::{Path, PathBuf}, + process::Command, +}; /// Detected Julia version #[derive(Clone)] @@ -126,7 +132,13 @@ impl Version { } } - fn emit_metadata(&self, min_minor_version: u32, max_minor_version: u32) { + fn emit_metadata( + &self, + min_minor_version: u32, + max_minor_version: u32, + nightly_minor_version: u32, + warn: bool, + ) { let major = self.major(); let minor = self.minor(); let patch = self.patch(); @@ -136,19 +148,49 @@ impl Version { } if self.is_dev() { - println!( - "cargo::warning=Detected development version of Julia {major}.{minor}.{patch}, \ - bindings may not be up-to-date. Please report any issues you encounter at \ - https://www.github.com/Taaitaaiger/jlrs/issues" - ); + if warn { + println!( + "cargo::warning=Detected development version of Julia {major}.{minor}.{patch}, \ + bindings may not be up-to-date. Please report any issues you encounter at \ + https://www.github.com/Taaitaaiger/jlrs/issues" + ); + } } - if minor > max_minor_version { - println!( - "cargo::warning=Detected unsupported version of Julia {major}.{minor}.{patch}, \ - assuming compatibility with 1.{max_minor_version}. Please report any issues you \ - encounter at https://www.github.com/Taaitaaiger/jlrs/issues" - ); + if minor > nightly_minor_version { + if warn { + println!( + "cargo::warning=Detected too recent version of Julia {major}.{minor}.{patch}, \ + assuming compatibility with 1.{nightly_minor_version}. Please report any issues you \ + encounter at https://www.github.com/Taaitaaiger/jlrs/issues" + ); + } + + let mut version = self.clone(); + version.minor = nightly_minor_version; + version.patch = 0; + version.emit_metadata_unchecked(); + } else if minor == nightly_minor_version { + if warn { + println!( + "cargo::warning=Detected nightly version of Julia {major}.{minor}.{patch}. \ + Please report any issues you encounter at \ + https://www.github.com/Taaitaaiger/jlrs/issues" + ); + } + + let mut version = self.clone(); + version.minor = nightly_minor_version; + version.patch = 0; + version.emit_metadata_unchecked(); + } else if minor > max_minor_version { + if warn { + println!( + "cargo::warning=Detected unsupported version of Julia {major}.{minor}.{patch}, \ + assuming compatibility with 1.{max_minor_version}. Please report any issues you \ + encounter at https://www.github.com/Taaitaaiger/jlrs/issues" + ); + } let mut version = self.clone(); version.minor = max_minor_version; @@ -206,6 +248,16 @@ impl JuliaDir { } } + pub fn docs(stable_major: u32, stable_minor: u32) -> Self { + JuliaDir { + is_binary_builder: false, + windows: false, + path: PathBuf::new(), + version: Version::new(stable_major, stable_minor, 0, false), + debug: false, + } + } + /// The version of this Julia installation pub fn version(&self) -> Version { self.version.clone() @@ -258,7 +310,13 @@ impl JuliaDir { } /// Emit detected Julia installation metadata. - pub fn emit_metadata(&self, min_minor_version: u32, max_minor_version: u32) { + pub fn emit_metadata( + &self, + min_minor_version: u32, + max_minor_version: u32, + nightly_minor_version: u32, + warn: bool, + ) { println!("cargo::metadata=julia_dir={}", self.path.display()); let is_debug = if self.debug { 1 } else { 0 }; @@ -267,8 +325,12 @@ impl JuliaDir { let is_windows = if self.windows { 1 } else { 0 }; println!("cargo::metadata=windows={}", is_windows); - self.version - .emit_metadata(min_minor_version, max_minor_version); + self.version.emit_metadata( + min_minor_version, + max_minor_version, + nightly_minor_version, + warn, + ); } /// Load the installation detected when jl-sys was built. @@ -297,6 +359,25 @@ impl JuliaDir { }) } } + + pub fn write_version_file( + &self, + path: &Path, + lts_version: u32, + nightly_minor_version: u32, + ) -> std::io::Result<()> { + let mut output = File::create(path)?; + write!( + output, + "const MAJOR_VERSION: usize = 1; +const MIN_MINOR_VERSION: usize = {}; +const NIGHTLY_MINOR_VERSION: usize = {}; +const SELECTED_MINOR_VERSION: usize = {};", + lts_version, nightly_minor_version, self.version.minor + )?; + + Ok(()) + } } /// Enable the `julia_1_x` version configs from `min_version..=max_version`. diff --git a/crates/build_utils/jlrs_compat/Cargo.toml b/crates/build_utils/jlrs_compat/Cargo.toml index d905ced6..00362ee4 100644 --- a/crates/build_utils/jlrs_compat/Cargo.toml +++ b/crates/build_utils/jlrs_compat/Cargo.toml @@ -1,9 +1,9 @@ [package] name = "jlrs-compat" -version = "0.1.0" +version = "0.2.0" authors = ["Thomas van Doornmalen "] description = """ -Defines compatible and stable versions of Julia supporte by jlrs +Defines compatible and stable versions of Julia supported by jlrs """ documentation = "https://docs.rs/jlrs" homepage = "https://github.com/Taaitaaiger/jlrs" diff --git a/crates/build_utils/jlrs_compat/src/lib.rs b/crates/build_utils/jlrs_compat/src/lib.rs index 938e96f7..5e596c8f 100644 --- a/crates/build_utils/jlrs_compat/src/lib.rs +++ b/crates/build_utils/jlrs_compat/src/lib.rs @@ -2,14 +2,20 @@ //! //! NB: jlrs docs are currently always built for the stable version. +/// Current stable Julia major version +pub const MAJOR_VERSION: u32 = 1; + /// Minimum supported Julia minor version pub const MIN_MINOR_VERSION: u32 = 10; /// Maximum supported Julia minor version pub const MAX_MINOR_VERSION: u32 = 13; -/// Current stable Julia major version -pub const STABLE_MAJOR_VERSION: u32 = 1; +/// Nightly Julia minor version +/// +/// This value is set to `Some(x)` if version 1.x has incompatible changes with respect to +/// 1.`MAX_MINOR_VERSION` +pub const NIGHTLY_MINOR_VERSION: u32 = MAX_MINOR_VERSION + 1; -/// Current stable Julia minor version -pub const STABLE_MINOR_VERSION: u32 = 11; +/// Julia minor version when building documentation for docs.rs +pub const DOCS_MINOR_VERSION: u32 = 12; diff --git a/crates/ffi/jl_sys/Cargo.toml b/crates/ffi/jl_sys/Cargo.toml index 3926c0a2..138bec06 100644 --- a/crates/ffi/jl_sys/Cargo.toml +++ b/crates/ffi/jl_sys/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "jl-sys" -version = "0.27.0" +version = "0.28.0" authors = ["Thomas van Doornmalen "] description = """ jl-sys contains the generated bindings for the Julia C API used by jlrs. @@ -25,8 +25,8 @@ docs = [] [build-dependencies] cc = "1" cfg-if = "1" -find-julia = { path = "../../build_utils/find_julia", version = "0.1" } -jlrs-compat = { path = "../../build_utils/jlrs_compat", version = "0.1" } +find-julia = { path = "../../build_utils/find_julia", version = "0.2" } +jlrs-compat = { path = "../../build_utils/jlrs_compat", version = "0.2" } [package.metadata.docs.rs] features = ["docs"] diff --git a/crates/ffi/jl_sys/build.rs b/crates/ffi/jl_sys/build.rs index 4a806cd4..5f976bf7 100644 --- a/crates/ffi/jl_sys/build.rs +++ b/crates/ffi/jl_sys/build.rs @@ -10,11 +10,11 @@ fn main() { println!("cargo::rerun-if-env-changed=JLRS_JULIA_DIR"); // Enable julia_1_x configs - enable_version_cfgs(MIN_MINOR_VERSION, MAX_MINOR_VERSION); + enable_version_cfgs(MIN_MINOR_VERSION, NIGHTLY_MINOR_VERSION); if building_docs() { // Don't link Julia when building the docs - let version = Version::new(STABLE_MAJOR_VERSION, STABLE_MINOR_VERSION, 0, false); + let version = Version::new(MAJOR_VERSION, DOCS_MINOR_VERSION, 0, false); version.emit_metadata_unchecked(); } else { // Detect active version of Julia, emit metadata, and link Julia. @@ -26,7 +26,12 @@ fn main() { let julia_dir = JuliaDir::find(windows_build(), false) .expect("JLRS_JULIA_DIR is not set and no installed version of Julia can be found"); - julia_dir.emit_metadata(MIN_MINOR_VERSION, MAX_MINOR_VERSION); + julia_dir.emit_metadata( + MIN_MINOR_VERSION, + MAX_MINOR_VERSION, + NIGHTLY_MINOR_VERSION, + true, + ); julia_dir.link(); } } diff --git a/crates/ffi/jl_sys/src/bindings.rs b/crates/ffi/jl_sys/src/bindings.rs index 227cdcab..a4cde9b4 100644 --- a/crates/ffi/jl_sys/src/bindings.rs +++ b/crates/ffi/jl_sys/src/bindings.rs @@ -216,6 +216,9 @@ pub mod globals { #[cfg(any(julia_1_10, julia_1_11))] pub static mut jl_kwcall_func: *mut crate::types::jl_value_t; + // Added in Julia 1.14 + #[cfg(not(any(julia_1_10, julia_1_11, julia_1_12, julia_1_13)))] + pub static mut jl_typeeq_type: *mut crate::types::jl_datatype_t; } } diff --git a/crates/ffi/jl_sys/src/types.rs b/crates/ffi/jl_sys/src/types.rs index 08cfd846..f49dc3ec 100644 --- a/crates/ffi/jl_sys/src/types.rs +++ b/crates/ffi/jl_sys/src/types.rs @@ -178,3 +178,10 @@ pub struct jl_binding_t { _unused: [u8; 0], _marker: PhantomData<(*mut u8, PhantomPinned)>, } + +#[repr(C)] +#[derive(Copy, Clone, Debug)] +pub struct jl_typeeq_t { + _unused: [u8; 0], + _marker: PhantomData<(*mut u8, PhantomPinned)>, +} diff --git a/crates/ffi/jlrs_sys/Cargo.toml b/crates/ffi/jlrs_sys/Cargo.toml index fac84faf..846b41da 100644 --- a/crates/ffi/jlrs_sys/Cargo.toml +++ b/crates/ffi/jlrs_sys/Cargo.toml @@ -26,11 +26,11 @@ windows = [] docs = [] [dependencies] -jl-sys = { path = "../jl_sys", version = "0.27"} +jl-sys = { path = "../jl_sys", version = "0.28"} [build-dependencies] -find-julia = { path = "../../build_utils/find_julia", version = "0.1" } -jlrs-compat = { path = "../../build_utils/jlrs_compat", version = "0.1" } +find-julia = { path = "../../build_utils/find_julia", version = "0.2" } +jlrs-compat = { path = "../../build_utils/jlrs_compat", version = "0.2" } cc = "1" cfg-if = "1" diff --git a/crates/ffi/jlrs_sys/build.rs b/crates/ffi/jlrs_sys/build.rs index 689dc449..6343382e 100644 --- a/crates/ffi/jlrs_sys/build.rs +++ b/crates/ffi/jlrs_sys/build.rs @@ -2,16 +2,14 @@ use std::env; use cfg_if::cfg_if; use find_julia::{JuliaDir, Version, enable_version_cfgs}; -use jlrs_compat::{ - MAX_MINOR_VERSION, MIN_MINOR_VERSION, STABLE_MAJOR_VERSION, STABLE_MINOR_VERSION, -}; +use jlrs_compat::{DOCS_MINOR_VERSION, MAJOR_VERSION, MIN_MINOR_VERSION, NIGHTLY_MINOR_VERSION}; fn main() { // Enable julia_1_x configs - enable_version_cfgs(MIN_MINOR_VERSION, MAX_MINOR_VERSION); + enable_version_cfgs(MIN_MINOR_VERSION, NIGHTLY_MINOR_VERSION); if building_docs() { - let version = Version::new(STABLE_MAJOR_VERSION, STABLE_MINOR_VERSION, 0, false); + let version = Version::new(MAJOR_VERSION, DOCS_MINOR_VERSION, 0, false); version.emit_metadata_unchecked(); return; } diff --git a/crates/ffi/jlrs_sys/src/bindings.rs b/crates/ffi/jlrs_sys/src/bindings.rs index 78b79faa..325a11dc 100644 --- a/crates/ffi/jlrs_sys/src/bindings.rs +++ b/crates/ffi/jlrs_sys/src/bindings.rs @@ -263,5 +263,8 @@ pub mod jlrs_cc { symbol: *const std::ffi::c_char, value: *mut *mut std::ffi::c_void, ) -> std::ffi::c_int; + + #[cfg(not(any(julia_1_10, julia_1_11, julia_1_12, julia_1_13)))] + pub fn jlrs_typeeq_T(v: *mut crate::types::jl_typeeq_t) -> *mut crate::types::jl_value_t; } } diff --git a/crates/ffi/jlrs_sys/src/jlrs_cc/jlrs_cc_ext.c b/crates/ffi/jlrs_sys/src/jlrs_cc/jlrs_cc_ext.c index f21ce884..f5e4aa24 100644 --- a/crates/ffi/jlrs_sys/src/jlrs_cc/jlrs_cc_ext.c +++ b/crates/ffi/jlrs_sys/src/jlrs_cc/jlrs_cc_ext.c @@ -398,6 +398,12 @@ extern "C" return (int)a->flags.how; #endif } + +#if JULIA_VERSION_MINOR >= 14 + jl_value_t *jlrs_typeeq_T(jl_typeeq_t *v) { + return v->T; + } +#endif #ifdef __cplusplus } #endif \ No newline at end of file diff --git a/crates/ffi/jlrs_sys/src/jlrs_cc/jlrs_cc_ext.h b/crates/ffi/jlrs_sys/src/jlrs_cc/jlrs_cc_ext.h index 3a34762b..a3d2bd46 100644 --- a/crates/ffi/jlrs_sys/src/jlrs_cc/jlrs_cc_ext.h +++ b/crates/ffi/jlrs_sys/src/jlrs_cc/jlrs_cc_ext.h @@ -124,6 +124,10 @@ extern "C" const jl_datatype_layout_t *jl_datatype_layout(jl_datatype_t *t); #endif +#if JULIA_VERSION_MINOR >= 14 + jl_value_t *jlrs_typeeq_T(jl_typeeq_t *v); +#endif + #ifdef __cplusplus } #endif // __cplusplus diff --git a/crates/ffi/jlrs_sys/src/jlrs_cc/jlrs_cc_hacks.h b/crates/ffi/jlrs_sys/src/jlrs_cc/jlrs_cc_hacks.h index 65176a72..70b97075 100644 --- a/crates/ffi/jlrs_sys/src/jlrs_cc/jlrs_cc_hacks.h +++ b/crates/ffi/jlrs_sys/src/jlrs_cc/jlrs_cc_hacks.h @@ -21,8 +21,8 @@ extern "C" void jlrs_unlock_value(jl_value_t *v); #if JULIA_VERSION_MINOR >= 11 - jl_genericmemoryref_t jlrs_memoryrefindex(jl_genericmemoryref_t m JL_ROOTING_ARGUMENT, size_t idx); - void jlrs_memoryrefset(jl_genericmemoryref_t m JL_ROOTING_ARGUMENT, jl_value_t *rhs JL_ROOTED_ARGUMENT JL_MAYBE_UNROOTED, int isatomic); + jl_genericmemoryref_t jlrs_memoryrefindex(jl_genericmemoryref_t m, size_t idx); + void jlrs_memoryrefset(jl_genericmemoryref_t m, jl_value_t *rhs, int isatomic); char *jlrs_genericmemory_typetagdata(jl_genericmemory_t *m); #endif diff --git a/crates/jlrs/Cargo.toml b/crates/jlrs/Cargo.toml index 2ffcfd34..88b4ea5e 100644 --- a/crates/jlrs/Cargo.toml +++ b/crates/jlrs/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "jlrs" -version = "0.23.0" +version = "0.24.0" authors = ["Thomas van Doornmalen "] description = """ jlrs provides bindings to the Julia C API that enable Julia code to be called from Rust and more. @@ -73,7 +73,7 @@ macos = ["jlrs-sys/macos"] docs = ["jl-sys/docs", "jlrs-sys/docs", "jlrs-macros/docs", "full"] [dependencies] -jl-sys = { version = "0.27", path = "../ffi/jl_sys" } +jl-sys = { version = "0.28", path = "../ffi/jl_sys" } jlrs-sys = { version = "0.2", path = "../ffi/jlrs_sys" } jlrs-macros = { version = "0.6", path = "../jlrs_macros" } smallvec = {version = "1", features = ["const_generics"]} @@ -96,8 +96,8 @@ num-complex = { version = "0.4", optional = true } tokio = { version = "1", features = ["rt", "time", "sync"]} [build-dependencies] -jlrs-compat = { path = "../build_utils/jlrs_compat", version = "0.1"} -find-julia = { path = "../build_utils/find_julia", version = "0.1"} +jlrs-compat = { path = "../build_utils/jlrs_compat", version = "0.2"} +find-julia = { path = "../build_utils/find_julia", version = "0.2"} [package.metadata.docs.rs] features = ["docs"] diff --git a/crates/jlrs/build.rs b/crates/jlrs/build.rs index 54adf711..7291ac15 100644 --- a/crates/jlrs/build.rs +++ b/crates/jlrs/build.rs @@ -1,15 +1,13 @@ use std::env; use find_julia::{JuliaDir, Version, enable_version_cfgs}; -use jlrs_compat::{ - MAX_MINOR_VERSION, MIN_MINOR_VERSION, STABLE_MAJOR_VERSION, STABLE_MINOR_VERSION, -}; +use jlrs_compat::{DOCS_MINOR_VERSION, MAJOR_VERSION, MIN_MINOR_VERSION, NIGHTLY_MINOR_VERSION}; fn main() { - enable_version_cfgs(MIN_MINOR_VERSION, MAX_MINOR_VERSION); + enable_version_cfgs(MIN_MINOR_VERSION, NIGHTLY_MINOR_VERSION); if building_docs() { - let version = Version::new(STABLE_MAJOR_VERSION, STABLE_MINOR_VERSION, 0, false); + let version = Version::new(MAJOR_VERSION, DOCS_MINOR_VERSION, 0, false); version.emit_metadata_unchecked(); return; } diff --git a/crates/jlrs/src/data/managed/mod.rs b/crates/jlrs/src/data/managed/mod.rs index 074926a6..773127bc 100644 --- a/crates/jlrs/src/data/managed/mod.rs +++ b/crates/jlrs/src/data/managed/mod.rs @@ -297,6 +297,8 @@ pub mod parachute; pub mod simple_vector; pub mod string; pub mod symbol; +#[cfg(not(any(julia_1_10, julia_1_11, julia_1_12, julia_1_13)))] +pub mod type_eq; pub mod type_name; pub mod type_var; pub mod union; diff --git a/crates/jlrs/src/data/managed/type_eq.rs b/crates/jlrs/src/data/managed/type_eq.rs new file mode 100644 index 00000000..8b2a32bc --- /dev/null +++ b/crates/jlrs/src/data/managed/type_eq.rs @@ -0,0 +1,63 @@ +use std::{marker::PhantomData, ptr::NonNull}; + +use jl_sys::{jl_typeeq_t, jl_typeeq_type}; +use jlrs_sys::jlrs_typeeq_T; + +use crate::{ + data::managed::{Weak, private::ManagedPriv, value::Value}, + impl_julia_typecheck, + memory::target::{TargetResult, TargetType}, + private::Private, +}; + +#[derive(Copy, Clone)] +#[repr(transparent)] +pub struct TypeEq<'scope>(NonNull, PhantomData<&'scope ()>); + +impl<'scope> TypeEq<'scope> { + pub fn t(self) -> Value<'scope, 'static> { + unsafe { + let v = jlrs_typeeq_T(self.unwrap(Private)); + debug_assert!(!v.is_null()); + Value::wrap_non_null(NonNull::new_unchecked(v), Private) + } + } +} + +impl<'scope> ManagedPriv<'scope, '_> for TypeEq<'scope> { + type Wraps = jl_typeeq_t; + type WithLifetimes<'target, 'da> = TypeEq<'target>; + const NAME: &'static str = "TypeEq"; + + // Safety: `inner` must not have been freed yet, the result must never be + // used after the GC might have freed it. + #[inline] + unsafe fn wrap_non_null(inner: NonNull, _: Private) -> Self { + Self(inner, PhantomData) + } + + #[inline] + fn unwrap_non_null(self, _: Private) -> NonNull { + self.0 + } +} + +/// A [`TypeEq`] that has not been explicitly rooted. +pub type WeakTypeEq<'scope> = Weak<'scope, 'static, TypeEq<'scope>>; + +/// A [`WeakTypeEq`] with static lifetimes. This is a useful shorthand for signatures of +/// `ccall`able functions that return a [`TypeEq`]. +pub type TypeEqRet = WeakTypeEq<'static>; + +/// `TypeEq` or `WeakTypeEq`, depending on the target type `Tgt`. +pub type TypeEqData<'target, Tgt> = >::Data<'static, TypeEq<'target>>; + +/// `JuliaResult` or `WeakJuliaResult`, depending on the target type `Tgt`. +pub type TypeEqResult<'target, Tgt> = TargetResult<'target, 'static, TypeEq<'target>, Tgt>; + +impl_julia_typecheck!(TypeEq<'scope>, jl_typeeq_type, 'scope); +impl_debug!(TypeEq<'_>); +impl_construct_type_managed!(TypeEq, 1, jl_typeeq_type); +impl_valid_layout!(WeakTypeEq, TypeEq, jl_typeeq_type); +impl_ccall_arg_managed!(TypeEq, 1); +impl_into_typed!(TypeEq); diff --git a/crates/jlrs/tests/typecheck.rs b/crates/jlrs/tests/typecheck.rs index f884ec08..6c557515 100644 --- a/crates/jlrs/tests/typecheck.rs +++ b/crates/jlrs/tests/typecheck.rs @@ -4,6 +4,8 @@ mod util; mod tests { use std::{ffi::c_void, ptr::null_mut}; + #[cfg(not(any(julia_1_10, julia_1_11, julia_1_12, julia_1_13)))] + use jlrs::data::managed::type_eq::TypeEq; use jlrs::{ data::{ managed::{named_tuple::NamedTuple, union_all::UnionAll}, @@ -225,6 +227,23 @@ mod tests { }) } + #[cfg(not(any(julia_1_10, julia_1_11, julia_1_12, julia_1_13)))] + fn type_type_typecheck() { + JULIA.with(|handle| { + handle.borrow_mut().with_stack(|mut stack| { + stack.scope(|mut frame| unsafe { + let args = [DataType::uint8_type(&frame).as_value()]; + let _ty = UnionAll::type_type(&frame) + .as_value() + .apply_type_unchecked(&mut frame, args) + .cast::() + .unwrap(); + }) + }) + }) + } + + #[cfg(any(julia_1_10, julia_1_11, julia_1_12, julia_1_13))] fn type_type_typecheck() { JULIA.with(|handle| { handle.borrow_mut().with_stack(|mut stack| { diff --git a/crates/jlrs_macros/Cargo.toml b/crates/jlrs_macros/Cargo.toml index 4785d414..254d48e4 100644 --- a/crates/jlrs_macros/Cargo.toml +++ b/crates/jlrs_macros/Cargo.toml @@ -30,11 +30,11 @@ proc-macro2 = { version = "1", optional = true } syn = { version = "2", features = ["full", "extra-traits", "printing"] } quote = { version = "1" } itertools = "0.14" -jl-sys = { path = "../ffi/jl_sys", version = "0.27"} +jl-sys = { path = "../ffi/jl_sys", version = "0.28"} [build-dependencies] -jlrs-compat = { path = "../build_utils/jlrs_compat", version = "0.1"} -find-julia = { path = "../build_utils/find_julia", version = "0.1"} +jlrs-compat = { path = "../build_utils/jlrs_compat", version = "0.2"} +find-julia = { path = "../build_utils/find_julia", version = "0.2"} [package.metadata.docs.rs] features = ["ccall", "derive"] diff --git a/crates/jlrs_macros/build.rs b/crates/jlrs_macros/build.rs index 56ece8e2..9a9ebd62 100644 --- a/crates/jlrs_macros/build.rs +++ b/crates/jlrs_macros/build.rs @@ -1,24 +1,22 @@ -use std::env; +use std::{env, path::PathBuf}; use find_julia::{JuliaDir, enable_version_cfgs}; -use jlrs_compat::{ - MAX_MINOR_VERSION, MIN_MINOR_VERSION, STABLE_MAJOR_VERSION, STABLE_MINOR_VERSION, -}; +use jlrs_compat::{DOCS_MINOR_VERSION, MAJOR_VERSION, MIN_MINOR_VERSION, NIGHTLY_MINOR_VERSION}; fn main() { - enable_version_cfgs(MIN_MINOR_VERSION, MAX_MINOR_VERSION); + enable_version_cfgs(MIN_MINOR_VERSION, NIGHTLY_MINOR_VERSION); - if building_docs() { - let version = - find_julia::Version::new(STABLE_MAJOR_VERSION, STABLE_MINOR_VERSION, 0, false); - version.emit_metadata_unchecked(); - return; - } + let julia_dir = if building_docs() { + JuliaDir::docs(MAJOR_VERSION, DOCS_MINOR_VERSION) + } else { + JuliaDir::from_detected().expect("Julia not detected by jl-sys") + }; - JuliaDir::from_detected() - .expect("Julia not detected by jl-sys") - .version() - .emit_metadata_unchecked(); + let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()).join("version.rs"); + julia_dir + .write_version_file(&out_path, MIN_MINOR_VERSION, NIGHTLY_MINOR_VERSION) + .expect("Unable to write version file"); + julia_dir.version().emit_metadata_unchecked(); } fn building_docs() -> bool { diff --git a/crates/jlrs_macros/src/version.rs b/crates/jlrs_macros/src/version.rs index 7f021414..1dd0c258 100644 --- a/crates/jlrs_macros/src/version.rs +++ b/crates/jlrs_macros/src/version.rs @@ -2,30 +2,13 @@ use std::ops::RangeInclusive; use proc_macro::{Delimiter, TokenStream, TokenTree}; -const MAJOR_VERSION: usize = 1; -const LTS_MINOR_VERSION: usize = 10; -const NIGHTLY_MINOR_VERSION: usize = 13; - -#[cfg(any( - all(julia_1_10, julia_1_11), - all(julia_1_10, julia_1_12), - all(julia_1_10, julia_1_13), - all(julia_1_11, julia_1_12), - all(julia_1_11, julia_1_13), - all(julia_1_12, julia_1_13), -))] -compile_error!("Multiple Julia versions have been detected"); - -#[cfg(not(any(julia_1_10, julia_1_11, julia_1_12, julia_1_13)))] -const SELECTED_MINOR_VERSION: usize = 10; -#[cfg(julia_1_10)] -const SELECTED_MINOR_VERSION: usize = 10; -#[cfg(julia_1_11)] -const SELECTED_MINOR_VERSION: usize = 11; -#[cfg(julia_1_12)] -const SELECTED_MINOR_VERSION: usize = 12; -#[cfg(julia_1_13)] -const SELECTED_MINOR_VERSION: usize = 13; +// Set in included file: +// const MAJOR_VERSION: usize = 1; +// const MIN_MINOR_VERSION: usize = 10; +// const MAX_MINOR_VERSION: usize = 13; +// const NIGHTLY_MINOR_VERSION: usize = 14; +// const SELECTED_MINOR_VERSION: usize = 14; +include!(concat!(env!("OUT_DIR"), "/version.rs")); pub fn emit_if_compatible(attr: TokenStream, item: TokenStream) -> TokenStream { let mut tts = attr.into_iter(); @@ -37,21 +20,21 @@ pub fn emit_if_compatible(attr: TokenStream, item: TokenStream) -> TokenStream { match tts.next() { Some(TokenTree::Ident(ident)) => match ident.to_string().as_ref() { "since" => { - expect_punt_eq(&mut tts); + expect_punct_eq(&mut tts); since = Some(unwrap_version(&mut tts)); if !expect_comma_or_end(&mut tts) { break; } } "until" => { - expect_punt_eq(&mut tts); + expect_punct_eq(&mut tts); until = Some(unwrap_version(&mut tts)); if !expect_comma_or_end(&mut tts) { break; } } "except" => { - expect_punt_eq(&mut tts); + expect_punct_eq(&mut tts); except = Some(unwrap_version_group(&mut tts)); if !expect_comma_or_end(&mut tts) { break; @@ -64,7 +47,7 @@ pub fn emit_if_compatible(attr: TokenStream, item: TokenStream) -> TokenStream { } } - let since = since.unwrap_or(Version::new(MAJOR_VERSION, LTS_MINOR_VERSION)); + let since = since.unwrap_or(Version::new(MAJOR_VERSION, MIN_MINOR_VERSION)); let until = until.unwrap_or(Version::new(MAJOR_VERSION, NIGHTLY_MINOR_VERSION)); let except = except.unwrap_or_default(); @@ -75,7 +58,7 @@ pub fn emit_if_compatible(attr: TokenStream, item: TokenStream) -> TokenStream { } } -fn expect_punt_eq>(iter: &mut T) { +fn expect_punct_eq>(iter: &mut T) { match iter.next() { Some(TokenTree::Punct(punct)) => { let punct = punct.as_char(); @@ -143,7 +126,7 @@ fn unwrap_version>(iter: &mut T) -> Version { assert!(iter.next().is_none(), "Expected of the form major.minor"); let version = Version::new(major, minor); - version.assert_valid(MAJOR_VERSION, LTS_MINOR_VERSION..=NIGHTLY_MINOR_VERSION); + version.assert_valid(MAJOR_VERSION, MIN_MINOR_VERSION..=NIGHTLY_MINOR_VERSION); version } diff --git a/examples/Cargo.toml b/examples/Cargo.toml index ffd184fd..29f94487 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -5,7 +5,7 @@ publish = false edition = "2024" [dev-dependencies] -jlrs = { version = "0.23", path = "../crates/jlrs", features = ["full"] } +jlrs = { version = "0.24", path = "../crates/jlrs", features = ["full"] } tokio = { version = "1", features = ["macros", "rt"]} rayon = "1.10"