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
103pub const DEFAULT_SOURCE_FILE: NonZeroU32 = NonZeroU32::MIN;
104
105#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
107pub struct SourceLoc {
108 pub line: NonZeroU32,
109 pub column: u32,
110 pub file: NonZeroU32,
111}
112
113impl SourceLoc {
114 pub fn new(line: u32, column: u32) -> Option<Self> {
116 Self::in_file(DEFAULT_SOURCE_FILE.get(), line, column)
117 }
118
119 pub fn in_file(file: u32, line: u32, column: u32) -> Option<Self> {
120 Some(Self {
121 line: NonZeroU32::new(line)?,
122 column,
123 file: NonZeroU32::new(file)?,
124 })
125 }
126
127 pub fn line(self) -> u32 {
128 self.line.get()
129 }
130}
131
132impl fmt::Display for SourceLoc {
133 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
134 if self.file == DEFAULT_SOURCE_FILE {
135 write!(f, "{}:{}", self.line, self.column)
136 } else {
137 write!(f, "{}:{}:{}", self.file, self.line, self.column)
138 }
139 }
140}
141
142#[cfg(test)]
143mod tests {
144 use super::*;
145
146 #[test]
147 fn source_loc_rejects_line_zero() {
148 assert!(SourceLoc::new(0, 4).is_none());
149 let loc = SourceLoc::new(7, 4).expect("line 7 is a line");
150 assert_eq!(loc.line(), 7);
151 assert_eq!(loc.file, DEFAULT_SOURCE_FILE);
152 assert_eq!(loc.to_string(), "7:4");
153 }
154
155 #[test]
156 fn source_loc_in_a_file_names_that_file() {
157 assert!(SourceLoc::in_file(0, 3, 1).is_none());
158 assert!(SourceLoc::in_file(2, 0, 1).is_none());
159 let loc = SourceLoc::in_file(2, 3, 1).expect("file 2, line 3");
160 assert_eq!(loc.file.get(), 2);
161 assert_eq!(loc.to_string(), "2:3:1");
162 assert_ne!(loc, SourceLoc::new(3, 1).expect("line 3"));
163 }
164
165 #[test]
166 fn a_compare_exchange_failure_ordering_is_a_load_no_stronger_than_the_success() {
167 use MemoryOrdering::{AcqRel, Acquire, Relaxed, Release, SeqCst};
168 for (success, failure) in [
169 (SeqCst, SeqCst),
170 (SeqCst, Acquire),
171 (SeqCst, Relaxed),
172 (AcqRel, Acquire),
173 (Release, Acquire),
174 (Acquire, Acquire),
175 (Acquire, Relaxed),
176 (Relaxed, Relaxed),
177 ] {
178 assert_eq!(
179 MemoryOrdering::cmpxchg_failure_rejection(success, failure),
180 None,
181 "{success} / {failure}"
182 );
183 }
184 for (success, failure) in [
185 (SeqCst, Release),
186 (SeqCst, AcqRel),
187 (Relaxed, Release),
188 (Acquire, SeqCst),
189 (AcqRel, SeqCst),
190 (Relaxed, Acquire),
191 ] {
192 assert!(
193 MemoryOrdering::cmpxchg_failure_rejection(success, failure).is_some(),
194 "{success} / {failure}"
195 );
196 }
197 }
198
199 #[test]
200 fn tls_and_ordering_names_round_trip_to_text() {
201 assert_eq!(TlsModel::LocalExec.as_str(), "local_exec");
202 assert_eq!(TlsModel::InitialExec.to_string(), "initial_exec");
203 assert_eq!(MemoryOrdering::AcqRel.to_string(), "acqrel");
204 assert_eq!(MemoryOrdering::SeqCst.to_string(), "seqcst");
205 }
206}