#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(docsrs, feature(doc_cfg))]
pub mod generator;
pub mod id;
pub use generator::Scru64Generator;
pub use id::Scru64Id;
#[cfg(feature = "global_gen")]
#[cfg_attr(docsrs, doc(cfg(feature = "global_gen")))]
pub use shortcut::{new, new_string, new_string_sync, new_sync};
#[cfg(test)]
mod test_cases;
const NODE_CTR_SIZE: u8 = 24;
#[cfg(feature = "global_gen")]
mod shortcut {
use std::{thread, time};
use crate::{generator::GlobalGenerator, Scru64Id};
const DELAY: time::Duration = time::Duration::from_millis(64);
#[doc = concat!("\n\n", include_str!("generator/doc_global_gen.md"), "\n\n")]
pub async fn new() -> Scru64Id {
if let Some(value) = GlobalGenerator.generate() {
value
} else {
spawn_thread_or_block(new_sync).await
}
}
#[doc = concat!("\n\n", include_str!("generator/doc_global_gen.md"), "\n\n")]
pub async fn new_string() -> String {
if let Some(value) = GlobalGenerator.generate() {
value.into()
} else {
spawn_thread_or_block(new_string_sync).await
}
}
#[cold]
async fn spawn_thread_or_block<T: Send + 'static>(f: fn() -> T) -> T {
match thread_async::run_with_builder(thread::Builder::new(), f) {
Ok((ftr, _)) => ftr.await,
Err(_) => f(),
}
}
#[doc = concat!("\n\n", include_str!("generator/doc_global_gen.md"), "\n\n")]
pub fn new_sync() -> Scru64Id {
loop {
if let Some(value) = GlobalGenerator.generate() {
break value;
} else {
#[cfg(test)]
tests::SLEEP_COUNT.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
thread::sleep(DELAY);
}
}
}
#[doc = concat!("\n\n", include_str!("generator/doc_global_gen.md"), "\n\n")]
pub fn new_string_sync() -> String {
new_sync().into()
}
#[cfg(test)]
mod tests {
use super::{new, new_string, new_string_sync, new_sync, GlobalGenerator};
use std::sync::atomic;
const N: usize = (10_000 >> 8) * (1 << 15) / (4);
fn setup() {
let _ = GlobalGenerator.initialize("42/8".parse().unwrap());
}
pub static SLEEP_COUNT: atomic::AtomicUsize = atomic::AtomicUsize::new(0);
fn teardown(name: &str) {
let c = SLEEP_COUNT.load(atomic::Ordering::SeqCst);
println!("finishing {}: global sleep count is now at {}", name, c);
}
#[tokio::test]
async fn new_many() {
setup();
let mut prev = new().await;
for _ in 0..N {
let curr = new().await;
assert!(prev < curr);
prev = curr;
}
let mut prev = String::from(prev);
for _ in 0..N {
let curr = new_string().await;
assert!(prev < curr);
prev = curr;
}
teardown("new_many");
}
#[test]
fn new_sync_many() {
setup();
let mut prev = new_sync();
for _ in 0..N {
let curr = new_sync();
assert!(prev < curr);
prev = curr;
}
let mut prev = String::from(prev);
for _ in 0..N {
let curr = new_string_sync();
assert!(prev < curr);
prev = curr;
}
teardown("new_sync_many");
}
}
}