use std::{fmt, num::NonZeroU32};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum TlsModel {
LocalExec,
InitialExec,
}
impl TlsModel {
pub const fn as_str(&self) -> &'static str {
match self {
TlsModel::LocalExec => "local_exec",
TlsModel::InitialExec => "initial_exec",
}
}
}
impl fmt::Display for TlsModel {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.as_str())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum MemoryOrdering {
Relaxed,
Acquire,
Release,
AcqRel,
SeqCst,
}
impl MemoryOrdering {
pub fn strength(self) -> u8 {
match self {
Self::Relaxed => 0,
Self::Acquire => 1,
Self::Release => 2,
Self::AcqRel => 3,
Self::SeqCst => 4,
}
}
pub fn cmpxchg_failure_rejection(success: Self, failure: Self) -> Option<&'static str> {
match failure {
Self::Release | Self::AcqRel => {
Some("the failure ordering is a load: use relaxed, acquire or seqcst")
}
Self::Relaxed | Self::Acquire | Self::SeqCst => {
if failure.strength() > success.strength() {
Some("the failure ordering may not be stronger than the success ordering")
} else {
None
}
}
}
}
}
impl fmt::Display for MemoryOrdering {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let s = match self {
MemoryOrdering::Relaxed => "relaxed",
MemoryOrdering::Acquire => "acquire",
MemoryOrdering::Release => "release",
MemoryOrdering::AcqRel => "acqrel",
MemoryOrdering::SeqCst => "seqcst",
};
write!(f, "{s}")
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SourceLoc {
pub line: NonZeroU32,
pub column: u32,
}
impl SourceLoc {
pub fn new(line: u32, column: u32) -> Option<Self> {
NonZeroU32::new(line).map(|line| Self { line, column })
}
pub fn line(self) -> u32 {
self.line.get()
}
}
impl fmt::Display for SourceLoc {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}:{}", self.line, self.column)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn source_loc_rejects_line_zero() {
assert!(SourceLoc::new(0, 4).is_none());
let loc = SourceLoc::new(7, 4).expect("line 7 is a line");
assert_eq!(loc.line(), 7);
assert_eq!(loc.to_string(), "7:4");
}
#[test]
fn a_compare_exchange_failure_ordering_is_a_load_no_stronger_than_the_success() {
use MemoryOrdering::{AcqRel, Acquire, Relaxed, Release, SeqCst};
for (success, failure) in [
(SeqCst, SeqCst),
(SeqCst, Acquire),
(SeqCst, Relaxed),
(AcqRel, Acquire),
(Release, Acquire),
(Acquire, Acquire),
(Acquire, Relaxed),
(Relaxed, Relaxed),
] {
assert_eq!(
MemoryOrdering::cmpxchg_failure_rejection(success, failure),
None,
"{success} / {failure}"
);
}
for (success, failure) in [
(SeqCst, Release),
(SeqCst, AcqRel),
(Relaxed, Release),
(Acquire, SeqCst),
(AcqRel, SeqCst),
(Relaxed, Acquire),
] {
assert!(
MemoryOrdering::cmpxchg_failure_rejection(success, failure).is_some(),
"{success} / {failure}"
);
}
}
#[test]
fn tls_and_ordering_names_round_trip_to_text() {
assert_eq!(TlsModel::LocalExec.as_str(), "local_exec");
assert_eq!(TlsModel::InitialExec.to_string(), "initial_exec");
assert_eq!(MemoryOrdering::AcqRel.to_string(), "acqrel");
assert_eq!(MemoryOrdering::SeqCst.to_string(), "seqcst");
}
}