Minor stylistic fixes.

This commit is contained in:
Stephen Chung 2022-11-04 21:22:31 +08:00
parent ed971df8f3
commit d2cd70bf53
5 changed files with 79 additions and 39 deletions

View File

@ -26,11 +26,11 @@ New features
* Normal loops return `()` as the value. * Normal loops return `()` as the value.
* Loop expressions can be enabled/disabled via `Engine::set_allow_loop_expressions` * Loop expressions can be enabled/disabled via `Engine::set_allow_loop_expressions`
### Stable hashing ### Static hashing
* It is now possible to specify a fixed _seed_ for use with the `ahash` hasher, via an environment variable, in order to force stable (i.e. deterministic) hashes for function signatures. * It is now possible to specify a fixed _seed_ for use with the `ahash` hasher, via a static function `rhai::config::hashing::set_ahash_seed` or an environment variable, in order to force static (i.e. deterministic) hashes for function signatures.
* This is necessary when using Rhai across shared-library boundaries. * This is necessary when using Rhai across shared-library boundaries.
* A build script is used to extract the environment variable (`RHAI_AHASH_SEED`) and splice it into the source code before compilation. * A build script is used to extract the environment variable (`RHAI_AHASH_SEED`, if any) and splice it into the source code before compilation.
### No Timestamps ### No Timestamps

View File

@ -1,2 +1,3 @@
// This file is automatically set during build time by build.rs and build.template. //! This file is automatically recreated during build time by `build.rs` from `build.template`.
pub(crate) const AHASH_SEED: Option<[u64; 4]> = {{AHASH_SEED}}; pub(crate) const AHASH_SEED: Option<[u64; 4]> = {{AHASH_SEED}};

View File

@ -2,18 +2,30 @@
//! //!
//! Set to [`None`] to disable stable hashing. //! Set to [`None`] to disable stable hashing.
//! //!
//! See [`set_rhai_ahash_seed`] for more. //! See [`set_rhai_ahash_seed`].
//! //!
//! Alternatively, You can also set this at compile time by setting the `RHAI_AHASH_SEED` //! # Example
//! environment variable instead.
//! //!
//! E.g. `env RHAI_AHASH_SEED ="[236,800,954,213]"` //! ```rust
//! // Set the hashing seed to [1, 2, 3, 4]
//! rhai::config::hashing::set_ahash_seed(Some([1, 2, 3, 4])).unwrap();
//! ```
//! Alternatively, set this at compile time via the `RHAI_AHASH_SEED` environment variable.
//!
//! # Example
//!
//! ```sh
//! 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
use crate::config::hashing_env; use crate::config::hashing_env;
use core::{ #[cfg(feature = "no_std")]
use std::prelude::v1::*;
use std::{
cell::UnsafeCell, cell::UnsafeCell,
marker::PhantomData, marker::PhantomData,
mem,
mem::MaybeUninit, mem::MaybeUninit,
panic::{RefUnwindSafe, UnwindSafe}, panic::{RefUnwindSafe, UnwindSafe},
sync::atomic::{AtomicBool, AtomicUsize, Ordering}, sync::atomic::{AtomicBool, AtomicUsize, Ordering},
@ -23,23 +35,25 @@ use core::{
// what does this do? // what does this do?
// so what this does is keep track of a global address in memory that acts as a global lock // 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 // i stole this from crossbeam so read their docs for more
#[must_use]
struct HokmaLock { struct HokmaLock {
lock: AtomicUsize, lock: AtomicUsize,
} }
impl HokmaLock { impl HokmaLock {
#[inline(always)]
pub const fn new() -> Self { pub const fn new() -> Self {
Self { Self {
lock: AtomicUsize::new(0), lock: AtomicUsize::new(0),
} }
} }
pub fn write(&'static self) -> WhenTheHokmaSupression { pub fn write(&'static self) -> WhenTheHokmaSuppression {
loop { loop {
let previous = self.lock.swap(1, Ordering::SeqCst); let previous = self.lock.swap(1, Ordering::SeqCst);
if previous != 1 { if previous != 1 {
return WhenTheHokmaSupression { return WhenTheHokmaSuppression {
hokma: self, hokma: self,
state: previous, state: previous,
}; };
@ -48,21 +62,21 @@ impl HokmaLock {
} }
} }
struct WhenTheHokmaSupression { struct WhenTheHokmaSuppression {
hokma: &'static HokmaLock, hokma: &'static HokmaLock,
state: usize, state: usize,
} }
impl WhenTheHokmaSupression { impl WhenTheHokmaSuppression {
#[inline]
pub fn the_price_of_silence(self) { pub fn the_price_of_silence(self) {
self.hokma.lock.store(self.state, Ordering::SeqCst); self.hokma.lock.store(self.state, Ordering::SeqCst);
mem::forget(self)
core::mem::forget(self)
} }
} }
impl Drop for WhenTheHokmaSupression { impl Drop for WhenTheHokmaSuppression {
#[inline]
fn drop(&mut self) { fn drop(&mut self) {
self.hokma self.hokma
.lock .lock
@ -70,6 +84,8 @@ impl Drop for WhenTheHokmaSupression {
} }
} }
#[inline(always)]
#[must_use]
fn hokmalock(address: usize) -> &'static HokmaLock { fn hokmalock(address: usize) -> &'static HokmaLock {
const LEN: usize = 787; const LEN: usize = 787;
const LCK: HokmaLock = HokmaLock::new(); const LCK: HokmaLock = HokmaLock::new();
@ -79,11 +95,12 @@ fn hokmalock(address: usize) -> &'static HokmaLock {
} }
// Safety: lol, there is a reason its called "SusLock<T>" // Safety: lol, there is a reason its called "SusLock<T>"
#[must_use]
struct SusLock<T> struct SusLock<T>
where where
T: 'static + Copy, T: 'static + Copy,
{ {
initalized: AtomicBool, initialized: AtomicBool,
data: UnsafeCell<MaybeUninit<T>>, data: UnsafeCell<MaybeUninit<T>>,
_marker: PhantomData<T>, _marker: PhantomData<T>,
} }
@ -92,17 +109,19 @@ impl<T> SusLock<T>
where where
T: 'static + Copy, T: 'static + Copy,
{ {
#[inline]
pub const fn new() -> SusLock<T> { pub const fn new() -> SusLock<T> {
SusLock { SusLock {
initalized: AtomicBool::new(false), initialized: AtomicBool::new(false),
data: UnsafeCell::new(MaybeUninit::uninit()), data: UnsafeCell::new(MaybeUninit::uninit()),
_marker: PhantomData, _marker: PhantomData,
} }
} }
#[must_use]
pub fn get(&self) -> Option<T> { pub fn get(&self) -> Option<T> {
if self.initalized.load(Ordering::SeqCst) { if self.initialized.load(Ordering::SeqCst) {
let hokma = hokmalock(unsafe { core::mem::transmute(self.data.get()) }); let hokma = hokmalock(unsafe { mem::transmute(self.data.get()) });
// we forgo the optimistic read, because we don't really care // we forgo the optimistic read, because we don't really care
let guard = hokma.write(); let guard = hokma.write();
let val = { let val = {
@ -116,11 +135,12 @@ where
} }
} }
#[must_use]
pub fn get_or_init(&self, f: impl FnOnce() -> T) -> Option<T> { pub fn get_or_init(&self, f: impl FnOnce() -> T) -> Option<T> {
let value = f(); let value = f();
if !self.initalized.load(Ordering::SeqCst) { if !self.initialized.load(Ordering::SeqCst) {
self.initalized.store(true, Ordering::SeqCst); self.initialized.store(true, Ordering::SeqCst);
let hokma = hokmalock(unsafe { core::mem::transmute(self.data.get()) }); let hokma = hokmalock(unsafe { mem::transmute(self.data.get()) });
hokma.write(); hokma.write();
unsafe { unsafe {
self.data.get().write(MaybeUninit::new(value)); self.data.get().write(MaybeUninit::new(value));
@ -131,7 +151,7 @@ where
} }
pub fn set(&self, value: T) -> Result<(), T> { pub fn set(&self, value: T) -> Result<(), T> {
if self.initalized.load(Ordering::SeqCst) { if self.initialized.load(Ordering::SeqCst) {
Err(value) Err(value)
} else { } else {
let _ = self.get_or_init(|| value); let _ = self.get_or_init(|| value);
@ -148,8 +168,9 @@ impl<T> Drop for SusLock<T>
where where
T: 'static + Copy, T: 'static + Copy,
{ {
#[inline]
fn drop(&mut self) { fn drop(&mut self) {
if self.initalized.load(Ordering::SeqCst) { if self.initialized.load(Ordering::SeqCst) {
unsafe { (&mut *self.data.get()).assume_init_drop() }; unsafe { (&mut *self.data.get()).assume_init_drop() };
} }
} }
@ -157,27 +178,44 @@ where
static AHASH_SEED: SusLock<Option<[u64; 4]>> = SusLock::new(); static AHASH_SEED: SusLock<Option<[u64; 4]>> = SusLock::new();
// #[doc(cfg(feature = "stable_hash"))] /// Set the hashing seed. This is used to hash functions etc.
/// 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 is a static global value and affects every Rhai instance.
/// This should not be used _unless_ you know you need it. /// This should not be used _unless_ you know you need it.
/// ///
/// # Warnings /// # 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 /// * You can only call this function **ONCE** for the entire duration of program execution.
/// This will error if the AHashSeed is already set. /// * You **MUST** call this before performing **ANY** Rhai operation (e.g. creating an [`Engine`]).
///
/// # Error
///
/// Returns an error containing the existing hashing seed if already set.
///
/// # Example
///
/// ```rust
/// # use rhai::Engine;
/// // Set the hashing seed to [1, 2, 3, 4]
/// rhai::config::hashing::set_ahash_seed(Some([1, 2, 3, 4])).unwrap();
///
/// // Use Rhai AFTER setting the hashing seed
/// let engine = Engine::new();
/// ```
#[inline(always)]
pub fn set_ahash_seed(new_seed: Option<[u64; 4]>) -> Result<(), Option<[u64; 4]>> { pub fn set_ahash_seed(new_seed: Option<[u64; 4]>) -> Result<(), Option<[u64; 4]>> {
AHASH_SEED.set(new_seed) AHASH_SEED.set(new_seed)
} }
/// Gets the current Rhai Ahash Seed. If the seed is not yet defined, this will automatically set a seed. /// Get the current hashing Seed.
/// The default seed is not stable and may change between versions. ///
/// If the seed is not yet defined, the `RHAI_AHASH_SEED` environment variable (if any) is used.
///
/// Otherwise, the hashing seed is randomized to protect against DOS attacks.
/// ///
/// See [`set_rhai_ahash_seed`] for more. /// See [`set_rhai_ahash_seed`] for more.
#[inline]
#[must_use]
pub fn get_ahash_seed() -> Option<[u64; 4]> { pub fn get_ahash_seed() -> Option<[u64; 4]> {
AHASH_SEED.get_or_init(|| hashing_env::AHASH_SEED).flatten() AHASH_SEED.get_or_init(|| hashing_env::AHASH_SEED).flatten()
} }

View File

@ -1,2 +1,3 @@
// This file is automatically set during build time by build.rs and build.template. //! This file is automatically recreated during build time by `build.rs` from `build.template`.
pub(crate) const AHASH_SEED: Option<[u64; 4]> = None; pub(crate) const AHASH_SEED: Option<[u64; 4]> = None;

View File

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