From 3e6a3a2759dba46ae976497e65c89040311edfa3 Mon Sep 17 00:00:00 2001 From: l1npengtul Date: Mon, 31 Oct 2022 22:14:09 +0900 Subject: [PATCH 01/10] Stable Hash: Add feature, adjust CI, modify build.rs, add new API for accessing and setting the ahash seed in config.rs, make config.rs public --- .github/workflows/build.yml | 31 +++++++++++++++++++ .gitignore | 3 ++ Cargo.toml | 1 + build.rs | 25 +++++++-------- build.template | 61 ++++++++++++++++++++++++++++++++++--- src/config.rs | 53 +++++++++++++++++++++++++++++--- src/func/hashing.rs | 2 +- src/lib.rs | 4 ++- 8 files changed, 157 insertions(+), 23 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6823d676..11ca384f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -89,6 +89,37 @@ jobs: command: test args: ${{matrix.flags}} + nightly_features_build: + name: NightlyFeatureBuild + runs-on: ${{matrix.os}} + continue-on-error: ${{matrix.experimental}} + strategy: + matrix: + os: [ubuntu-latest] + flags: + - "--features stable_hash" + toolchain: [ nightly ] + experimental: [ false ] + include: + # smoketests for different toolchains + - { toolchain: nightly, os: windows-latest, experimental: false, flags: "" } + - { toolchain: nightly, os: macos-latest, experimental: false, flags: "" } + fail-fast: false + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Setup Toolchain + uses: actions-rs/toolchain@v1 + with: + toolchain: ${{matrix.toolchain}} + override: true + - name: Test + uses: actions-rs/cargo@v1 + with: + command: test + args: ${{matrix.flags}} + + # no-std builds are a bit more extensive to test no_std_build: name: NoStdBuild diff --git a/.gitignore b/.gitignore index fe87b992..10e86a86 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,6 @@ Rhai.toml **/*.bat doc/rhai-sync.json doc/rhai.json +.idea/ +.idea +.idea/* diff --git a/Cargo.toml b/Cargo.toml index 3999b7de..310ceb40 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -63,6 +63,7 @@ unicode-xid-ident = ["unicode-xid"] # allow Unicode Standard Annex #31 for ident metadata = ["serde", "serde_json", "rhai_codegen/metadata", "smartstring/serde"] # enable exporting functions metadata internals = [] # expose internal data structures debugging = ["internals"] # enable debugging +stable_hash = ["std"] serde = ["dep:serde", "smartstring/serde", "smallvec/serde"] # implement serde for rhai types # compiling for no-std diff --git a/build.rs b/build.rs index 66903154..76abd9ee 100644 --- a/build.rs +++ b/build.rs @@ -8,20 +8,21 @@ fn main() { // Tell Cargo that if the given environment variable changes, to rerun this build script. println!("cargo:rerun-if-changed=build.template"); println!("cargo:rerun-if-env-changed=RHAI_AHASH_SEED"); + if !cfg!(feature = "stable_hash") { + let mut contents = String::new(); - let mut contents = String::new(); + File::open("build.template") + .expect("cannot open `build.template`") + .read_to_string(&mut contents) + .expect("cannot read from `build.template`"); - File::open("build.template") - .expect("cannot open `build.template`") - .read_to_string(&mut contents) - .expect("cannot read from `build.template`"); + let seed = env::var("RHAI_AHASH_SEED").map_or_else(|_| "None".into(), |s| format!("Some({s})")); - let seed = env::var("RHAI_AHASH_SEED").map_or_else(|_| "None".into(), |s| format!("Some({s})")); + contents = contents.replace("{{AHASH_SEED}}", &seed); - contents = contents.replace("{{AHASH_SEED}}", &seed); - - File::create("src/config.rs") - .expect("cannot create `config.rs`") - .write(contents.as_bytes()) - .expect("cannot write to `config.rs`"); + File::create("src/config.rs") + .expect("cannot create `config.rs`") + .write_all(contents.as_bytes()) + .expect("cannot write to `config.rs`"); + } } diff --git a/build.template b/build.template index 6f09909f..ed5e161d 100644 --- a/build.template +++ b/build.template @@ -1,7 +1,60 @@ -//! Configuration settings for this Rhai build -//! -//! This file is auto-generated from `build.template` +#[cfg(feature = "stable_hash")] +use core::cell::OnceCell; +// [236,800,954,213], haha funny yume nikki reference + +#[cfg(not(feature = "stable_hash"))] /// Fixed hashing seeds for stable hashing. +/// /// Set to [`None`] to disable stable hashing. -pub const AHASH_SEED: Option<[u64; 4]> = {{AHASH_SEED}}; +/// +/// See [`set_rhai_ahash_seed`] for more. +/// +/// You can also set this at compile time by disabling `stable_hash` and setting the `RHAI_AHASH_SEED` +/// environment variable instead. +/// +/// E.g. `env RHAI_AHASH_SEED ="[236,800,954,213]"` +const AHASH_SEED: Option<[u64; 4]> = {{AHASH_SEED}}; +#[cfg(feature = "stable_hash")] +/// Fixed hashing seeds for stable hashing. +/// +/// Set to [`None`] to disable stable hashing. +/// +/// See [`set_rhai_ahash_seed`] for more. +/// +/// You can also set this at compile time by disabling `stable_hash` and setting the `RHAI_AHASH_SEED` +/// environment variable instead. +/// +/// E.g. `env RHAI_AHASH_SEED ="[236,800,954,213]"` +static AHASH_SEED: OnceCell> = OnceCell::new(); + +#[cfg(feature = "stable_hash")] +#[doc(cfg(feature = "stable_hash"))] +/// Sets the Rhai Ahash seed. This is used to hash functions and the like. +/// +/// This is a global variable, and thus will affect every Rhai instance. +/// This should not be used _unless_ you know you need it. +/// +/// **WARNING**: +/// - You can only call this function **ONCE** for the whole of your program execution. +/// - You should gracefully handle the `Err(())`. +/// - You **MUST** call this before **ANY** Rhai operation occurs (e.g. creating an [`Engine`]). +pub fn set_rhai_ahash_seed(new_seed: Option<[u64; 4]>) -> Result<(), Option<[u64; 4]>> { + AHASH_SEED.set(new_seed) +} + +#[cfg(feature = "stable_hash")] +/// Gets the current Rhai Ahash Seed. +/// +/// See [`set_rhai_ahash_seed`] for more. +pub fn get_rhai_ahash_seed() -> Option<[u64; 4]> { + AHASH_SEED.get().map(|x| *x).flatten() +} + +#[cfg(not(feature = "stable_hash"))] +/// Gets the current Rhai Ahash Seed. +/// +/// See [`AHASH_SEED`] and [`set_rhai_ahash_seed`] for more. +pub fn get_rhai_ahash_seed() -> Option<[u64; 4]> { + AHASH_SEED +} \ No newline at end of file diff --git a/src/config.rs b/src/config.rs index 93db79d5..4297fa07 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,7 +1,50 @@ -//! Configuration settings for this Rhai build +//! Fixed hashing seeds for stable hashing. //! -//! This file is auto-generated from `build.template` +//! Set to [`None`] to disable stable hashing. +//! +//! See [`set_rhai_ahash_seed`] for more. +//! +//! Alternatively, You can also set this at compile time by disabling `stable_hash` and setting the `RHAI_AHASH_SEED` +//! environment variable instead. +//! +//! E.g. `env RHAI_AHASH_SEED ="[236,800,954,213]"` +// [236,800,954,213], haha funny yume nikki reference epic uboachan face numberworld nexus moment 100 -/// Fixed hashing seeds for stable hashing. -/// Set to [`None`] to disable stable hashing. -pub const AHASH_SEED: Option<[u64; 4]> = None; +#[cfg(feature = "stable_hash")] +use std::sync::OnceLock; + +#[cfg(not(feature = "stable_hash"))] +const AHASH_SEED: Option<[u64; 4]> = None; +#[cfg(feature = "stable_hash")] +static AHASH_SEED: OnceLock> = OnceLock::new(); + +#[cfg(feature = "stable_hash")] +// #[doc(cfg(feature = "stable_hash"))] +/// Sets the Rhai Ahash seed. This is used to hash functions and the like. +/// +/// This is a global variable, and thus will affect every Rhai instance. +/// This should not be used _unless_ you know you need it. +/// +/// **WARNING**: +/// - You can only call this function **ONCE** for the whole of your program execution. +/// - You should gracefully handle the `Err(())`. +/// - You **MUST** call this before **ANY** Rhai operation occurs (e.g. creating an [`Engine`]). +pub fn set_rhai_ahash_seed(new_seed: Option<[u64; 4]>) -> Result<(), Option<[u64; 4]>> { + AHASH_SEED.set(new_seed) +} + +#[cfg(feature = "stable_hash")] +/// Gets the current Rhai Ahash Seed. +/// +/// See [`set_rhai_ahash_seed`] for more. +pub fn get_rhai_ahash_seed() -> Option<[u64; 4]> { + AHASH_SEED.get().map(|x| *x).flatten() +} + +#[cfg(not(feature = "stable_hash"))] +/// Gets the current Rhai Ahash Seed. +/// +/// See [`AHASH_SEED`] and [`set_rhai_ahash_seed`] for more. +pub fn get_rhai_ahash_seed() -> Option<[u64; 4]> { + AHASH_SEED +} diff --git a/src/func/hashing.rs b/src/func/hashing.rs index 5f6a806c..406a21c6 100644 --- a/src/func/hashing.rs +++ b/src/func/hashing.rs @@ -77,7 +77,7 @@ impl BuildHasher for StraightHasherBuilder { #[inline(always)] #[must_use] pub fn get_hasher() -> ahash::AHasher { - match config::AHASH_SEED { + match config::get_rhai_ahash_seed() { Some([seed1, seed2, seed3, seed4]) if seed1 | seed2 | seed3 | seed4 != 0 => { ahash::RandomState::with_seeds(seed1, seed2, seed3, seed4).build_hasher() } diff --git a/src/lib.rs b/src/lib.rs index 199edb75..d2d6eae7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -71,6 +71,8 @@ #![allow(clippy::negative_feature_names)] #![allow(clippy::module_inception)] +#![cfg_attr(feature = "stable_hash", feature(once_cell))] + #[cfg(feature = "no_std")] extern crate alloc; @@ -83,7 +85,7 @@ use std::prelude::v1::*; // Internal modules mod api; mod ast; -mod config; +pub mod config; mod engine; mod eval; mod func; From ec332b4e496189efe899c1e0ba4d1f789df38b55 Mon Sep 17 00:00:00 2001 From: l1npengtul Date: Mon, 31 Oct 2022 22:20:43 +0900 Subject: [PATCH 02/10] add errors doc for set rhai fn --- src/config.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/config.rs b/src/config.rs index 4297fa07..9ea638bb 100644 --- a/src/config.rs +++ b/src/config.rs @@ -29,6 +29,9 @@ static AHASH_SEED: OnceLock> = OnceLock::new(); /// - You can only call this function **ONCE** for the whole of your program execution. /// - You should gracefully handle the `Err(())`. /// - You **MUST** call this before **ANY** Rhai operation occurs (e.g. creating an [`Engine`]). +/// +/// # Errors +/// This will error if the AHashSeed is already set. pub fn set_rhai_ahash_seed(new_seed: Option<[u64; 4]>) -> Result<(), Option<[u64; 4]>> { AHASH_SEED.set(new_seed) } From 87e51cb8fe7ce30396a2c2eb38b97027ef10598b Mon Sep 17 00:00:00 2001 From: l1npengtul Date: Mon, 31 Oct 2022 22:26:04 +0900 Subject: [PATCH 03/10] adjust warnings doc --- src/config.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config.rs b/src/config.rs index 9ea638bb..e7611418 100644 --- a/src/config.rs +++ b/src/config.rs @@ -25,7 +25,7 @@ static AHASH_SEED: OnceLock> = OnceLock::new(); /// This is a global variable, and thus will affect every Rhai instance. /// This should not be used _unless_ you know you need it. /// -/// **WARNING**: +/// # Warning: /// - You can only call this function **ONCE** for the whole of your program execution. /// - You should gracefully handle the `Err(())`. /// - You **MUST** call this before **ANY** Rhai operation occurs (e.g. creating an [`Engine`]). From bb01f914e012500653e9a2a2e189e6fbeae8a8ea Mon Sep 17 00:00:00 2001 From: l1npengtul Date: Tue, 1 Nov 2022 00:59:07 +0900 Subject: [PATCH 04/10] Address concerns --- .github/workflows/build.yml | 63 ++++++------- Cargo.toml | 2 +- build.rs | 4 +- build.template | 175 +++++++++++++++++++++++++----------- src/config.rs | 148 ++++++++++++++++++++++-------- src/config/hashing.rs | 129 ++++++++++++++++++++++++++ src/config/mod.rs | 3 + src/func/hashing.rs | 2 +- src/lib.rs | 2 +- 9 files changed, 404 insertions(+), 124 deletions(-) create mode 100644 src/config/hashing.rs create mode 100644 src/config/mod.rs diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 11ca384f..fc782151 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -44,7 +44,7 @@ jobs: flags: - "" - "--features debugging" - - "--features metadata,serde,internals" + - "--features metadata,serde,internals,static_hash" - "--features unchecked,serde,metadata,internals,debugging" - "--features sync,serde,metadata,internals,debugging" - "--features no_position,serde,metadata,internals,debugging" @@ -89,35 +89,35 @@ jobs: command: test args: ${{matrix.flags}} - nightly_features_build: - name: NightlyFeatureBuild - runs-on: ${{matrix.os}} - continue-on-error: ${{matrix.experimental}} - strategy: - matrix: - os: [ubuntu-latest] - flags: - - "--features stable_hash" - toolchain: [ nightly ] - experimental: [ false ] - include: - # smoketests for different toolchains - - { toolchain: nightly, os: windows-latest, experimental: false, flags: "" } - - { toolchain: nightly, os: macos-latest, experimental: false, flags: "" } - fail-fast: false - steps: - - name: Checkout - uses: actions/checkout@v2 - - name: Setup Toolchain - uses: actions-rs/toolchain@v1 - with: - toolchain: ${{matrix.toolchain}} - override: true - - name: Test - uses: actions-rs/cargo@v1 - with: - command: test - args: ${{matrix.flags}} +# nightly_features_build: +# name: NightlyFeatureBuild +# runs-on: ${{matrix.os}} +# continue-on-error: ${{matrix.experimental}} +# strategy: +# matrix: +# os: [ubuntu-latest] +# flags: +# - "--features stable_hash" +# toolchain: [ nightly ] +# experimental: [ false ] +# include: +# # smoketests for different toolchains +# - { toolchain: nightly, os: windows-latest, experimental: false, flags: "" } +# - { toolchain: nightly, os: macos-latest, experimental: false, flags: "" } +# fail-fast: false +# steps: +# - name: Checkout +# uses: actions/checkout@v2 +# - name: Setup Toolchain +# uses: actions-rs/toolchain@v1 +# with: +# toolchain: ${{matrix.toolchain}} +# override: true +# - name: Test +# uses: actions-rs/cargo@v1 +# with: +# command: test +# args: ${{matrix.flags}} # no-std builds are a bit more extensive to test @@ -127,6 +127,9 @@ jobs: continue-on-error: ${{matrix.experimental}} strategy: matrix: + flags: + - "" + - "--features static_hash" include: - {os: ubuntu-latest, flags: "--profile unix", experimental: false} - {os: windows-latest, flags: "--profile windows", experimental: true} diff --git a/Cargo.toml b/Cargo.toml index 310ceb40..e5edb293 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -63,7 +63,7 @@ unicode-xid-ident = ["unicode-xid"] # allow Unicode Standard Annex #31 for ident metadata = ["serde", "serde_json", "rhai_codegen/metadata", "smartstring/serde"] # enable exporting functions metadata internals = [] # expose internal data structures debugging = ["internals"] # enable debugging -stable_hash = ["std"] +static_hash = [] serde = ["dep:serde", "smartstring/serde", "smallvec/serde"] # implement serde for rhai types # compiling for no-std diff --git a/build.rs b/build.rs index 76abd9ee..dda0850e 100644 --- a/build.rs +++ b/build.rs @@ -20,9 +20,9 @@ fn main() { contents = contents.replace("{{AHASH_SEED}}", &seed); - File::create("src/config.rs") + File::create("src/config/hashing.rs") .expect("cannot create `config.rs`") .write_all(contents.as_bytes()) - .expect("cannot write to `config.rs`"); + .expect("cannot write to `config/hashing.rs`"); } } diff --git a/build.template b/build.template index ed5e161d..709a3f65 100644 --- a/build.template +++ b/build.template @@ -1,60 +1,129 @@ -#[cfg(feature = "stable_hash")] -use core::cell::OnceCell; +//! Fixed hashing seeds for stable hashing. +//! +//! Set to [`None`] to disable stable hashing. +//! +//! See [`set_rhai_ahash_seed`] for more. +//! +//! Alternatively, You can also set this at compile time by disabling `stable_hash` and setting the `RHAI_AHASH_SEED` +//! environment variable instead. +//! +//! E.g. `env RHAI_AHASH_SEED ="[236,800,954,213]"` +// [236,800,954,213], haha funny yume nikki reference epic uboachan face numberworld nexus moment 100 -// [236,800,954,213], haha funny yume nikki reference +pub use internal::get_ahash_seed; +#[cfg(feature = "static_hash")] +pub use internal::set_ahash_seed; -#[cfg(not(feature = "stable_hash"))] -/// Fixed hashing seeds for stable hashing. -/// -/// Set to [`None`] to disable stable hashing. -/// -/// See [`set_rhai_ahash_seed`] for more. -/// -/// You can also set this at compile time by disabling `stable_hash` and setting the `RHAI_AHASH_SEED` -/// environment variable instead. -/// -/// E.g. `env RHAI_AHASH_SEED ="[236,800,954,213]"` -const AHASH_SEED: Option<[u64; 4]> = {{AHASH_SEED}}; -#[cfg(feature = "stable_hash")] -/// Fixed hashing seeds for stable hashing. -/// -/// Set to [`None`] to disable stable hashing. -/// -/// See [`set_rhai_ahash_seed`] for more. -/// -/// You can also set this at compile time by disabling `stable_hash` and setting the `RHAI_AHASH_SEED` -/// environment variable instead. -/// -/// E.g. `env RHAI_AHASH_SEED ="[236,800,954,213]"` -static AHASH_SEED: OnceCell> = OnceCell::new(); +#[cfg(feature = "static_hash")] +mod internal { + use core::{ + cell::UnsafeCell, + marker::PhantomData, + mem::MaybeUninit, + sync::atomic::{AtomicBool, Ordering}, + panic::{RefUnwindSafe, UnwindSafe} + }; -#[cfg(feature = "stable_hash")] -#[doc(cfg(feature = "stable_hash"))] -/// Sets the Rhai Ahash seed. This is used to hash functions and the like. -/// -/// This is a global variable, and thus will affect every Rhai instance. -/// This should not be used _unless_ you know you need it. -/// -/// **WARNING**: -/// - You can only call this function **ONCE** for the whole of your program execution. -/// - You should gracefully handle the `Err(())`. -/// - You **MUST** call this before **ANY** Rhai operation occurs (e.g. creating an [`Engine`]). -pub fn set_rhai_ahash_seed(new_seed: Option<[u64; 4]>) -> Result<(), Option<[u64; 4]>> { - AHASH_SEED.set(new_seed) + struct SusLock where T: 'static { + initalized: AtomicBool, + data: UnsafeCell>, + _marker: PhantomData, + } + + impl SusLock { + pub const fn new() -> SusLock { + SusLock { + initalized: AtomicBool::new(false), + data: UnsafeCell::new(MaybeUninit::uninit()), + _marker: PhantomData + } + } + + pub fn get(&self) -> Option<&T> { + if self.initalized.load(Ordering::SeqCst) { + Some( + unsafe { + (&*self.data.get()).assume_init_ref() + } + ) + } else { + return None + } + } + + pub fn get_or_init(&self, f: impl FnOnce() -> T) -> Option<&T> { + let value = f(); + if !self.initalized.load(Ordering::SeqCst) { + unsafe { + self.data.get().write(MaybeUninit::new(value)); + } + self.initalized.store(true, Ordering::SeqCst); + } + + self.get() + } + + pub fn set(&self, value: T) -> Result<(), T> { + if self.initalized.load(Ordering::SeqCst) { + Err(value) + } else { + let _ = self.get_or_init(|| value); + Ok(()) + } + } + } + + unsafe impl Sync for SusLock {} + unsafe impl Send for SusLock {} + impl RefUnwindSafe for SusLock {} + + impl Drop for SusLock { + fn drop(&mut self) { + if self.initalized.load(Ordering::SeqCst) { + unsafe { (&mut *self.data.get()).assume_init_drop() }; + } + } + } + + static AHASH_SEED: SusLock> = SusLock::new(); + + // #[doc(cfg(feature = "stable_hash"))] + /// Sets the Rhai Ahash seed. This is used to hash functions and the like. + /// + /// This is a global variable, and thus will affect every Rhai instance. + /// This should not be used _unless_ you know you need it. + /// + /// # Warnings + /// - You can only call this function **ONCE** for the whole of your program execution. + /// - You should gracefully handle the `Err(())`. + /// - You **MUST** call this before **ANY** Rhai operation occurs (e.g. creating an [`Engine`]). + /// + /// # Errors + /// This will error if the AHashSeed is already set. + pub fn set_ahash_seed(new_seed: Option<[u64; 4]>) -> Result<(), Option<[u64; 4]>> { + AHASH_SEED.set(new_seed) + } + + /// Gets the current Rhai Ahash Seed. If the seed is not yet defined, this will automatically set a seed. + /// The default seed is not stable and may change between versions. + /// + /// See [`set_rhai_ahash_seed`] for more. + pub fn get_ahash_seed() -> Option<[u64; 4]> { + const FUNNY_YUMENIKKI_REFERENCE: [u64; 4] = [236,800,954,213]; + + AHASH_SEED.get_or_init(|| Some(FUNNY_YUMENIKKI_REFERENCE)).map(|x| *x).flatten() + } } -#[cfg(feature = "stable_hash")] -/// Gets the current Rhai Ahash Seed. -/// -/// See [`set_rhai_ahash_seed`] for more. -pub fn get_rhai_ahash_seed() -> Option<[u64; 4]> { - AHASH_SEED.get().map(|x| *x).flatten() -} +#[cfg(not(feature = "static_hash"))] +mod internal { + const AHASH_SEED: Option<[u64; 4]> = {{ AHASH_SEED }}; -#[cfg(not(feature = "stable_hash"))] -/// Gets the current Rhai Ahash Seed. -/// -/// See [`AHASH_SEED`] and [`set_rhai_ahash_seed`] for more. -pub fn get_rhai_ahash_seed() -> Option<[u64; 4]> { - AHASH_SEED + /// Gets the current Rhai Ahash Seed. If the seed is not yet defined, this will automatically set a seed. + /// The default seed is not stable and may change between versions. + /// + /// See [`set_ahash_seed`] for more. + pub fn get_ahash_seed() -> Option<[u64; 4]> { + AHASH_SEED + } } \ No newline at end of file diff --git a/src/config.rs b/src/config.rs index e7611418..709a3f65 100644 --- a/src/config.rs +++ b/src/config.rs @@ -10,44 +10,120 @@ //! E.g. `env RHAI_AHASH_SEED ="[236,800,954,213]"` // [236,800,954,213], haha funny yume nikki reference epic uboachan face numberworld nexus moment 100 -#[cfg(feature = "stable_hash")] -use std::sync::OnceLock; +pub use internal::get_ahash_seed; +#[cfg(feature = "static_hash")] +pub use internal::set_ahash_seed; -#[cfg(not(feature = "stable_hash"))] -const AHASH_SEED: Option<[u64; 4]> = None; -#[cfg(feature = "stable_hash")] -static AHASH_SEED: OnceLock> = OnceLock::new(); +#[cfg(feature = "static_hash")] +mod internal { + use core::{ + cell::UnsafeCell, + marker::PhantomData, + mem::MaybeUninit, + sync::atomic::{AtomicBool, Ordering}, + panic::{RefUnwindSafe, UnwindSafe} + }; -#[cfg(feature = "stable_hash")] -// #[doc(cfg(feature = "stable_hash"))] -/// Sets the Rhai Ahash seed. This is used to hash functions and the like. -/// -/// This is a global variable, and thus will affect every Rhai instance. -/// This should not be used _unless_ you know you need it. -/// -/// # Warning: -/// - You can only call this function **ONCE** for the whole of your program execution. -/// - You should gracefully handle the `Err(())`. -/// - You **MUST** call this before **ANY** Rhai operation occurs (e.g. creating an [`Engine`]). -/// -/// # Errors -/// This will error if the AHashSeed is already set. -pub fn set_rhai_ahash_seed(new_seed: Option<[u64; 4]>) -> Result<(), Option<[u64; 4]>> { - AHASH_SEED.set(new_seed) + struct SusLock where T: 'static { + initalized: AtomicBool, + data: UnsafeCell>, + _marker: PhantomData, + } + + impl SusLock { + pub const fn new() -> SusLock { + SusLock { + initalized: AtomicBool::new(false), + data: UnsafeCell::new(MaybeUninit::uninit()), + _marker: PhantomData + } + } + + pub fn get(&self) -> Option<&T> { + if self.initalized.load(Ordering::SeqCst) { + Some( + unsafe { + (&*self.data.get()).assume_init_ref() + } + ) + } else { + return None + } + } + + pub fn get_or_init(&self, f: impl FnOnce() -> T) -> Option<&T> { + let value = f(); + if !self.initalized.load(Ordering::SeqCst) { + unsafe { + self.data.get().write(MaybeUninit::new(value)); + } + self.initalized.store(true, Ordering::SeqCst); + } + + self.get() + } + + pub fn set(&self, value: T) -> Result<(), T> { + if self.initalized.load(Ordering::SeqCst) { + Err(value) + } else { + let _ = self.get_or_init(|| value); + Ok(()) + } + } + } + + unsafe impl Sync for SusLock {} + unsafe impl Send for SusLock {} + impl RefUnwindSafe for SusLock {} + + impl Drop for SusLock { + fn drop(&mut self) { + if self.initalized.load(Ordering::SeqCst) { + unsafe { (&mut *self.data.get()).assume_init_drop() }; + } + } + } + + static AHASH_SEED: SusLock> = SusLock::new(); + + // #[doc(cfg(feature = "stable_hash"))] + /// Sets the Rhai Ahash seed. This is used to hash functions and the like. + /// + /// This is a global variable, and thus will affect every Rhai instance. + /// This should not be used _unless_ you know you need it. + /// + /// # Warnings + /// - You can only call this function **ONCE** for the whole of your program execution. + /// - You should gracefully handle the `Err(())`. + /// - You **MUST** call this before **ANY** Rhai operation occurs (e.g. creating an [`Engine`]). + /// + /// # Errors + /// This will error if the AHashSeed is already set. + pub fn set_ahash_seed(new_seed: Option<[u64; 4]>) -> Result<(), Option<[u64; 4]>> { + AHASH_SEED.set(new_seed) + } + + /// Gets the current Rhai Ahash Seed. If the seed is not yet defined, this will automatically set a seed. + /// The default seed is not stable and may change between versions. + /// + /// See [`set_rhai_ahash_seed`] for more. + pub fn get_ahash_seed() -> Option<[u64; 4]> { + const FUNNY_YUMENIKKI_REFERENCE: [u64; 4] = [236,800,954,213]; + + AHASH_SEED.get_or_init(|| Some(FUNNY_YUMENIKKI_REFERENCE)).map(|x| *x).flatten() + } } -#[cfg(feature = "stable_hash")] -/// Gets the current Rhai Ahash Seed. -/// -/// See [`set_rhai_ahash_seed`] for more. -pub fn get_rhai_ahash_seed() -> Option<[u64; 4]> { - AHASH_SEED.get().map(|x| *x).flatten() -} +#[cfg(not(feature = "static_hash"))] +mod internal { + const AHASH_SEED: Option<[u64; 4]> = {{ AHASH_SEED }}; -#[cfg(not(feature = "stable_hash"))] -/// Gets the current Rhai Ahash Seed. -/// -/// See [`AHASH_SEED`] and [`set_rhai_ahash_seed`] for more. -pub fn get_rhai_ahash_seed() -> Option<[u64; 4]> { - AHASH_SEED -} + /// Gets the current Rhai Ahash Seed. If the seed is not yet defined, this will automatically set a seed. + /// The default seed is not stable and may change between versions. + /// + /// See [`set_ahash_seed`] for more. + pub fn get_ahash_seed() -> Option<[u64; 4]> { + AHASH_SEED + } +} \ No newline at end of file diff --git a/src/config/hashing.rs b/src/config/hashing.rs new file mode 100644 index 00000000..709a3f65 --- /dev/null +++ b/src/config/hashing.rs @@ -0,0 +1,129 @@ +//! Fixed hashing seeds for stable hashing. +//! +//! Set to [`None`] to disable stable hashing. +//! +//! See [`set_rhai_ahash_seed`] for more. +//! +//! Alternatively, You can also set this at compile time by disabling `stable_hash` and setting the `RHAI_AHASH_SEED` +//! environment variable instead. +//! +//! E.g. `env RHAI_AHASH_SEED ="[236,800,954,213]"` +// [236,800,954,213], haha funny yume nikki reference epic uboachan face numberworld nexus moment 100 + +pub use internal::get_ahash_seed; +#[cfg(feature = "static_hash")] +pub use internal::set_ahash_seed; + +#[cfg(feature = "static_hash")] +mod internal { + use core::{ + cell::UnsafeCell, + marker::PhantomData, + mem::MaybeUninit, + sync::atomic::{AtomicBool, Ordering}, + panic::{RefUnwindSafe, UnwindSafe} + }; + + struct SusLock where T: 'static { + initalized: AtomicBool, + data: UnsafeCell>, + _marker: PhantomData, + } + + impl SusLock { + pub const fn new() -> SusLock { + SusLock { + initalized: AtomicBool::new(false), + data: UnsafeCell::new(MaybeUninit::uninit()), + _marker: PhantomData + } + } + + pub fn get(&self) -> Option<&T> { + if self.initalized.load(Ordering::SeqCst) { + Some( + unsafe { + (&*self.data.get()).assume_init_ref() + } + ) + } else { + return None + } + } + + pub fn get_or_init(&self, f: impl FnOnce() -> T) -> Option<&T> { + let value = f(); + if !self.initalized.load(Ordering::SeqCst) { + unsafe { + self.data.get().write(MaybeUninit::new(value)); + } + self.initalized.store(true, Ordering::SeqCst); + } + + self.get() + } + + pub fn set(&self, value: T) -> Result<(), T> { + if self.initalized.load(Ordering::SeqCst) { + Err(value) + } else { + let _ = self.get_or_init(|| value); + Ok(()) + } + } + } + + unsafe impl Sync for SusLock {} + unsafe impl Send for SusLock {} + impl RefUnwindSafe for SusLock {} + + impl Drop for SusLock { + fn drop(&mut self) { + if self.initalized.load(Ordering::SeqCst) { + unsafe { (&mut *self.data.get()).assume_init_drop() }; + } + } + } + + static AHASH_SEED: SusLock> = SusLock::new(); + + // #[doc(cfg(feature = "stable_hash"))] + /// Sets the Rhai Ahash seed. This is used to hash functions and the like. + /// + /// This is a global variable, and thus will affect every Rhai instance. + /// This should not be used _unless_ you know you need it. + /// + /// # Warnings + /// - You can only call this function **ONCE** for the whole of your program execution. + /// - You should gracefully handle the `Err(())`. + /// - You **MUST** call this before **ANY** Rhai operation occurs (e.g. creating an [`Engine`]). + /// + /// # Errors + /// This will error if the AHashSeed is already set. + pub fn set_ahash_seed(new_seed: Option<[u64; 4]>) -> Result<(), Option<[u64; 4]>> { + AHASH_SEED.set(new_seed) + } + + /// Gets the current Rhai Ahash Seed. If the seed is not yet defined, this will automatically set a seed. + /// The default seed is not stable and may change between versions. + /// + /// See [`set_rhai_ahash_seed`] for more. + pub fn get_ahash_seed() -> Option<[u64; 4]> { + const FUNNY_YUMENIKKI_REFERENCE: [u64; 4] = [236,800,954,213]; + + AHASH_SEED.get_or_init(|| Some(FUNNY_YUMENIKKI_REFERENCE)).map(|x| *x).flatten() + } +} + +#[cfg(not(feature = "static_hash"))] +mod internal { + const AHASH_SEED: Option<[u64; 4]> = {{ AHASH_SEED }}; + + /// Gets the current Rhai Ahash Seed. If the seed is not yet defined, this will automatically set a seed. + /// The default seed is not stable and may change between versions. + /// + /// See [`set_ahash_seed`] for more. + pub fn get_ahash_seed() -> Option<[u64; 4]> { + AHASH_SEED + } +} \ No newline at end of file diff --git a/src/config/mod.rs b/src/config/mod.rs new file mode 100644 index 00000000..194ac6da --- /dev/null +++ b/src/config/mod.rs @@ -0,0 +1,3 @@ +//! Contains Configuration for Rhai. + +pub mod hashing; \ No newline at end of file diff --git a/src/func/hashing.rs b/src/func/hashing.rs index 406a21c6..855dcd3d 100644 --- a/src/func/hashing.rs +++ b/src/func/hashing.rs @@ -77,7 +77,7 @@ impl BuildHasher for StraightHasherBuilder { #[inline(always)] #[must_use] pub fn get_hasher() -> ahash::AHasher { - match config::get_rhai_ahash_seed() { + match config::hashing::get_ahash_seed() { Some([seed1, seed2, seed3, seed4]) if seed1 | seed2 | seed3 | seed4 != 0 => { ahash::RandomState::with_seeds(seed1, seed2, seed3, seed4).build_hasher() } diff --git a/src/lib.rs b/src/lib.rs index d2d6eae7..f2a0cad5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -71,7 +71,7 @@ #![allow(clippy::negative_feature_names)] #![allow(clippy::module_inception)] -#![cfg_attr(feature = "stable_hash", feature(once_cell))] +#![cfg_attr(feature = "static_hash", feature(once_cell))] #[cfg(feature = "no_std")] extern crate alloc; From 876fd63dd3c359c597bdcd71b02e01346d2db91b Mon Sep 17 00:00:00 2001 From: l1npengtul Date: Tue, 1 Nov 2022 01:01:04 +0900 Subject: [PATCH 05/10] remove unneeded feature --- src/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index f2a0cad5..8879012f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -71,8 +71,6 @@ #![allow(clippy::negative_feature_names)] #![allow(clippy::module_inception)] -#![cfg_attr(feature = "static_hash", feature(once_cell))] - #[cfg(feature = "no_std")] extern crate alloc; From 488a8eab5e015f55f51eb01e0c2e5bb97494e289 Mon Sep 17 00:00:00 2001 From: l1npengtul Date: Tue, 1 Nov 2022 01:02:55 +0900 Subject: [PATCH 06/10] remove config.rs (?) --- src/config.rs | 129 -------------------------------------------------- 1 file changed, 129 deletions(-) delete mode 100644 src/config.rs diff --git a/src/config.rs b/src/config.rs deleted file mode 100644 index 709a3f65..00000000 --- a/src/config.rs +++ /dev/null @@ -1,129 +0,0 @@ -//! Fixed hashing seeds for stable hashing. -//! -//! Set to [`None`] to disable stable hashing. -//! -//! See [`set_rhai_ahash_seed`] for more. -//! -//! Alternatively, You can also set this at compile time by disabling `stable_hash` and setting the `RHAI_AHASH_SEED` -//! environment variable instead. -//! -//! E.g. `env RHAI_AHASH_SEED ="[236,800,954,213]"` -// [236,800,954,213], haha funny yume nikki reference epic uboachan face numberworld nexus moment 100 - -pub use internal::get_ahash_seed; -#[cfg(feature = "static_hash")] -pub use internal::set_ahash_seed; - -#[cfg(feature = "static_hash")] -mod internal { - use core::{ - cell::UnsafeCell, - marker::PhantomData, - mem::MaybeUninit, - sync::atomic::{AtomicBool, Ordering}, - panic::{RefUnwindSafe, UnwindSafe} - }; - - struct SusLock where T: 'static { - initalized: AtomicBool, - data: UnsafeCell>, - _marker: PhantomData, - } - - impl SusLock { - pub const fn new() -> SusLock { - SusLock { - initalized: AtomicBool::new(false), - data: UnsafeCell::new(MaybeUninit::uninit()), - _marker: PhantomData - } - } - - pub fn get(&self) -> Option<&T> { - if self.initalized.load(Ordering::SeqCst) { - Some( - unsafe { - (&*self.data.get()).assume_init_ref() - } - ) - } else { - return None - } - } - - pub fn get_or_init(&self, f: impl FnOnce() -> T) -> Option<&T> { - let value = f(); - if !self.initalized.load(Ordering::SeqCst) { - unsafe { - self.data.get().write(MaybeUninit::new(value)); - } - self.initalized.store(true, Ordering::SeqCst); - } - - self.get() - } - - pub fn set(&self, value: T) -> Result<(), T> { - if self.initalized.load(Ordering::SeqCst) { - Err(value) - } else { - let _ = self.get_or_init(|| value); - Ok(()) - } - } - } - - unsafe impl Sync for SusLock {} - unsafe impl Send for SusLock {} - impl RefUnwindSafe for SusLock {} - - impl Drop for SusLock { - fn drop(&mut self) { - if self.initalized.load(Ordering::SeqCst) { - unsafe { (&mut *self.data.get()).assume_init_drop() }; - } - } - } - - static AHASH_SEED: SusLock> = SusLock::new(); - - // #[doc(cfg(feature = "stable_hash"))] - /// Sets the Rhai Ahash seed. This is used to hash functions and the like. - /// - /// This is a global variable, and thus will affect every Rhai instance. - /// This should not be used _unless_ you know you need it. - /// - /// # Warnings - /// - You can only call this function **ONCE** for the whole of your program execution. - /// - You should gracefully handle the `Err(())`. - /// - You **MUST** call this before **ANY** Rhai operation occurs (e.g. creating an [`Engine`]). - /// - /// # Errors - /// This will error if the AHashSeed is already set. - pub fn set_ahash_seed(new_seed: Option<[u64; 4]>) -> Result<(), Option<[u64; 4]>> { - AHASH_SEED.set(new_seed) - } - - /// Gets the current Rhai Ahash Seed. If the seed is not yet defined, this will automatically set a seed. - /// The default seed is not stable and may change between versions. - /// - /// See [`set_rhai_ahash_seed`] for more. - pub fn get_ahash_seed() -> Option<[u64; 4]> { - const FUNNY_YUMENIKKI_REFERENCE: [u64; 4] = [236,800,954,213]; - - AHASH_SEED.get_or_init(|| Some(FUNNY_YUMENIKKI_REFERENCE)).map(|x| *x).flatten() - } -} - -#[cfg(not(feature = "static_hash"))] -mod internal { - const AHASH_SEED: Option<[u64; 4]> = {{ AHASH_SEED }}; - - /// Gets the current Rhai Ahash Seed. If the seed is not yet defined, this will automatically set a seed. - /// The default seed is not stable and may change between versions. - /// - /// See [`set_ahash_seed`] for more. - pub fn get_ahash_seed() -> Option<[u64; 4]> { - AHASH_SEED - } -} \ No newline at end of file From 79e7c305bf86193846f050858e68f6946c23a0c8 Mon Sep 17 00:00:00 2001 From: l1npengtul Date: Tue, 1 Nov 2022 01:26:23 +0900 Subject: [PATCH 07/10] fix templateing issue --- build.rs | 2 +- src/config/hashing.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.rs b/build.rs index dda0850e..a994ef69 100644 --- a/build.rs +++ b/build.rs @@ -18,7 +18,7 @@ fn main() { let seed = env::var("RHAI_AHASH_SEED").map_or_else(|_| "None".into(), |s| format!("Some({s})")); - contents = contents.replace("{{AHASH_SEED}}", &seed); + contents = contents.replace("{{ AHASH_SEED }}", &seed); File::create("src/config/hashing.rs") .expect("cannot create `config.rs`") diff --git a/src/config/hashing.rs b/src/config/hashing.rs index 709a3f65..19423149 100644 --- a/src/config/hashing.rs +++ b/src/config/hashing.rs @@ -117,7 +117,7 @@ mod internal { #[cfg(not(feature = "static_hash"))] mod internal { - const AHASH_SEED: Option<[u64; 4]> = {{ AHASH_SEED }}; + const AHASH_SEED: Option<[u64; 4]> = None; /// Gets the current Rhai Ahash Seed. If the seed is not yet defined, this will automatically set a seed. /// The default seed is not stable and may change between versions. From 5816d571b39d6da8cf357a24175399fdc9067c19 Mon Sep 17 00:00:00 2001 From: l1npengtul Date: Tue, 1 Nov 2022 21:25:45 +0900 Subject: [PATCH 08/10] remove stable hash and fix CI --- Cargo.toml | 1 - build.rs | 24 +++--- build.template | 185 +++++++++++++++++++----------------------- src/config/hashing.rs | 185 +++++++++++++++++++----------------------- src/config/mod.rs | 2 +- 5 files changed, 180 insertions(+), 217 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e5edb293..3999b7de 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -63,7 +63,6 @@ unicode-xid-ident = ["unicode-xid"] # allow Unicode Standard Annex #31 for ident metadata = ["serde", "serde_json", "rhai_codegen/metadata", "smartstring/serde"] # enable exporting functions metadata internals = [] # expose internal data structures debugging = ["internals"] # enable debugging -static_hash = [] serde = ["dep:serde", "smartstring/serde", "smallvec/serde"] # implement serde for rhai types # compiling for no-std diff --git a/build.rs b/build.rs index a994ef69..e95b1dc3 100644 --- a/build.rs +++ b/build.rs @@ -8,21 +8,19 @@ fn main() { // Tell Cargo that if the given environment variable changes, to rerun this build script. println!("cargo:rerun-if-changed=build.template"); println!("cargo:rerun-if-env-changed=RHAI_AHASH_SEED"); - if !cfg!(feature = "stable_hash") { - let mut contents = String::new(); + let mut contents = String::new(); - File::open("build.template") - .expect("cannot open `build.template`") - .read_to_string(&mut contents) - .expect("cannot read from `build.template`"); + File::open("build.template") + .expect("cannot open `build.template`") + .read_to_string(&mut contents) + .expect("cannot read from `build.template`"); - let seed = env::var("RHAI_AHASH_SEED").map_or_else(|_| "None".into(), |s| format!("Some({s})")); + let seed = env::var("RHAI_AHASH_SEED").map_or_else(|_| "None".into(), |s| format!("Some({s})")); - contents = contents.replace("{{ AHASH_SEED }}", &seed); + contents = contents.replace("{{ AHASH_SEED }}", &seed); - File::create("src/config/hashing.rs") - .expect("cannot create `config.rs`") - .write_all(contents.as_bytes()) - .expect("cannot write to `config/hashing.rs`"); - } + File::create("src/config/hashing.rs") + .expect("cannot create `config.rs`") + .write_all(contents.as_bytes()) + .expect("cannot write to `config/hashing.rs`"); } diff --git a/build.template b/build.template index 709a3f65..89b0e403 100644 --- a/build.template +++ b/build.template @@ -10,120 +10,103 @@ //! E.g. `env RHAI_AHASH_SEED ="[236,800,954,213]"` // [236,800,954,213], haha funny yume nikki reference epic uboachan face numberworld nexus moment 100 -pub use internal::get_ahash_seed; -#[cfg(feature = "static_hash")] -pub use internal::set_ahash_seed; +use core::{ + cell::UnsafeCell, + marker::PhantomData, + mem::MaybeUninit, + panic::{RefUnwindSafe, UnwindSafe}, + sync::atomic::{AtomicBool, Ordering}, +}; -#[cfg(feature = "static_hash")] -mod internal { - use core::{ - cell::UnsafeCell, - marker::PhantomData, - mem::MaybeUninit, - sync::atomic::{AtomicBool, Ordering}, - panic::{RefUnwindSafe, UnwindSafe} - }; +// Safety: lol +struct SusLock +where + T: 'static, +{ + initalized: AtomicBool, + data: UnsafeCell>, + _marker: PhantomData, +} - struct SusLock where T: 'static { - initalized: AtomicBool, - data: UnsafeCell>, - _marker: PhantomData, - } - - impl SusLock { - pub const fn new() -> SusLock { - SusLock { - initalized: AtomicBool::new(false), - data: UnsafeCell::new(MaybeUninit::uninit()), - _marker: PhantomData - } - } - - pub fn get(&self) -> Option<&T> { - if self.initalized.load(Ordering::SeqCst) { - Some( - unsafe { - (&*self.data.get()).assume_init_ref() - } - ) - } else { - return None - } - } - - pub fn get_or_init(&self, f: impl FnOnce() -> T) -> Option<&T> { - let value = f(); - if !self.initalized.load(Ordering::SeqCst) { - unsafe { - self.data.get().write(MaybeUninit::new(value)); - } - self.initalized.store(true, Ordering::SeqCst); - } - - self.get() - } - - pub fn set(&self, value: T) -> Result<(), T> { - if self.initalized.load(Ordering::SeqCst) { - Err(value) - } else { - let _ = self.get_or_init(|| value); - Ok(()) - } +impl SusLock { + pub const fn new() -> SusLock { + SusLock { + initalized: AtomicBool::new(false), + data: UnsafeCell::new(MaybeUninit::uninit()), + _marker: PhantomData, } } - unsafe impl Sync for SusLock {} - unsafe impl Send for SusLock {} - impl RefUnwindSafe for SusLock {} - - impl Drop for SusLock { - fn drop(&mut self) { - if self.initalized.load(Ordering::SeqCst) { - unsafe { (&mut *self.data.get()).assume_init_drop() }; - } + pub fn get(&self) -> Option<&T> { + if self.initalized.load(Ordering::SeqCst) { + Some(unsafe { (&*self.data.get()).assume_init_ref() }) + } else { + return None; } } - static AHASH_SEED: SusLock> = SusLock::new(); + pub fn get_or_init(&self, f: impl FnOnce() -> T) -> Option<&T> { + let value = f(); + if !self.initalized.load(Ordering::SeqCst) { + unsafe { + self.data.get().write(MaybeUninit::new(value)); + } + self.initalized.store(true, Ordering::SeqCst); + } - // #[doc(cfg(feature = "stable_hash"))] - /// Sets the Rhai Ahash seed. This is used to hash functions and the like. - /// - /// This is a global variable, and thus will affect every Rhai instance. - /// This should not be used _unless_ you know you need it. - /// - /// # Warnings - /// - You can only call this function **ONCE** for the whole of your program execution. - /// - You should gracefully handle the `Err(())`. - /// - You **MUST** call this before **ANY** Rhai operation occurs (e.g. creating an [`Engine`]). - /// - /// # Errors - /// This will error if the AHashSeed is already set. - pub fn set_ahash_seed(new_seed: Option<[u64; 4]>) -> Result<(), Option<[u64; 4]>> { - AHASH_SEED.set(new_seed) + self.get() } - /// Gets the current Rhai Ahash Seed. If the seed is not yet defined, this will automatically set a seed. - /// The default seed is not stable and may change between versions. - /// - /// See [`set_rhai_ahash_seed`] for more. - pub fn get_ahash_seed() -> Option<[u64; 4]> { - const FUNNY_YUMENIKKI_REFERENCE: [u64; 4] = [236,800,954,213]; - - AHASH_SEED.get_or_init(|| Some(FUNNY_YUMENIKKI_REFERENCE)).map(|x| *x).flatten() + pub fn set(&self, value: T) -> Result<(), T> { + if self.initalized.load(Ordering::SeqCst) { + Err(value) + } else { + let _ = self.get_or_init(|| value); + Ok(()) + } } } -#[cfg(not(feature = "static_hash"))] -mod internal { - const AHASH_SEED: Option<[u64; 4]> = {{ AHASH_SEED }}; +unsafe impl Sync for SusLock {} +unsafe impl Send for SusLock {} +impl RefUnwindSafe for SusLock {} - /// Gets the current Rhai Ahash Seed. If the seed is not yet defined, this will automatically set a seed. - /// The default seed is not stable and may change between versions. - /// - /// See [`set_ahash_seed`] for more. - pub fn get_ahash_seed() -> Option<[u64; 4]> { - AHASH_SEED +impl Drop for SusLock { + fn drop(&mut self) { + if self.initalized.load(Ordering::SeqCst) { + unsafe { (&mut *self.data.get()).assume_init_drop() }; + } } -} \ No newline at end of file +} + +static AHASH_SEED: SusLock> = SusLock::new(); + +// #[doc(cfg(feature = "stable_hash"))] +/// Sets the Rhai Ahash seed. This is used to hash functions and the like. +/// +/// This is a global variable, and thus will affect every Rhai instance. +/// This should not be used _unless_ you know you need it. +/// +/// # Warnings +/// - You can only call this function **ONCE** for the whole of your program execution. +/// - You should gracefully handle the `Err(())`. +/// - You **MUST** call this before **ANY** Rhai operation occurs (e.g. creating an [`Engine`]). +/// +/// # Errors +/// This will error if the AHashSeed is already set. +pub fn set_ahash_seed(new_seed: Option<[u64; 4]>) -> Result<(), Option<[u64; 4]>> { + AHASH_SEED.set(new_seed) +} + +/// Gets the current Rhai Ahash Seed. If the seed is not yet defined, this will automatically set a seed. +/// The default seed is not stable and may change between versions. +/// +/// See [`set_rhai_ahash_seed`] for more. +pub fn get_ahash_seed() -> Option<[u64; 4]> { + const FUNNY_YUMENIKKI_REFERENCE: Option<[u64; 4]> = {{ AHASH_SEED }}; + + AHASH_SEED + .get_or_init(|| FUNNY_YUMENIKKI_REFERENCE) + .map(|x| *x) + .flatten() +} diff --git a/src/config/hashing.rs b/src/config/hashing.rs index 19423149..3f318fef 100644 --- a/src/config/hashing.rs +++ b/src/config/hashing.rs @@ -10,120 +10,103 @@ //! E.g. `env RHAI_AHASH_SEED ="[236,800,954,213]"` // [236,800,954,213], haha funny yume nikki reference epic uboachan face numberworld nexus moment 100 -pub use internal::get_ahash_seed; -#[cfg(feature = "static_hash")] -pub use internal::set_ahash_seed; +use core::{ + cell::UnsafeCell, + marker::PhantomData, + mem::MaybeUninit, + panic::{RefUnwindSafe, UnwindSafe}, + sync::atomic::{AtomicBool, Ordering}, +}; -#[cfg(feature = "static_hash")] -mod internal { - use core::{ - cell::UnsafeCell, - marker::PhantomData, - mem::MaybeUninit, - sync::atomic::{AtomicBool, Ordering}, - panic::{RefUnwindSafe, UnwindSafe} - }; +// Safety: lol +struct SusLock +where + T: 'static, +{ + initalized: AtomicBool, + data: UnsafeCell>, + _marker: PhantomData, +} - struct SusLock where T: 'static { - initalized: AtomicBool, - data: UnsafeCell>, - _marker: PhantomData, - } - - impl SusLock { - pub const fn new() -> SusLock { - SusLock { - initalized: AtomicBool::new(false), - data: UnsafeCell::new(MaybeUninit::uninit()), - _marker: PhantomData - } - } - - pub fn get(&self) -> Option<&T> { - if self.initalized.load(Ordering::SeqCst) { - Some( - unsafe { - (&*self.data.get()).assume_init_ref() - } - ) - } else { - return None - } - } - - pub fn get_or_init(&self, f: impl FnOnce() -> T) -> Option<&T> { - let value = f(); - if !self.initalized.load(Ordering::SeqCst) { - unsafe { - self.data.get().write(MaybeUninit::new(value)); - } - self.initalized.store(true, Ordering::SeqCst); - } - - self.get() - } - - pub fn set(&self, value: T) -> Result<(), T> { - if self.initalized.load(Ordering::SeqCst) { - Err(value) - } else { - let _ = self.get_or_init(|| value); - Ok(()) - } +impl SusLock { + pub const fn new() -> SusLock { + SusLock { + initalized: AtomicBool::new(false), + data: UnsafeCell::new(MaybeUninit::uninit()), + _marker: PhantomData, } } - unsafe impl Sync for SusLock {} - unsafe impl Send for SusLock {} - impl RefUnwindSafe for SusLock {} - - impl Drop for SusLock { - fn drop(&mut self) { - if self.initalized.load(Ordering::SeqCst) { - unsafe { (&mut *self.data.get()).assume_init_drop() }; - } + pub fn get(&self) -> Option<&T> { + if self.initalized.load(Ordering::SeqCst) { + Some(unsafe { (&*self.data.get()).assume_init_ref() }) + } else { + return None; } } - static AHASH_SEED: SusLock> = SusLock::new(); + pub fn get_or_init(&self, f: impl FnOnce() -> T) -> Option<&T> { + let value = f(); + if !self.initalized.load(Ordering::SeqCst) { + unsafe { + self.data.get().write(MaybeUninit::new(value)); + } + self.initalized.store(true, Ordering::SeqCst); + } - // #[doc(cfg(feature = "stable_hash"))] - /// Sets the Rhai Ahash seed. This is used to hash functions and the like. - /// - /// This is a global variable, and thus will affect every Rhai instance. - /// This should not be used _unless_ you know you need it. - /// - /// # Warnings - /// - You can only call this function **ONCE** for the whole of your program execution. - /// - You should gracefully handle the `Err(())`. - /// - You **MUST** call this before **ANY** Rhai operation occurs (e.g. creating an [`Engine`]). - /// - /// # Errors - /// This will error if the AHashSeed is already set. - pub fn set_ahash_seed(new_seed: Option<[u64; 4]>) -> Result<(), Option<[u64; 4]>> { - AHASH_SEED.set(new_seed) + self.get() } - /// Gets the current Rhai Ahash Seed. If the seed is not yet defined, this will automatically set a seed. - /// The default seed is not stable and may change between versions. - /// - /// See [`set_rhai_ahash_seed`] for more. - pub fn get_ahash_seed() -> Option<[u64; 4]> { - const FUNNY_YUMENIKKI_REFERENCE: [u64; 4] = [236,800,954,213]; - - AHASH_SEED.get_or_init(|| Some(FUNNY_YUMENIKKI_REFERENCE)).map(|x| *x).flatten() + pub fn set(&self, value: T) -> Result<(), T> { + if self.initalized.load(Ordering::SeqCst) { + Err(value) + } else { + let _ = self.get_or_init(|| value); + Ok(()) + } } } -#[cfg(not(feature = "static_hash"))] -mod internal { - const AHASH_SEED: Option<[u64; 4]> = None; +unsafe impl Sync for SusLock {} +unsafe impl Send for SusLock {} +impl RefUnwindSafe for SusLock {} - /// Gets the current Rhai Ahash Seed. If the seed is not yet defined, this will automatically set a seed. - /// The default seed is not stable and may change between versions. - /// - /// See [`set_ahash_seed`] for more. - pub fn get_ahash_seed() -> Option<[u64; 4]> { - AHASH_SEED +impl Drop for SusLock { + fn drop(&mut self) { + if self.initalized.load(Ordering::SeqCst) { + unsafe { (&mut *self.data.get()).assume_init_drop() }; + } } -} \ No newline at end of file +} + +static AHASH_SEED: SusLock> = SusLock::new(); + +// #[doc(cfg(feature = "stable_hash"))] +/// Sets the Rhai Ahash seed. This is used to hash functions and the like. +/// +/// This is a global variable, and thus will affect every Rhai instance. +/// This should not be used _unless_ you know you need it. +/// +/// # Warnings +/// - You can only call this function **ONCE** for the whole of your program execution. +/// - You should gracefully handle the `Err(())`. +/// - You **MUST** call this before **ANY** Rhai operation occurs (e.g. creating an [`Engine`]). +/// +/// # Errors +/// This will error if the AHashSeed is already set. +pub fn set_ahash_seed(new_seed: Option<[u64; 4]>) -> Result<(), Option<[u64; 4]>> { + AHASH_SEED.set(new_seed) +} + +/// Gets the current Rhai Ahash Seed. If the seed is not yet defined, this will automatically set a seed. +/// The default seed is not stable and may change between versions. +/// +/// See [`set_rhai_ahash_seed`] for more. +pub fn get_ahash_seed() -> Option<[u64; 4]> { + const FUNNY_YUMENIKKI_REFERENCE: Option<[u64; 4]> = None; + + AHASH_SEED + .get_or_init(|| FUNNY_YUMENIKKI_REFERENCE) + .map(|x| *x) + .flatten() +} diff --git a/src/config/mod.rs b/src/config/mod.rs index 194ac6da..e2748d4a 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -1,3 +1,3 @@ //! Contains Configuration for Rhai. -pub mod hashing; \ No newline at end of file +pub mod hashing; From 80fef5a01cfab4067a85f487adc1c4a32bf8db1a Mon Sep 17 00:00:00 2001 From: l1npengtul Date: Tue, 1 Nov 2022 22:42:35 +0900 Subject: [PATCH 09/10] remove static hash from CI --- .github/workflows/build.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index fc782151..cf7f1f7b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -44,7 +44,7 @@ jobs: flags: - "" - "--features debugging" - - "--features metadata,serde,internals,static_hash" + - "--features metadata,serde,internals" - "--features unchecked,serde,metadata,internals,debugging" - "--features sync,serde,metadata,internals,debugging" - "--features no_position,serde,metadata,internals,debugging" @@ -129,7 +129,6 @@ jobs: matrix: flags: - "" - - "--features static_hash" include: - {os: ubuntu-latest, flags: "--profile unix", experimental: false} - {os: windows-latest, flags: "--profile windows", experimental: true} From 36edc445d1afc79493092506badbc2fa713df619 Mon Sep 17 00:00:00 2001 From: l1npengtul Date: Fri, 4 Nov 2022 15:36:18 +0900 Subject: [PATCH 10/10] fix build.yml, concurrency concerns, build.rs concerns --- .github/workflows/build.yml | 31 ---------- build.rs | 6 +- build.template | 114 +----------------------------------- src/config/hashing.rs | 109 ++++++++++++++++++++++++++++------ src/config/hashing_env.rs | 2 + src/config/mod.rs | 1 + 6 files changed, 98 insertions(+), 165 deletions(-) create mode 100644 src/config/hashing_env.rs diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index cf7f1f7b..d186abb9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -89,37 +89,6 @@ jobs: command: test args: ${{matrix.flags}} -# nightly_features_build: -# name: NightlyFeatureBuild -# runs-on: ${{matrix.os}} -# continue-on-error: ${{matrix.experimental}} -# strategy: -# matrix: -# os: [ubuntu-latest] -# flags: -# - "--features stable_hash" -# toolchain: [ nightly ] -# experimental: [ false ] -# include: -# # smoketests for different toolchains -# - { toolchain: nightly, os: windows-latest, experimental: false, flags: "" } -# - { toolchain: nightly, os: macos-latest, experimental: false, flags: "" } -# fail-fast: false -# steps: -# - name: Checkout -# uses: actions/checkout@v2 -# - name: Setup Toolchain -# uses: actions-rs/toolchain@v1 -# with: -# toolchain: ${{matrix.toolchain}} -# override: true -# - name: Test -# uses: actions-rs/cargo@v1 -# with: -# command: test -# args: ${{matrix.flags}} - - # no-std builds are a bit more extensive to test no_std_build: name: NoStdBuild diff --git a/build.rs b/build.rs index e95b1dc3..39c11238 100644 --- a/build.rs +++ b/build.rs @@ -17,10 +17,10 @@ fn main() { let seed = env::var("RHAI_AHASH_SEED").map_or_else(|_| "None".into(), |s| format!("Some({s})")); - contents = contents.replace("{{ AHASH_SEED }}", &seed); + contents = contents.replace("{{AHASH_SEED}}", &seed); - File::create("src/config/hashing.rs") + File::create("src/config/hashing_env.rs") .expect("cannot create `config.rs`") .write_all(contents.as_bytes()) - .expect("cannot write to `config/hashing.rs`"); + .expect("cannot write to `config/hashing_env.rs`"); } diff --git a/build.template b/build.template index 89b0e403..a165e5ed 100644 --- a/build.template +++ b/build.template @@ -1,112 +1,2 @@ -//! Fixed hashing seeds for stable hashing. -//! -//! Set to [`None`] to disable stable hashing. -//! -//! See [`set_rhai_ahash_seed`] for more. -//! -//! Alternatively, You can also set this at compile time by disabling `stable_hash` and setting the `RHAI_AHASH_SEED` -//! environment variable instead. -//! -//! E.g. `env RHAI_AHASH_SEED ="[236,800,954,213]"` -// [236,800,954,213], haha funny yume nikki reference epic uboachan face numberworld nexus moment 100 - -use core::{ - cell::UnsafeCell, - marker::PhantomData, - mem::MaybeUninit, - panic::{RefUnwindSafe, UnwindSafe}, - sync::atomic::{AtomicBool, Ordering}, -}; - -// Safety: lol -struct SusLock -where - T: 'static, -{ - initalized: AtomicBool, - data: UnsafeCell>, - _marker: PhantomData, -} - -impl SusLock { - pub const fn new() -> SusLock { - SusLock { - initalized: AtomicBool::new(false), - data: UnsafeCell::new(MaybeUninit::uninit()), - _marker: PhantomData, - } - } - - pub fn get(&self) -> Option<&T> { - if self.initalized.load(Ordering::SeqCst) { - Some(unsafe { (&*self.data.get()).assume_init_ref() }) - } else { - return None; - } - } - - pub fn get_or_init(&self, f: impl FnOnce() -> T) -> Option<&T> { - let value = f(); - if !self.initalized.load(Ordering::SeqCst) { - unsafe { - self.data.get().write(MaybeUninit::new(value)); - } - self.initalized.store(true, Ordering::SeqCst); - } - - self.get() - } - - pub fn set(&self, value: T) -> Result<(), T> { - if self.initalized.load(Ordering::SeqCst) { - Err(value) - } else { - let _ = self.get_or_init(|| value); - Ok(()) - } - } -} - -unsafe impl Sync for SusLock {} -unsafe impl Send for SusLock {} -impl RefUnwindSafe for SusLock {} - -impl Drop for SusLock { - fn drop(&mut self) { - if self.initalized.load(Ordering::SeqCst) { - unsafe { (&mut *self.data.get()).assume_init_drop() }; - } - } -} - -static AHASH_SEED: SusLock> = SusLock::new(); - -// #[doc(cfg(feature = "stable_hash"))] -/// Sets the Rhai Ahash seed. This is used to hash functions and the like. -/// -/// This is a global variable, and thus will affect every Rhai instance. -/// This should not be used _unless_ you know you need it. -/// -/// # Warnings -/// - You can only call this function **ONCE** for the whole of your program execution. -/// - You should gracefully handle the `Err(())`. -/// - You **MUST** call this before **ANY** Rhai operation occurs (e.g. creating an [`Engine`]). -/// -/// # Errors -/// This will error if the AHashSeed is already set. -pub fn set_ahash_seed(new_seed: Option<[u64; 4]>) -> Result<(), Option<[u64; 4]>> { - AHASH_SEED.set(new_seed) -} - -/// Gets the current Rhai Ahash Seed. If the seed is not yet defined, this will automatically set a seed. -/// The default seed is not stable and may change between versions. -/// -/// See [`set_rhai_ahash_seed`] for more. -pub fn get_ahash_seed() -> Option<[u64; 4]> { - const FUNNY_YUMENIKKI_REFERENCE: Option<[u64; 4]> = {{ AHASH_SEED }}; - - AHASH_SEED - .get_or_init(|| FUNNY_YUMENIKKI_REFERENCE) - .map(|x| *x) - .flatten() -} +// This file is automatically set during build time by build.rs and build.template. +pub(crate) const AHASH_SEED: Option<[u64; 4]> = {{AHASH_SEED}}; diff --git a/src/config/hashing.rs b/src/config/hashing.rs index 3f318fef..2355a405 100644 --- a/src/config/hashing.rs +++ b/src/config/hashing.rs @@ -4,31 +4,94 @@ //! //! See [`set_rhai_ahash_seed`] for more. //! -//! Alternatively, You can also set this at compile time by disabling `stable_hash` and setting the `RHAI_AHASH_SEED` +//! Alternatively, You can also set this at compile time by setting the `RHAI_AHASH_SEED` //! environment variable instead. //! //! E.g. `env RHAI_AHASH_SEED ="[236,800,954,213]"` // [236,800,954,213], haha funny yume nikki reference epic uboachan face numberworld nexus moment 100 +use crate::config::hashing_env; use core::{ cell::UnsafeCell, marker::PhantomData, mem::MaybeUninit, panic::{RefUnwindSafe, UnwindSafe}, - sync::atomic::{AtomicBool, Ordering}, + sync::atomic::{AtomicBool, AtomicUsize, Ordering}, }; -// Safety: lol +// omg its hokma from record team here to record our locks +// what does this do? +// so what this does is keep track of a global address in memory that acts as a global lock +// i stole this from crossbeam so read their docs for more +struct HokmaLock { + lock: AtomicUsize, +} + +impl HokmaLock { + pub const fn new() -> Self { + Self { + lock: AtomicUsize::new(0), + } + } + + pub fn write(&'static self) -> WhenTheHokmaSupression { + loop { + let previous = self.lock.swap(1, Ordering::SeqCst); + + if previous != 1 { + return WhenTheHokmaSupression { + hokma: self, + state: previous, + }; + } + } + } +} + +struct WhenTheHokmaSupression { + hokma: &'static HokmaLock, + + state: usize, +} + +impl WhenTheHokmaSupression { + pub fn the_price_of_silence(self) { + self.hokma.lock.store(self.state, Ordering::SeqCst); + + core::mem::forget(self) + } +} + +impl Drop for WhenTheHokmaSupression { + fn drop(&mut self) { + self.hokma + .lock + .store(self.state.wrapping_add(2), Ordering::SeqCst) + } +} + +fn hokmalock(address: usize) -> &'static HokmaLock { + const LEN: usize = 787; + const LCK: HokmaLock = HokmaLock::new(); + static RECORDS: [HokmaLock; LEN] = [LCK; LEN]; + + &RECORDS[address % LEN] +} + +// Safety: lol, there is a reason its called "SusLock" struct SusLock where - T: 'static, + T: 'static + Copy, { initalized: AtomicBool, data: UnsafeCell>, _marker: PhantomData, } -impl SusLock { +impl SusLock +where + T: 'static + Copy, +{ pub const fn new() -> SusLock { SusLock { initalized: AtomicBool::new(false), @@ -37,21 +100,31 @@ impl SusLock { } } - pub fn get(&self) -> Option<&T> { + pub fn get(&self) -> Option { if self.initalized.load(Ordering::SeqCst) { - Some(unsafe { (&*self.data.get()).assume_init_ref() }) + let hokma = hokmalock(unsafe { core::mem::transmute(self.data.get()) }); + // we forgo the optimistic read, because we don't really care + let guard = hokma.write(); + let val = { + let cast: *const T = self.data.get().cast(); + unsafe { cast.read() } + }; + guard.the_price_of_silence(); + Some(val) } else { return None; } } - pub fn get_or_init(&self, f: impl FnOnce() -> T) -> Option<&T> { + pub fn get_or_init(&self, f: impl FnOnce() -> T) -> Option { let value = f(); if !self.initalized.load(Ordering::SeqCst) { + self.initalized.store(true, Ordering::SeqCst); + let hokma = hokmalock(unsafe { core::mem::transmute(self.data.get()) }); + hokma.write(); unsafe { self.data.get().write(MaybeUninit::new(value)); } - self.initalized.store(true, Ordering::SeqCst); } self.get() @@ -67,11 +140,14 @@ impl SusLock { } } -unsafe impl Sync for SusLock {} -unsafe impl Send for SusLock {} -impl RefUnwindSafe for SusLock {} +unsafe impl Sync for SusLock where T: 'static + Copy {} +unsafe impl Send for SusLock where T: 'static + Copy {} +impl RefUnwindSafe for SusLock where T: 'static + Copy {} -impl Drop for SusLock { +impl Drop for SusLock +where + T: 'static + Copy, +{ fn drop(&mut self) { if self.initalized.load(Ordering::SeqCst) { unsafe { (&mut *self.data.get()).assume_init_drop() }; @@ -103,10 +179,5 @@ pub fn set_ahash_seed(new_seed: Option<[u64; 4]>) -> Result<(), Option<[u64; 4]> /// /// See [`set_rhai_ahash_seed`] for more. pub fn get_ahash_seed() -> Option<[u64; 4]> { - const FUNNY_YUMENIKKI_REFERENCE: Option<[u64; 4]> = None; - - AHASH_SEED - .get_or_init(|| FUNNY_YUMENIKKI_REFERENCE) - .map(|x| *x) - .flatten() + AHASH_SEED.get_or_init(|| hashing_env::AHASH_SEED).flatten() } diff --git a/src/config/hashing_env.rs b/src/config/hashing_env.rs new file mode 100644 index 00000000..ee2b35db --- /dev/null +++ b/src/config/hashing_env.rs @@ -0,0 +1,2 @@ +// This file is automatically set during build time by build.rs and build.template. +pub(crate) const AHASH_SEED: Option<[u64; 4]> = None; diff --git a/src/config/mod.rs b/src/config/mod.rs index e2748d4a..db5448f6 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -1,3 +1,4 @@ //! Contains Configuration for Rhai. pub mod hashing; +mod hashing_env;