use crate::err::StageOutOfBoundsError;
use core::fmt::{Display, Formatter};
pub(crate) type WordNum = usize;
pub(crate) type SequenceNum = usize;
pub(crate) type ThreadId = usize;
pub(crate) type ThreadIndex = usize;
pub(crate) fn convert_thread_id_to_thread_index(thread_id: ThreadId) -> ThreadIndex {
thread_id - 1
}
pub(crate) fn convert_thread_index_to_thread_id(thread_index: ThreadIndex) -> ThreadId {
thread_index + 1
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Stage {
Inactive = 0,
Claiming = 1,
Setting = 2,
Reverting = 3,
Successful = 4,
Reverted = 5,
}
pub(crate) const STAGE_BIT_LENGTH: usize = 3;
impl Display for Stage {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "{self:?}")
}
}
impl TryFrom<usize> for Stage {
type Error = StageOutOfBoundsError;
fn try_from(stage: usize) -> Result<Self, StageOutOfBoundsError> {
match stage {
i if i == Stage::Inactive as usize => Ok(Stage::Inactive),
i if i == Stage::Claiming as usize => Ok(Stage::Claiming),
i if i == Stage::Setting as usize => Ok(Stage::Setting),
i if i == Stage::Reverting as usize => Ok(Stage::Reverting),
i if i == Stage::Successful as usize => Ok(Stage::Successful),
i if i == Stage::Reverted as usize => Ok(Stage::Reverted),
i => Err(StageOutOfBoundsError(i)),
}
}
}
pub(crate) type StageAndSequence = usize;
pub(crate) const SEQUENCE_MASK_FOR_STAGE_AND_SEQUENCE: usize = {
let num_sequence_bits: usize = usize::BITS as usize - STAGE_BIT_LENGTH;
!(0b111 << num_sequence_bits)
};
pub(crate) fn construct_stage_and_sequence(
stage: Stage,
sequence: SequenceNum,
) -> StageAndSequence {
(stage as usize) << (usize::BITS as usize - STAGE_BIT_LENGTH) | sequence
}
pub(crate) fn extract_stage_from_stage_and_sequence(
stage_and_sequence: StageAndSequence,
) -> Result<Stage, StageOutOfBoundsError> {
let stage_as_num: usize = stage_and_sequence >> (usize::BITS as usize - STAGE_BIT_LENGTH);
Stage::try_from(stage_as_num)
}
pub(crate) fn extract_sequence_from_stage_and_sequence(
stage_and_sequence: StageAndSequence,
) -> SequenceNum {
stage_and_sequence & SEQUENCE_MASK_FOR_STAGE_AND_SEQUENCE
}
pub(crate) type ThreadAndSequence = usize;
pub const fn is_value_a_kcas_marker<const NUM_THREADS: usize>(value: usize) -> bool {
let top_bits: usize = extract_thread_from_thread_and_sequence::<NUM_THREADS>(value);
top_bits > 0 && top_bits <= NUM_THREADS
}
pub const fn get_bit_length_of_num_threads<const NUM_THREADS: usize>() -> usize {
let num_threads_plus_one: usize = NUM_THREADS + 1;
let mut i: usize = 0;
while i != usize::BITS as usize && num_threads_plus_one >> i != 0usize {
i += 1;
}
i
}
pub(crate) const fn get_sequence_mask_for_thread_and_sequence<const NUM_THREADS: usize>() -> usize {
let bit_length_of_num_threads: usize = get_bit_length_of_num_threads::<NUM_THREADS>();
let num_sequence_bits: usize = usize::BITS as usize - bit_length_of_num_threads;
!(usize::MAX << num_sequence_bits)
}
pub(crate) const fn construct_thread_and_sequence<const NUM_THREADS: usize>(
thread_id: ThreadId,
sequence: SequenceNum,
) -> ThreadAndSequence {
thread_id << (usize::BITS as usize - get_bit_length_of_num_threads::<NUM_THREADS>()) | sequence
}
pub(crate) const fn extract_thread_from_thread_and_sequence<const NUM_THREADS: usize>(
thread_and_sequence: ThreadAndSequence,
) -> ThreadId {
thread_and_sequence >> (usize::BITS as usize - get_bit_length_of_num_threads::<NUM_THREADS>())
}
pub(crate) const fn extract_sequence_from_thread_and_sequence<const NUM_THREADS: usize>(
thread_and_sequence: ThreadAndSequence,
) -> SequenceNum {
thread_and_sequence & get_sequence_mask_for_thread_and_sequence::<NUM_THREADS>()
}
#[cfg(test)]
#[cfg(feature = "std")]
mod tests {
use crate::types::{
construct_stage_and_sequence, extract_sequence_from_stage_and_sequence,
extract_stage_from_stage_and_sequence, SequenceNum, Stage, StageAndSequence,
SEQUENCE_MASK_FOR_STAGE_AND_SEQUENCE,
};
use test_log::test;
use tracing::debug;
#[test]
fn test() {
let stage_and_sequence: StageAndSequence =
construct_stage_and_sequence(Stage::Successful, 0);
debug!("stage_and_sequence: {stage_and_sequence:?}");
let stage: Stage =
extract_stage_from_stage_and_sequence(stage_and_sequence).expect("Could not extract");
let sequence: SequenceNum = extract_sequence_from_stage_and_sequence(stage_and_sequence);
debug!("stage: {stage:?}");
debug!("sequence: {sequence:?}");
debug!("mask: {:?}", SEQUENCE_MASK_FOR_STAGE_AND_SEQUENCE);
assert_eq!(stage, Stage::Successful);
assert_eq!(sequence, 0usize);
}
}