use std::cell::Cell;
use nonmax::NonMaxU32;
use oxc_allocator::CloneInSemanticIds;
use oxc_index::Idx;
const _: () = {
assert!(CloneInSemanticIds::With as u32 == 0);
assert!(CloneInSemanticIds::Without as u32 == u32::MAX);
};
pub trait SemanticId: Idx {
#[must_use]
#[expect(clippy::inline_always)]
#[inline(always)] fn clone_id(&self, with_semantic_ids: CloneInSemanticIds) -> Self {
let mask = !(with_semantic_ids as u32);
#[expect(clippy::cast_possible_truncation)]
let index = self.index() as u32;
let masked = index & mask;
Self::from_usize(masked as usize)
}
#[expect(clippy::inline_always)]
#[inline(always)] fn clone_cell_option_id(
cell: &Cell<Option<Self>>,
with_semantic_ids: CloneInSemanticIds,
) -> Cell<Option<Self>> {
let mask = !(with_semantic_ids as u32);
#[expect(clippy::cast_possible_truncation)]
let bits = match cell.get() {
Some(id) => !(id.index() as u32),
None => 0,
};
let masked = bits & mask;
let raw = NonMaxU32::new(!masked);
Cell::new(raw.map(|raw| Self::from_usize(raw.get() as usize)))
}
}
#[cfg(test)]
mod test {
use std::cell::Cell;
use oxc_allocator::CloneInSemanticIds;
use crate::node::NodeId;
use super::SemanticId;
const INPUTS: [u32; 11] = [
0,
1,
2,
42,
1000,
u32::MAX / 2 - 1,
u32::MAX / 2,
u32::MAX / 2 + 1,
u32::MAX - 1000,
u32::MAX - 2,
u32::MAX - 1,
];
#[test]
fn clone_id() {
for n in INPUTS {
let id = NodeId::from_usize(n as usize);
assert_eq!(id.clone_id(CloneInSemanticIds::With), id);
assert_eq!(id.clone_id(CloneInSemanticIds::Without), NodeId::from_usize(0));
}
}
#[test]
fn clone_cell_option_id() {
let cell = Cell::new(None);
assert_eq!(NodeId::clone_cell_option_id(&cell, CloneInSemanticIds::With).get(), None);
assert_eq!(NodeId::clone_cell_option_id(&cell, CloneInSemanticIds::Without).get(), None);
for n in INPUTS {
let id = NodeId::from_usize(n as usize);
let cell = Cell::new(Some(id));
assert_eq!(
NodeId::clone_cell_option_id(&cell, CloneInSemanticIds::With).get(),
Some(id)
);
assert_eq!(
NodeId::clone_cell_option_id(&cell, CloneInSemanticIds::Without).get(),
None
);
}
}
}