fix build.yml, concurrency concerns, build.rs concerns
This commit is contained in:
parent
80fef5a01c
commit
36edc445d1
31
.github/workflows/build.yml
vendored
31
.github/workflows/build.yml
vendored
@ -89,37 +89,6 @@ jobs:
|
|||||||
command: test
|
command: test
|
||||||
args: ${{matrix.flags}}
|
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 builds are a bit more extensive to test
|
||||||
no_std_build:
|
no_std_build:
|
||||||
name: NoStdBuild
|
name: NoStdBuild
|
||||||
|
6
build.rs
6
build.rs
@ -17,10 +17,10 @@ fn main() {
|
|||||||
|
|
||||||
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")
|
File::create("src/config/hashing_env.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/hashing.rs`");
|
.expect("cannot write to `config/hashing_env.rs`");
|
||||||
}
|
}
|
||||||
|
114
build.template
114
build.template
@ -1,112 +1,2 @@
|
|||||||
//! Fixed hashing seeds for stable hashing.
|
// This file is automatically set during build time by build.rs and build.template.
|
||||||
//!
|
pub(crate) const AHASH_SEED: Option<[u64; 4]> = {{AHASH_SEED}};
|
||||||
//! 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<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: Option<[u64; 4]> = {{ AHASH_SEED }};
|
|
||||||
|
|
||||||
AHASH_SEED
|
|
||||||
.get_or_init(|| FUNNY_YUMENIKKI_REFERENCE)
|
|
||||||
.map(|x| *x)
|
|
||||||
.flatten()
|
|
||||||
}
|
|
||||||
|
@ -4,31 +4,94 @@
|
|||||||
//!
|
//!
|
||||||
//! See [`set_rhai_ahash_seed`] for more.
|
//! 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.
|
//! environment variable instead.
|
||||||
//!
|
//!
|
||||||
//! 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
|
||||||
|
|
||||||
|
use crate::config::hashing_env;
|
||||||
use core::{
|
use core::{
|
||||||
cell::UnsafeCell,
|
cell::UnsafeCell,
|
||||||
marker::PhantomData,
|
marker::PhantomData,
|
||||||
mem::MaybeUninit,
|
mem::MaybeUninit,
|
||||||
panic::{RefUnwindSafe, UnwindSafe},
|
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<T>"
|
||||||
struct SusLock<T>
|
struct SusLock<T>
|
||||||
where
|
where
|
||||||
T: 'static,
|
T: 'static + Copy,
|
||||||
{
|
{
|
||||||
initalized: AtomicBool,
|
initalized: AtomicBool,
|
||||||
data: UnsafeCell<MaybeUninit<T>>,
|
data: UnsafeCell<MaybeUninit<T>>,
|
||||||
_marker: PhantomData<T>,
|
_marker: PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> SusLock<T> {
|
impl<T> SusLock<T>
|
||||||
|
where
|
||||||
|
T: 'static + Copy,
|
||||||
|
{
|
||||||
pub const fn new() -> SusLock<T> {
|
pub const fn new() -> SusLock<T> {
|
||||||
SusLock {
|
SusLock {
|
||||||
initalized: AtomicBool::new(false),
|
initalized: AtomicBool::new(false),
|
||||||
@ -37,21 +100,31 @@ impl<T> SusLock<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&self) -> Option<&T> {
|
pub fn get(&self) -> Option<T> {
|
||||||
if self.initalized.load(Ordering::SeqCst) {
|
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 {
|
} else {
|
||||||
return None;
|
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<T> {
|
||||||
let value = f();
|
let value = f();
|
||||||
if !self.initalized.load(Ordering::SeqCst) {
|
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 {
|
unsafe {
|
||||||
self.data.get().write(MaybeUninit::new(value));
|
self.data.get().write(MaybeUninit::new(value));
|
||||||
}
|
}
|
||||||
self.initalized.store(true, Ordering::SeqCst);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.get()
|
self.get()
|
||||||
@ -67,11 +140,14 @@ impl<T> SusLock<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<T: Sync + Send> Sync for SusLock<T> {}
|
unsafe impl<T: Sync + Send> Sync for SusLock<T> where T: 'static + Copy {}
|
||||||
unsafe impl<T: Send> Send for SusLock<T> {}
|
unsafe impl<T: Send> Send for SusLock<T> where T: 'static + Copy {}
|
||||||
impl<T: RefUnwindSafe + UnwindSafe> RefUnwindSafe for SusLock<T> {}
|
impl<T: RefUnwindSafe + UnwindSafe> RefUnwindSafe for SusLock<T> where T: 'static + Copy {}
|
||||||
|
|
||||||
impl<T> Drop for SusLock<T> {
|
impl<T> Drop for SusLock<T>
|
||||||
|
where
|
||||||
|
T: 'static + Copy,
|
||||||
|
{
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
if self.initalized.load(Ordering::SeqCst) {
|
if self.initalized.load(Ordering::SeqCst) {
|
||||||
unsafe { (&mut *self.data.get()).assume_init_drop() };
|
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.
|
/// See [`set_rhai_ahash_seed`] for more.
|
||||||
pub fn get_ahash_seed() -> Option<[u64; 4]> {
|
pub fn get_ahash_seed() -> Option<[u64; 4]> {
|
||||||
const FUNNY_YUMENIKKI_REFERENCE: Option<[u64; 4]> = None;
|
AHASH_SEED.get_or_init(|| hashing_env::AHASH_SEED).flatten()
|
||||||
|
|
||||||
AHASH_SEED
|
|
||||||
.get_or_init(|| FUNNY_YUMENIKKI_REFERENCE)
|
|
||||||
.map(|x| *x)
|
|
||||||
.flatten()
|
|
||||||
}
|
}
|
||||||
|
2
src/config/hashing_env.rs
Normal file
2
src/config/hashing_env.rs
Normal file
@ -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;
|
@ -1,3 +1,4 @@
|
|||||||
//! Contains Configuration for Rhai.
|
//! Contains Configuration for Rhai.
|
||||||
|
|
||||||
pub mod hashing;
|
pub mod hashing;
|
||||||
|
mod hashing_env;
|
||||||
|
Loading…
Reference in New Issue
Block a user