1use std::{fmt, num::NonZeroU32};
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
15pub enum TlsModel {
16 LocalExec,
19 InitialExec,
22}
23
24impl TlsModel {
25 pub const fn as_str(&self) -> &'static str {
26 match self {
27 TlsModel::LocalExec => "local_exec",
28 TlsModel::InitialExec => "initial_exec",
29 }
30 }
31}
32
33impl fmt::Display for TlsModel {
34 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
35 write!(f, "{}", self.as_str())
36 }
37}
38
39#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
42pub enum MemoryOrdering {
43 Relaxed,
45 Acquire,
47 Release,
49 AcqRel,
51 SeqCst,
53}
54
55impl MemoryOrdering {
56 pub fn strength(self) -> u8 {
59 match self {
60 Self::Relaxed => 0,
61 Self::Acquire => 1,
62 Self::Release => 2,
63 Self::AcqRel => 3,
64 Self::SeqCst => 4,
65 }
66 }
67
68 pub fn cmpxchg_failure_rejection(success: Self, failure: Self) -> Option<&'static str> {
75 match failure {
76 Self::Release | Self::AcqRel => {
77 Some("the failure ordering is a load: use relaxed, acquire or seqcst")
78 }
79 Self::Relaxed | Self::Acquire | Self::SeqCst => {
80 if failure.strength() > success.strength() {
81 Some("the failure ordering may not be stronger than the success ordering")
82 } else {
83 None
84 }
85 }
86 }
87 }
88}
89
90impl fmt::Display for MemoryOrdering {
91 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
92 let s = match self {
93 MemoryOrdering::Relaxed => "relaxed",
94 MemoryOrdering::Acquire => "acquire",
95 MemoryOrdering::Release => "release",
96 MemoryOrdering::AcqRel => "acqrel",
97 MemoryOrdering::SeqCst => "seqcst",
98 };
99 write!(f, "{s}")
100 }
101}
102
103#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
105pub struct SourceLoc {
106 pub line: NonZeroU32,
107 pub column: u32,
108}
109
110impl SourceLoc {
111 pub fn new(line: u32, column: u32) -> Option<Self> {
113 NonZeroU32::new(line).map(|line| Self { line, column })
114 }
115
116 pub fn line(self) -> u32 {
117 self.line.get()
118 }
119}
120
121impl fmt::Display for SourceLoc {
122 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
123 write!(f, "{}:{}", self.line, self.column)
124 }
125}
126
127#[cfg(test)]
128mod tests {
129 use super::*;
130
131 #[test]
132 fn source_loc_rejects_line_zero() {
133 assert!(SourceLoc::new(0, 4).is_none());
134 let loc = SourceLoc::new(7, 4).expect("line 7 is a line");
135 assert_eq!(loc.line(), 7);
136 assert_eq!(loc.to_string(), "7:4");
137 }
138
139 #[test]
140 fn a_compare_exchange_failure_ordering_is_a_load_no_stronger_than_the_success() {
141 use MemoryOrdering::{AcqRel, Acquire, Relaxed, Release, SeqCst};
142 for (success, failure) in [
143 (SeqCst, SeqCst),
144 (SeqCst, Acquire),
145 (SeqCst, Relaxed),
146 (AcqRel, Acquire),
147 (Release, Acquire),
148 (Acquire, Acquire),
149 (Acquire, Relaxed),
150 (Relaxed, Relaxed),
151 ] {
152 assert_eq!(
153 MemoryOrdering::cmpxchg_failure_rejection(success, failure),
154 None,
155 "{success} / {failure}"
156 );
157 }
158 for (success, failure) in [
159 (SeqCst, Release),
160 (SeqCst, AcqRel),
161 (Relaxed, Release),
162 (Acquire, SeqCst),
163 (AcqRel, SeqCst),
164 (Relaxed, Acquire),
165 ] {
166 assert!(
167 MemoryOrdering::cmpxchg_failure_rejection(success, failure).is_some(),
168 "{success} / {failure}"
169 );
170 }
171 }
172
173 #[test]
174 fn tls_and_ordering_names_round_trip_to_text() {
175 assert_eq!(TlsModel::LocalExec.as_str(), "local_exec");
176 assert_eq!(TlsModel::InitialExec.to_string(), "initial_exec");
177 assert_eq!(MemoryOrdering::AcqRel.to_string(), "acqrel");
178 assert_eq!(MemoryOrdering::SeqCst.to_string(), "seqcst");
179 }
180}