#![allow(clippy::unwrap_used)]
#![allow(clippy::similar_names)]
use core::time::Duration;
use nulid::Generator;
use std::sync::Arc;
use std::thread;
#[allow(clippy::too_many_lines)]
fn main() -> Result<(), Box<dyn core::error::Error>> {
println!("NULID Monotonic Generation Example");
println!("===================================\n");
println!("1. Basic Monotonic Generation");
println!(" Generating NULIDs in rapid succession...");
let generator = Generator::new();
let mut prev_nulid = generator.generate()?;
println!(" First: {prev_nulid}");
for i in 1..5 {
let nulid = generator.generate()?;
println!(" NULID {}: {nulid}", i + 1);
assert!(nulid > prev_nulid, "NULIDs must be strictly increasing");
prev_nulid = nulid;
}
println!(" All NULIDs are strictly increasing\n");
println!("2. High-Speed Generation");
println!(" Generating 10,000 NULIDs as fast as possible...");
let start = std::time::Instant::now();
let generator = Generator::new();
let mut id_vec = Vec::with_capacity(10000);
for _ in 0..10000 {
id_vec.push(generator.generate()?);
}
let duration = start.elapsed();
println!(" Generated: {} NULIDs", id_vec.len());
println!(" Time: {duration:?}");
println!(
" Rate: {:.0} NULIDs/second",
10000.0 / duration.as_secs_f64()
);
let is_sorted = id_vec.windows(2).all(|w| w[0] < w[1]);
println!(" Strict monotonic order maintained: {is_sorted}\n");
println!("3. Concurrent Generation");
println!(" Spawning 10 threads, each generating 1,000 NULIDs...");
let generator = Arc::new(Generator::new());
let mut handles = vec![];
for thread_id in 0..10 {
let generator_clone = Arc::clone(&generator);
let handle = thread::spawn(move || {
let mut thread_nulids = Vec::with_capacity(1000);
for _ in 0..1000 {
thread_nulids.push(generator_clone.generate().unwrap());
}
(thread_id, thread_nulids)
});
handles.push(handle);
}
let mut all_ids = Vec::with_capacity(10000);
for handle in handles {
let (thread_id, thread_ids) = handle.join().unwrap();
println!(
" Thread {thread_id} generated {} NULIDs",
thread_ids.len()
);
all_ids.extend(thread_ids);
}
let original_len = all_ids.len();
all_ids.sort();
all_ids.dedup();
let unique_len = all_ids.len();
println!(" Total NULIDs: {original_len}");
println!(" Unique NULIDs: {unique_len}");
let no_duplicates = original_len == unique_len;
println!(" No duplicates: {no_duplicates}\n");
println!("4. Generation with Time Delays");
println!(" Generating NULIDs with 10ms delays...");
let generator = Generator::new();
for i in 0..5 {
let id = generator.generate()?;
let ts = id.nanos();
println!(" [{i_plus_1}] {id} (timestamp: {ts})", i_plus_1 = i + 1);
if i < 4 {
thread::sleep(Duration::from_millis(10));
}
}
println!(" Each NULID has a later timestamp\n");
println!("5. Monotonicity Within Same Nanosecond");
println!(" Rapidly generating NULIDs to test same-nanosecond handling...");
let generator = Generator::new();
let mut same_ns_count = 0;
let mut total_generated = 0;
let id1 = generator.generate()?;
let mut prev_ts = id1.nanos();
let mut prev_id = id1;
for _ in 0..1000 {
let id = generator.generate()?;
let ts = id.nanos();
if ts == prev_ts {
same_ns_count += 1;
assert!(
id > prev_id,
"NULIDs in same nanosecond must have increasing randomness"
);
}
prev_ts = ts;
prev_id = id;
total_generated += 1;
}
let total = total_generated + 1;
println!(" Total generated: {total}");
println!(" Same nanosecond: {same_ns_count}");
println!(" Monotonicity maintained even within same nanosecond\n");
println!("6. Shared Generator via Arc");
println!(" Using Arc-wrapped generator across threads...");
let generator = Arc::new(Generator::new());
let mut handles = vec![];
for thread_id in 0..5 {
let generator_clone = Arc::clone(&generator);
let handle = thread::spawn(move || {
let mut ids = Vec::new();
for _ in 0..100 {
if let Ok(id) = generator_clone.generate() {
ids.push(id);
}
}
(thread_id, ids.len())
});
handles.push(handle);
}
let mut total = 0;
for handle in handles {
let (thread_id, count) = handle.join().unwrap();
println!(" Thread {thread_id} generated: {count} NULIDs");
total += count;
}
println!(" Total: {total} NULIDs");
println!(" Arc-wrapped generators share state correctly\n");
println!("7. Sortable Properties");
println!(" Verifying lexicographic string sorting...");
let generator = Generator::new();
let mut id_list = vec![];
let mut strings = vec![];
for _ in 0..10 {
let id = generator.generate()?;
strings.push(id.to_string());
id_list.push(id);
}
let mut sorted_ids = id_list.clone();
sorted_ids.sort();
let mut sorted_strings = strings.clone();
sorted_strings.sort();
let ids_from_strings: Vec<_> = sorted_strings
.iter()
.filter_map(|s| s.parse().ok())
.collect();
let order_matches = id_list == sorted_ids;
println!(" Original order matches sorted: {order_matches}");
let string_sort_matches = sorted_ids == ids_from_strings;
println!(" String sort matches NULID sort: {string_sort_matches}");
println!(" Lexicographic sorting is consistent\n");
println!("8. Performance Comparison");
println!(" Comparing single-threaded vs concurrent generation...");
let single_start = std::time::Instant::now();
let generator = Generator::new();
for _ in 0..5000 {
let _ = generator.generate();
}
let single_duration = single_start.elapsed();
let concurrent_start = std::time::Instant::now();
let generator = Arc::new(Generator::new());
let mut handles = vec![];
for _ in 0..5 {
let generator_clone = Arc::clone(&generator);
let handle = thread::spawn(move || {
for _ in 0..1000 {
drop(generator_clone.generate());
}
});
handles.push(handle);
}
for handle in handles {
drop(handle.join());
}
let concurrent_duration = concurrent_start.elapsed();
println!(" Single-threaded (5,000): {single_duration:?}");
println!(" Concurrent 5 threads (5,000): {concurrent_duration:?}");
let speedup = single_duration.as_secs_f64() / concurrent_duration.as_secs_f64();
println!(" Speedup: {speedup:.2}x\n");
println!("All monotonic generation examples completed successfully!");
Ok(())
}