Address concerns

This commit is contained in:
l1npengtul 2022-11-01 00:59:07 +09:00
parent 87e51cb8fe
commit bb01f914e0
9 changed files with 404 additions and 124 deletions

View File

@ -44,7 +44,7 @@ jobs:
flags: flags:
- "" - ""
- "--features debugging" - "--features debugging"
- "--features metadata,serde,internals" - "--features metadata,serde,internals,static_hash"
- "--features unchecked,serde,metadata,internals,debugging" - "--features unchecked,serde,metadata,internals,debugging"
- "--features sync,serde,metadata,internals,debugging" - "--features sync,serde,metadata,internals,debugging"
- "--features no_position,serde,metadata,internals,debugging" - "--features no_position,serde,metadata,internals,debugging"
@ -89,35 +89,35 @@ jobs:
command: test command: test
args: ${{matrix.flags}} args: ${{matrix.flags}}
nightly_features_build: # nightly_features_build:
name: NightlyFeatureBuild # name: NightlyFeatureBuild
runs-on: ${{matrix.os}} # runs-on: ${{matrix.os}}
continue-on-error: ${{matrix.experimental}} # continue-on-error: ${{matrix.experimental}}
strategy: # strategy:
matrix: # matrix:
os: [ubuntu-latest] # os: [ubuntu-latest]
flags: # flags:
- "--features stable_hash" # - "--features stable_hash"
toolchain: [ nightly ] # toolchain: [ nightly ]
experimental: [ false ] # experimental: [ false ]
include: # include:
# smoketests for different toolchains # # smoketests for different toolchains
- { toolchain: nightly, os: windows-latest, experimental: false, flags: "" } # - { toolchain: nightly, os: windows-latest, experimental: false, flags: "" }
- { toolchain: nightly, os: macos-latest, experimental: false, flags: "" } # - { toolchain: nightly, os: macos-latest, experimental: false, flags: "" }
fail-fast: false # fail-fast: false
steps: # steps:
- name: Checkout # - name: Checkout
uses: actions/checkout@v2 # uses: actions/checkout@v2
- name: Setup Toolchain # - name: Setup Toolchain
uses: actions-rs/toolchain@v1 # uses: actions-rs/toolchain@v1
with: # with:
toolchain: ${{matrix.toolchain}} # toolchain: ${{matrix.toolchain}}
override: true # override: true
- name: Test # - name: Test
uses: actions-rs/cargo@v1 # uses: actions-rs/cargo@v1
with: # with:
command: test # command: test
args: ${{matrix.flags}} # args: ${{matrix.flags}}
# no-std builds are a bit more extensive to test # no-std builds are a bit more extensive to test
@ -127,6 +127,9 @@ jobs:
continue-on-error: ${{matrix.experimental}} continue-on-error: ${{matrix.experimental}}
strategy: strategy:
matrix: matrix:
flags:
- ""
- "--features static_hash"
include: include:
- {os: ubuntu-latest, flags: "--profile unix", experimental: false} - {os: ubuntu-latest, flags: "--profile unix", experimental: false}
- {os: windows-latest, flags: "--profile windows", experimental: true} - {os: windows-latest, flags: "--profile windows", experimental: true}

View File

@ -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 metadata = ["serde", "serde_json", "rhai_codegen/metadata", "smartstring/serde"] # enable exporting functions metadata
internals = [] # expose internal data structures internals = [] # expose internal data structures
debugging = ["internals"] # enable debugging debugging = ["internals"] # enable debugging
stable_hash = ["std"] static_hash = []
serde = ["dep:serde", "smartstring/serde", "smallvec/serde"] # implement serde for rhai types serde = ["dep:serde", "smartstring/serde", "smallvec/serde"] # implement serde for rhai types
# compiling for no-std # compiling for no-std

View File

@ -20,9 +20,9 @@ fn main() {
contents = contents.replace("{{AHASH_SEED}}", &seed); contents = contents.replace("{{AHASH_SEED}}", &seed);
File::create("src/config.rs") File::create("src/config/hashing.rs")
.expect("cannot create `config.rs`") .expect("cannot create `config.rs`")
.write_all(contents.as_bytes()) .write_all(contents.as_bytes())
.expect("cannot write to `config.rs`"); .expect("cannot write to `config/hashing.rs`");
} }
} }

View File

@ -1,60 +1,129 @@
#[cfg(feature = "stable_hash")] //! Fixed hashing seeds for stable hashing.
use core::cell::OnceCell; //!
//! 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"))] #[cfg(feature = "static_hash")]
/// Fixed hashing seeds for stable hashing. mod internal {
/// use core::{
/// Set to [`None`] to disable stable hashing. cell::UnsafeCell,
/// marker::PhantomData,
/// See [`set_rhai_ahash_seed`] for more. mem::MaybeUninit,
/// sync::atomic::{AtomicBool, Ordering},
/// You can also set this at compile time by disabling `stable_hash` and setting the `RHAI_AHASH_SEED` panic::{RefUnwindSafe, UnwindSafe}
/// 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<Option<[u64; 4]>> = OnceCell::new();
#[cfg(feature = "stable_hash")] struct SusLock<T> where T: 'static {
#[doc(cfg(feature = "stable_hash"))] initalized: AtomicBool,
/// Sets the Rhai Ahash seed. This is used to hash functions and the like. data: UnsafeCell<MaybeUninit<T>>,
/// _marker: PhantomData<T>,
/// This is a global variable, and thus will affect every Rhai instance. }
/// This should not be used _unless_ you know you need it.
/// impl<T> SusLock<T> {
/// **WARNING**: pub const fn new() -> SusLock<T> {
/// - You can only call this function **ONCE** for the whole of your program execution. SusLock {
/// - You should gracefully handle the `Err(())`. initalized: AtomicBool::new(false),
/// - You **MUST** call this before **ANY** Rhai operation occurs (e.g. creating an [`Engine`]). data: UnsafeCell::new(MaybeUninit::uninit()),
pub fn set_rhai_ahash_seed(new_seed: Option<[u64; 4]>) -> Result<(), Option<[u64; 4]>> { _marker: PhantomData
AHASH_SEED.set(new_seed) }
}
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<T: Sync + Send> Sync for SusLock<T> {}
unsafe impl<T: Send> Send for SusLock<T> {}
impl<T: RefUnwindSafe + UnwindSafe> RefUnwindSafe for SusLock<T> {}
impl<T> Drop for SusLock<T> {
fn drop(&mut self) {
if self.initalized.load(Ordering::SeqCst) {
unsafe { (&mut *self.data.get()).assume_init_drop() };
}
}
}
static AHASH_SEED: SusLock<Option<[u64; 4]>> = 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")] #[cfg(not(feature = "static_hash"))]
/// Gets the current Rhai Ahash Seed. mod internal {
/// const AHASH_SEED: Option<[u64; 4]> = {{ 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. If the seed is not yet defined, this will automatically set a seed.
/// Gets the current Rhai Ahash Seed. /// The default seed is not stable and may change between versions.
/// ///
/// See [`AHASH_SEED`] and [`set_rhai_ahash_seed`] for more. /// See [`set_ahash_seed`] for more.
pub fn get_rhai_ahash_seed() -> Option<[u64; 4]> { pub fn get_ahash_seed() -> Option<[u64; 4]> {
AHASH_SEED AHASH_SEED
}
} }

View File

@ -10,44 +10,120 @@
//! E.g. `env RHAI_AHASH_SEED ="[236,800,954,213]"` //! 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 epic uboachan face numberworld nexus moment 100
#[cfg(feature = "stable_hash")] pub use internal::get_ahash_seed;
use std::sync::OnceLock; #[cfg(feature = "static_hash")]
pub use internal::set_ahash_seed;
#[cfg(not(feature = "stable_hash"))] #[cfg(feature = "static_hash")]
const AHASH_SEED: Option<[u64; 4]> = None; mod internal {
#[cfg(feature = "stable_hash")] use core::{
static AHASH_SEED: OnceLock<Option<[u64; 4]>> = OnceLock::new(); cell::UnsafeCell,
marker::PhantomData,
mem::MaybeUninit,
sync::atomic::{AtomicBool, Ordering},
panic::{RefUnwindSafe, UnwindSafe}
};
#[cfg(feature = "stable_hash")] struct SusLock<T> where T: 'static {
// #[doc(cfg(feature = "stable_hash"))] initalized: AtomicBool,
/// Sets the Rhai Ahash seed. This is used to hash functions and the like. data: UnsafeCell<MaybeUninit<T>>,
/// _marker: PhantomData<T>,
/// This is a global variable, and thus will affect every Rhai instance. }
/// This should not be used _unless_ you know you need it.
/// impl<T> SusLock<T> {
/// # Warning: pub const fn new() -> SusLock<T> {
/// - You can only call this function **ONCE** for the whole of your program execution. SusLock {
/// - You should gracefully handle the `Err(())`. initalized: AtomicBool::new(false),
/// - You **MUST** call this before **ANY** Rhai operation occurs (e.g. creating an [`Engine`]). data: UnsafeCell::new(MaybeUninit::uninit()),
/// _marker: PhantomData
/// # 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) 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<T: Sync + Send> Sync for SusLock<T> {}
unsafe impl<T: Send> Send for SusLock<T> {}
impl<T: RefUnwindSafe + UnwindSafe> RefUnwindSafe for SusLock<T> {}
impl<T> Drop for SusLock<T> {
fn drop(&mut self) {
if self.initalized.load(Ordering::SeqCst) {
unsafe { (&mut *self.data.get()).assume_init_drop() };
}
}
}
static AHASH_SEED: SusLock<Option<[u64; 4]>> = 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")] #[cfg(not(feature = "static_hash"))]
/// Gets the current Rhai Ahash Seed. mod internal {
/// const AHASH_SEED: Option<[u64; 4]> = {{ 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. If the seed is not yet defined, this will automatically set a seed.
/// Gets the current Rhai Ahash Seed. /// The default seed is not stable and may change between versions.
/// ///
/// See [`AHASH_SEED`] and [`set_rhai_ahash_seed`] for more. /// See [`set_ahash_seed`] for more.
pub fn get_rhai_ahash_seed() -> Option<[u64; 4]> { pub fn get_ahash_seed() -> Option<[u64; 4]> {
AHASH_SEED AHASH_SEED
} }
}

129
src/config/hashing.rs Normal file
View File

@ -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<T> where T: 'static {
initalized: AtomicBool,
data: UnsafeCell<MaybeUninit<T>>,
_marker: PhantomData<T>,
}
impl<T> SusLock<T> {
pub const fn new() -> SusLock<T> {
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<T: Sync + Send> Sync for SusLock<T> {}
unsafe impl<T: Send> Send for SusLock<T> {}
impl<T: RefUnwindSafe + UnwindSafe> RefUnwindSafe for SusLock<T> {}
impl<T> Drop for SusLock<T> {
fn drop(&mut self) {
if self.initalized.load(Ordering::SeqCst) {
unsafe { (&mut *self.data.get()).assume_init_drop() };
}
}
}
static AHASH_SEED: SusLock<Option<[u64; 4]>> = 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
}
}

3
src/config/mod.rs Normal file
View File

@ -0,0 +1,3 @@
//! Contains Configuration for Rhai.
pub mod hashing;

View File

@ -77,7 +77,7 @@ impl BuildHasher for StraightHasherBuilder {
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn get_hasher() -> ahash::AHasher { 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 => { Some([seed1, seed2, seed3, seed4]) if seed1 | seed2 | seed3 | seed4 != 0 => {
ahash::RandomState::with_seeds(seed1, seed2, seed3, seed4).build_hasher() ahash::RandomState::with_seeds(seed1, seed2, seed3, seed4).build_hasher()
} }

View File

@ -71,7 +71,7 @@
#![allow(clippy::negative_feature_names)] #![allow(clippy::negative_feature_names)]
#![allow(clippy::module_inception)] #![allow(clippy::module_inception)]
#![cfg_attr(feature = "stable_hash", feature(once_cell))] #![cfg_attr(feature = "static_hash", feature(once_cell))]
#[cfg(feature = "no_std")] #[cfg(feature = "no_std")]
extern crate alloc; extern crate alloc;