use std::sync::Arc;
#[cfg(feature = "interning")]
mod enabled {
use crate::errors::seq_to_string_or_log;
use super::Arc;
use std::num::NonZeroU32;
use std::sync::atomic::{AtomicBool, AtomicU32, Ordering};
use ahash::RandomState;
use dashmap::DashMap;
use lasso::{Key, Spur, ThreadedRodeo};
use once_cell::sync::Lazy;
use parking_lot::RwLock;
static SEQ_INTERNER: Lazy<SeqInterner> = Lazy::new(SeqInterner::default);
#[inline]
pub fn seq_from_bytes(bytes: &[u8]) -> SeqHandle {
SEQ_INTERNER.intern(bytes)
}
#[inline]
pub fn seq_to_bytes(h: &SeqHandle) -> Arc<[u8]> {
SEQ_INTERNER.resolve(h)
}
pub fn reserve_seq_interner(estimated_unique: usize) {
SEQ_INTERNER.reserve(estimated_unique);
}
#[inline]
pub fn num_interned_reverse() -> usize {
SEQ_INTERNER.num_interned_reverse()
}
#[inline]
pub fn num_interned_forward() -> usize {
SEQ_INTERNER.num_interned_forward()
}
pub fn clear_seq_interner() {
SEQ_INTERNER.clear();
}
#[repr(transparent)]
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
pub struct SeqHandle(NonZeroU32);
impl SeqHandle {
#[inline]
pub fn get(&self) -> u32 {
self.0.get()
}
#[inline]
fn from_index0(i: u32) -> Self {
Self::from_raw(i + 1)
}
#[inline]
fn from_raw(i: u32) -> Self {
SeqHandle(NonZeroU32::new(i).expect("nonzero"))
}
#[inline]
fn index0(&self) -> usize {
(self.0.get() - 1) as usize
}
#[inline]
pub fn len(&self) -> usize {
seq_to_bytes(self).len()
}
#[inline]
pub fn is_empty(&self) -> bool {
seq_to_bytes(self).is_empty()
}
#[inline]
pub fn to_str_or_log(&self) -> String {
seq_to_string_or_log(&seq_to_bytes(self).to_vec())
}
}
struct ForwardEntry {
bytes: Arc<[u8]>,
handle_raw: AtomicU32,
init_claimed: AtomicBool,
}
impl ForwardEntry {
#[inline]
pub fn new_unclaimed(bytes: Arc<[u8]>) -> Self {
ForwardEntry {
bytes,
handle_raw: AtomicU32::new(0),
init_claimed: AtomicBool::new(false),
}
}
}
pub struct SeqInterner {
forward: DashMap<Arc<[u8]>, Arc<ForwardEntry>, RandomState>,
reverse: RwLock<Vec<Arc<[u8]>>>,
next: AtomicU32,
}
impl Default for SeqInterner {
fn default() -> Self {
Self {
forward: DashMap::with_hasher(RandomState::new()),
reverse: RwLock::new(Vec::new()),
next: AtomicU32::new(0),
}
}
}
impl SeqInterner {
#[inline]
pub fn intern(&self, bytes: &[u8]) -> SeqHandle {
let entry = match self.forward.get(bytes) {
Some(found) => Arc::clone(found.value()),
None => {
let arc = Arc::<[u8]>::from(bytes);
let entry_ref = self
.forward
.entry(arc.clone())
.or_insert_with(|| Arc::new(ForwardEntry::new_unclaimed(arc)));
Arc::clone(entry_ref.value())
}
};
loop {
let raw = entry.handle_raw.load(Ordering::Acquire);
if raw != 0 {
return SeqHandle::from_raw(raw);
}
if entry
.init_claimed
.compare_exchange(false, true, Ordering::AcqRel, Ordering::Acquire)
.is_ok()
{
let idx0 = self.next.fetch_add(1, Ordering::Relaxed);
if idx0 == u32::MAX {
panic!("SeqInterner exhausted SeqHandle space");
}
let handle = SeqHandle::from_index0(idx0);
{
let mut rev = self.reverse.write();
let pos = idx0 as usize;
match rev.len().cmp(&pos) {
std::cmp::Ordering::Less => {
rev.resize_with(pos, || Arc::<[u8]>::from(&b""[..]));
rev.push(entry.bytes.clone())
}
std::cmp::Ordering::Equal => rev.push(entry.bytes.clone()),
std::cmp::Ordering::Greater => rev[pos] = entry.bytes.clone(),
}
}
entry.handle_raw.store(handle.get(), Ordering::Release);
return handle;
}
std::thread::yield_now();
}
}
#[inline]
pub fn resolve(&self, id: &SeqHandle) -> Arc<[u8]> {
self.reverse.read()[id.index0()].clone()
}
pub fn reserve(&self, additional_unique: usize) {
self.reverse.write().reserve(additional_unique);
}
#[inline]
pub fn num_interned_reverse(&self) -> usize {
self.reverse.read().len()
}
#[inline]
pub fn num_interned_forward(&self) -> usize {
self.forward.len()
}
pub fn clear(&self) {
self.forward.clear();
self.reverse.write().clear();
self.next.store(0, Ordering::Release);
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
struct GroupKey(NonZeroU32);
unsafe impl Key for GroupKey {
fn into_usize(self) -> usize {
(self.0.get() - 0b100) as usize
}
fn try_from_usize(int: usize) -> Option<Self> {
Some(Self(
NonZeroU32::new(int.checked_add(0b100)? as u32).expect("Checked > 0b11"),
))
}
}
static GROUP_IDS: Lazy<ThreadedRodeo<GroupKey>> = Lazy::new(ThreadedRodeo::<GroupKey>::new);
#[repr(transparent)]
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
pub struct GroupID(GroupKey);
#[inline]
pub fn group_id_from_str(s: &str) -> GroupID {
GroupID(GROUP_IDS.get_or_intern(s))
}
#[inline]
pub fn group_id_to_str(id: &GroupID) -> Arc<str> {
Arc::<str>::from(GROUP_IDS.resolve(&id.0))
}
#[inline]
pub fn group_id_from_raw(i: NonZeroU32) -> GroupID {
GroupID(GroupKey(i))
}
#[inline]
pub fn group_id_to_raw(id: &GroupID) -> NonZeroU32 {
id.0.0
}
static LIB_IDS: Lazy<ThreadedRodeo> = Lazy::new(ThreadedRodeo::default);
#[repr(transparent)]
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
pub struct LibraryID(Spur);
#[inline]
pub fn library_id_from_str(s: &str) -> LibraryID {
LibraryID(LIB_IDS.get_or_intern(s))
}
#[inline]
pub fn library_id_to_str(id: &LibraryID) -> Arc<str> {
Arc::<str>::from(LIB_IDS.resolve(&id.0))
}
static REGIONS: Lazy<ThreadedRodeo> = Lazy::new(ThreadedRodeo::default);
#[repr(transparent)]
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
pub struct RegionID(Spur);
#[inline]
pub fn region_id_from_str(s: &str) -> RegionID {
RegionID(REGIONS.get_or_intern(s))
}
#[inline]
pub fn region_id_to_str(id: &RegionID) -> Arc<str> {
Arc::<str>::from(REGIONS.resolve(&id.0))
}
}
#[cfg(not(feature = "interning"))]
mod disabled {
use crate::errors::seq_to_string_or_log;
use super::Arc;
#[derive(Eq, PartialEq, Hash, Debug)]
pub struct SeqHandle(pub Arc<[u8]>);
impl SeqHandle {
#[inline]
pub fn len(&self) -> usize {
seq_to_bytes(self).len()
}
#[inline]
pub fn is_empty(&self) -> bool {
seq_to_bytes(self).is_empty()
}
#[inline]
pub fn to_str_or_log(&self) -> String {
seq_to_string_or_log(&seq_to_bytes(self).to_vec())
}
}
impl Clone for SeqHandle {
#[inline(always)]
fn clone(&self) -> Self {
SeqHandle(Arc::clone(&self.0))
}
}
#[inline]
pub fn seq_from_bytes(bytes: &[u8]) -> SeqHandle {
SeqHandle(Arc::<[u8]>::from(bytes))
}
#[inline]
pub fn seq_to_bytes(h: &SeqHandle) -> Arc<[u8]> {
h.0.clone()
}
pub fn reserve_seq_interner(_estimated_unique: usize) {}
#[inline]
pub fn num_interned_reverse() -> usize {
0
}
#[inline]
pub fn num_interned_forward() -> usize {
0
}
#[inline]
pub fn clear_seq_interner() {}
#[derive(Eq, PartialEq, Hash, Debug)]
pub struct GroupID(pub Arc<str>);
impl Clone for GroupID {
#[inline(always)]
fn clone(&self) -> Self {
GroupID(Arc::clone(&self.0))
}
}
#[inline]
pub fn group_id_from_str(s: &str) -> GroupID {
GroupID(Arc::<str>::from(s))
}
#[inline]
pub fn group_id_to_str(h: &GroupID) -> Arc<str> {
h.0.clone()
}
#[derive(Eq, PartialEq, Hash, Debug)]
pub struct LibraryID(pub Arc<str>);
impl Clone for LibraryID {
#[inline(always)]
fn clone(&self) -> Self {
LibraryID(Arc::clone(&self.0))
}
}
#[inline]
pub fn library_id_from_str(s: &str) -> LibraryID {
LibraryID(Arc::<str>::from(s))
}
#[inline]
pub fn library_id_to_str(h: &LibraryID) -> Arc<str> {
h.0.clone()
}
#[derive(Eq, PartialEq, Hash, Debug)]
pub struct RegionID(pub Arc<str>);
impl Clone for RegionID {
#[inline(always)]
fn clone(&self) -> Self {
RegionID(Arc::clone(&self.0))
}
}
#[inline]
pub fn region_id_from_str(s: &str) -> RegionID {
RegionID(Arc::<str>::from(s))
}
#[inline]
pub fn region_id_to_str(h: &RegionID) -> Arc<str> {
h.0.clone()
}
}
#[cfg(feature = "interning")]
pub use enabled::*;
#[cfg(not(feature = "interning"))]
pub use disabled::*;
#[cfg(test)]
mod tests {
use super::*;
use std::collections::HashMap;
#[test]
fn seq_round_trip_bytes() {
let h = seq_from_bytes(b"ACGTN");
let out = seq_to_bytes(&h);
assert_eq!(&*out, b"ACGTN");
}
#[test]
fn group_round_trip_str() {
let g = group_id_from_str("groupA");
let s = group_id_to_str(&g);
assert_eq!(&*s, "groupA");
}
#[test]
fn library_round_trip_str() {
let l = library_id_from_str("seqA");
let s = library_id_to_str(&l);
assert_eq!(&*s, "seqA");
}
#[test]
fn region_round_trip_str() {
let r = region_id_from_str("Reg1");
let s = region_id_to_str(&r);
assert_eq!(&*s, "Reg1");
}
#[test]
fn handles_work_as_hashmap_keys() {
let a = seq_from_bytes(b"AAAA");
let b = seq_from_bytes(b"GGGG");
let mut m: HashMap<SeqHandle, u32> = HashMap::new();
m.insert(a.clone(), 1);
m.insert(b.clone(), 2);
assert_eq!(m.get(&a), Some(&1));
assert_eq!(m.get(&b), Some(&2));
}
#[test]
fn seq_round_trip_empty() {
let h = seq_from_bytes(b"");
let out = seq_to_bytes(&h);
assert_eq!(&*out, b"");
}
#[test]
fn seq_len_method() {
let h = seq_from_bytes(b"ACGTACGT");
assert_eq!(h.len(), 8);
let h_empty = seq_from_bytes(b"");
assert_eq!(h_empty.len(), 0);
}
#[test]
fn seq_is_empty_method() {
let h = seq_from_bytes(b"A");
assert!(!h.is_empty());
let h_empty = seq_from_bytes(b"");
assert!(h_empty.is_empty());
}
#[test]
fn seq_to_str_or_log_valid_utf8() {
let h = seq_from_bytes(b"ACGT");
let s = h.to_str_or_log();
assert_eq!(s, "ACGT");
}
#[test]
fn seq_to_str_or_log_empty() {
let h = seq_from_bytes(b"");
let s = h.to_str_or_log();
assert_eq!(s, "");
}
#[test]
fn group_round_trip_empty_string() {
let g = group_id_from_str("");
let s = group_id_to_str(&g);
assert_eq!(&*s, "");
}
#[test]
fn group_round_trip_special_chars() {
let g = group_id_from_str("pool-A_123.xyz");
let s = group_id_to_str(&g);
assert_eq!(&*s, "pool-A_123.xyz");
}
#[test]
fn library_round_trip_empty_string() {
let l = library_id_from_str("");
let s = library_id_to_str(&l);
assert_eq!(&*s, "");
}
#[test]
fn library_round_trip_special_chars() {
let l = library_id_from_str("seq-001_variant.v2");
let s = library_id_to_str(&l);
assert_eq!(&*s, "seq-001_variant.v2");
}
#[test]
fn region_round_trip_empty_string() {
let r = region_id_from_str("");
let s = region_id_to_str(&r);
assert_eq!(&*s, "");
}
#[test]
fn region_round_trip_special_chars() {
let r = region_id_from_str("Region_A-1.upstream");
let s = region_id_to_str(&r);
assert_eq!(&*s, "Region_A-1.upstream");
}
#[test]
fn seq_handles_clone() {
let h1 = seq_from_bytes(b"ACGT");
let h2 = h1.clone();
assert_eq!(h1, h2);
}
#[test]
fn group_handles_clone() {
let g1 = group_id_from_str("group1");
let g2 = g1.clone();
assert_eq!(g1, g2);
}
#[test]
fn library_handles_copy_and_clone() {
let l1 = library_id_from_str("lib1");
let l2 = l1.clone();
assert_eq!(l1, l2);
}
#[test]
fn region_handles_copy_and_clone() {
let r1 = region_id_from_str("region1");
let r2 = r1.clone();
assert_eq!(r1, r2);
}
#[test]
fn seq_handles_in_hashmap() {
let h1 = seq_from_bytes(b"ACGT");
let h2 = seq_from_bytes(b"GGGG");
let h3 = seq_from_bytes(b"ACGT");
let mut m: HashMap<SeqHandle, u32> = HashMap::new();
m.insert(h1, 1);
m.insert(h2, 2);
assert_eq!(m.get(&h3), Some(&1));
assert_eq!(m.len(), 2);
}
#[test]
fn group_handles_in_hashmap() {
let g1 = group_id_from_str("a");
let g2 = group_id_from_str("b");
let g3 = group_id_from_str("a");
let mut m: HashMap<GroupID, u32> = HashMap::new();
m.insert(g1, 1);
m.insert(g2, 2);
assert_eq!(m.get(&g3), Some(&1));
}
#[test]
fn library_handles_in_hashmap() {
let l1 = library_id_from_str("x");
let l2 = library_id_from_str("y");
let l3 = library_id_from_str("x");
let mut m: HashMap<LibraryID, u32> = HashMap::new();
m.insert(l1, 1);
m.insert(l2, 2);
assert_eq!(m.get(&l3), Some(&1));
}
#[test]
fn region_handles_in_hashmap() {
let r1 = region_id_from_str("alpha");
let r2 = region_id_from_str("beta");
let r3 = region_id_from_str("alpha");
let mut m: HashMap<RegionID, u32> = HashMap::new();
m.insert(r1, 1);
m.insert(r2, 2);
assert_eq!(m.get(&r3), Some(&1));
}
#[test]
fn reserve_seq_interner_smoke_test() {
reserve_seq_interner(1000);
}
#[cfg(feature = "interning")]
mod enabled_tests {
use super::*;
use std::collections::HashSet;
use std::thread;
#[test]
fn seq_dedup_same_bytes_get_same_handle() {
let a1 = seq_from_bytes(b"ACGT");
let a2 = seq_from_bytes(b"ACGT");
assert_eq!(
a1, a2,
"interning enabled: identical bytes should dedupe to same handle"
);
let p1 = Arc::as_ptr(&seq_to_bytes(&a1));
let p2 = Arc::as_ptr(&seq_to_bytes(&a2));
assert_eq!(
p1, p2,
"interning enabled: resolved Arc should be same allocation"
);
}
#[test]
fn group_dedup_same_str_get_same_handle() {
let g1 = group_id_from_str("x");
let g2 = group_id_from_str("x");
assert_eq!(
g1, g2,
"interning enabled: identical group string should dedupe"
);
}
#[test]
fn region_dedup_same_str_get_same_handle() {
let r1 = region_id_from_str("r");
let r2 = region_id_from_str("r");
assert_eq!(
r1, r2,
"interning enabled: identical region string should dedupe"
);
}
#[test]
fn option_seqhandle_is_niche_optimized() {
assert_eq!(
std::mem::size_of::<Option<SeqHandle>>(),
std::mem::size_of::<SeqHandle>(),
"enabled mode: SeqHandle should be niche-optimized so Option<SeqHandle> doesn't grow"
);
}
#[test]
fn concurrent_seq_interning_is_consistent() {
let inputs: Vec<Vec<u8>> = (0..1000)
.map(|i| format!("SEQ{:04}", i).into_bytes())
.collect();
let n_threads = 8;
let handles_per_thread: Vec<Vec<SeqHandle>> = (0..n_threads)
.map(|_| {
let inputs = inputs.clone();
thread::spawn(move || {
inputs.iter().map(|s| seq_from_bytes(s)).collect::<Vec<_>>()
})
})
.map(|j| j.join().unwrap())
.collect();
for t in 1..n_threads {
for i in 0..inputs.len() {
assert_eq!(
handles_per_thread[0][i], handles_per_thread[t][i],
"enabled mode: same bytes should yield same handle across threads"
);
}
}
}
#[test]
fn handles_have_reasonable_hash_distribution_smoke() {
let mut set: HashSet<SeqHandle> = HashSet::new();
for i in 0..10_000 {
let s = format!("X{:05}", i).into_bytes();
set.insert(seq_from_bytes(&s));
}
assert_eq!(set.len(), 10_000);
}
#[test]
fn concurrent_duplicate_inserts_do_not_allocate_extra_ids() {
let interner = Arc::new(SeqInterner::default());
let before_rev = interner.num_interned_reverse();
let before_fwd = interner.num_interned_forward();
let n_threads = 32;
let n_iters = 1000;
std::thread::scope(|s| {
for _ in 0..n_threads {
s.spawn(|| {
for _ in 0..n_iters {
let _ = interner.intern(b"ACGT");
}
});
}
});
let after_rev = interner.num_interned_reverse();
let after_fwd = interner.num_interned_forward();
assert_eq!(
after_rev,
before_rev + 1,
"Concurrent inserts should add exactly 1 reverse ID"
);
assert_eq!(
after_fwd,
before_fwd + 1,
"Concurrent inserts should add exactly 1 forward ID"
);
}
#[test]
fn concurrent_unique_inserts_allocate_exactly_one_id_each() {
let interner = Arc::new(SeqInterner::default());
let before_rev = interner.num_interned_reverse();
let before_fwd = interner.num_interned_forward();
let n = 5_000;
let seqs: Vec<Vec<u8>> = (0..n)
.map(|i| format!("SEQ{:05}", i).into_bytes())
.collect();
std::thread::scope(|scope| {
let chunk = 500;
for part in seqs.chunks(chunk) {
let thread_interner = interner.clone();
scope.spawn(move || {
for s in part {
let _ = thread_interner.intern(s);
}
});
}
});
let after_rev = interner.num_interned_reverse();
let after_fwd = interner.num_interned_forward();
assert_eq!(
after_rev,
before_rev + n,
"unique inserts should allocate exactly one reverse entry per unique sequence"
);
assert_eq!(
after_fwd,
before_fwd + n,
"unique inserts should allocate exactly one forward entry per unique sequence"
);
}
#[test]
fn concurrent_intern_and_resolve_is_safe() {
let n_threads = 16;
let n_iters = 5_000;
std::thread::scope(|scope| {
for _ in 0..n_threads {
scope.spawn(|| {
for _ in 0..n_iters {
let h = seq_from_bytes(b"GATTACA");
let seq = seq_to_bytes(&h);
assert_eq!(seq.as_ref(), b"GATTACA");
}
});
}
});
}
#[test]
fn seq_get_raw_value() {
let h = seq_from_bytes(b"ACGT");
let raw = h.get();
assert!(raw > 0, "SeqHandle should have non-zero raw value");
}
#[test]
fn seq_handles_large_sequence() {
let large_seq = vec![b'A'; 100_000];
let h = seq_from_bytes(&large_seq);
assert_eq!(h.len(), 100_000);
let resolved = seq_to_bytes(&h);
assert_eq!(resolved.len(), 100_000);
}
#[test]
fn seq_handles_various_bytes() {
let h = seq_from_bytes(&[0, 255, 127, 128, 1, 2]);
let resolved = seq_to_bytes(&h);
assert_eq!(resolved.as_ref(), &[0, 255, 127, 128, 1, 2]);
}
#[test]
fn multiple_different_sequences() {
let h1 = seq_from_bytes(b"AAA");
let h2 = seq_from_bytes(b"AAB");
let h3 = seq_from_bytes(b"ABB");
let h4 = seq_from_bytes(b"BBB");
assert_ne!(h1, h2);
assert_ne!(h2, h3);
assert_ne!(h3, h4);
assert_ne!(h1, h4);
}
#[test]
fn group_concurrent_different_strings() {
let n_threads = 10;
let n_groups = 100;
std::thread::scope(|scope| {
for t in 0..n_threads {
scope.spawn(move || {
for i in 0..n_groups {
let name = format!("group_{}_{}", t, i);
let id = group_id_from_str(&name);
let resolved = group_id_to_str(&id);
assert_eq!(&*resolved, &name);
}
});
}
});
}
#[test]
fn region_concurrent_different_strings() {
let n_threads = 10;
let n_regions = 100;
std::thread::scope(|scope| {
for t in 0..n_threads {
scope.spawn(move || {
for i in 0..n_regions {
let name = format!("region_{}_{}", t, i);
let id = region_id_from_str(&name);
let resolved = region_id_to_str(&id);
assert_eq!(&*resolved, &name);
}
});
}
});
}
#[test]
fn library_concurrent_different_strings() {
let n_threads = 10;
let n_libs = 100;
std::thread::scope(|scope| {
for t in 0..n_threads {
scope.spawn(move || {
for i in 0..n_libs {
let name = format!("lib_{}_{}", t, i);
let id = library_id_from_str(&name);
let resolved = library_id_to_str(&id);
assert_eq!(&*resolved, &name);
}
});
}
});
}
}
#[cfg(not(feature = "interning"))]
mod disabled_tests {
use super::*;
#[test]
fn seq_not_required_to_dedup() {
let a1 = seq_from_bytes(b"ACGT");
let a2 = seq_from_bytes(b"ACGT");
assert_eq!(
a1, a2,
"disabled mode: identical bytes should still compare equal"
);
}
#[test]
fn are_owned_and_round_trip() {
let g = group_id_from_str("hello");
let r = region_id_from_str("regionX");
let l = library_id_from_str("seqX");
assert_eq!(&*group_id_to_str(&g), "hello");
assert_eq!(&*region_id_to_str(&r), "regionX");
assert_eq!(&*library_id_to_str(&l), "seqX");
}
#[test]
fn seq_arc_equality_by_content() {
let a1 = seq_from_bytes(b"ACGT");
let a2 = seq_from_bytes(b"ACGT");
let a3 = seq_from_bytes(b"GGGG");
assert_eq!(a1, a2);
assert_ne!(a1, a3);
}
#[test]
fn group_arc_equality_by_content() {
let g1 = group_id_from_str("test");
let g2 = group_id_from_str("test");
let g3 = group_id_from_str("other");
assert_eq!(g1, g2);
assert_ne!(g1, g3);
}
#[test]
fn library_arc_equality_by_content() {
let l1 = library_id_from_str("test");
let l2 = library_id_from_str("test");
let l3 = library_id_from_str("other");
assert_eq!(l1, l2);
assert_ne!(l1, l3);
}
#[test]
fn region_arc_equality_by_content() {
let r1 = region_id_from_str("test");
let r2 = region_id_from_str("test");
let r3 = region_id_from_str("other");
assert_eq!(r1, r2);
assert_ne!(r1, r3);
}
}
}