linux_futex/
op.rs

1//! Arguments to the [`wake_op`][crate::Futex::wake_op] function.
2
3/// The operation [`wake_op`][crate::Futex::wake_op] applies to the second futex.
4///
5/// An [`Op`] must be combined with a [`Cmp`] by using the plus operator. For
6/// example: `Op::assign(1) + Cmp::eq(0)`
7///
8/// The argument to any operation must be below `1 << 12` (= 4096).
9#[derive(Clone, Copy, PartialEq, Eq)]
10pub struct Op {
11	bits: u32,
12}
13
14impl Op {
15	/// Assign the argument to the futex value: `value = arg`
16	#[inline]
17	pub fn assign(arg: u32) -> Self {
18		Self::new(0, arg)
19	}
20
21	/// Add the argument to the futex value: `value += arg`
22	#[inline]
23	pub fn add(arg: u32) -> Self {
24		Self::new(1, arg)
25	}
26
27	/// Bitwise-or the futex value with the argument: `value |= arg`
28	#[inline]
29	pub fn or(arg: u32) -> Self {
30		Self::new(2, arg)
31	}
32
33	/// Bitwise-and the futex value with the bitwise complement of the argument: `value &= !arg`
34	#[inline]
35	pub fn and_not(arg: u32) -> Self {
36		Self::new(3, arg)
37	}
38
39	/// Xor the futex value with the argument: `value ^= arg`
40	#[inline]
41	pub fn xor(arg: u32) -> Self {
42		Self::new(4, arg)
43	}
44
45	/// Assign `1 << bit` to the futex value: `value = 1 << bit`
46	#[inline]
47	pub fn assign_bit(bit: u32) -> Self {
48		Self::new(8, bit)
49	}
50
51	/// Add `1 << bit` to the futex value: `value += 1 << bit`
52	#[inline]
53	pub fn add_bit(bit: u32) -> Self {
54		Self::new(9, bit)
55	}
56
57	/// Set the `bit`th bit of the futex value: `value |= 1 << bit`
58	#[inline]
59	pub fn set_bit(bit: u32) -> Self {
60		Self::new(10, bit)
61	}
62
63	/// Clear the `bit`th bit of the futex value: `value &= !(1 << bit)`
64	#[inline]
65	pub fn clear_bit(bit: u32) -> Self {
66		Self::new(11, bit)
67	}
68
69	/// Toggle the `bit`th bit of the futex value: `value ^= 1 << bit`
70	#[inline]
71	pub fn toggle_bit(bit: u32) -> Self {
72		Self::new(12, bit)
73	}
74
75	#[inline]
76	fn new(op: u32, value: u32) -> Self {
77		if value >= 1 << 12 {
78			panic!("Value too large: {}", value);
79		}
80		Self {
81			bits: value << 12 | op << 28,
82		}
83	}
84}
85
86impl std::fmt::Debug for Op {
87	fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
88		let op = match self.bits >> 28 {
89			0 => "assign",
90			1 => "add",
91			2 => "or",
92			3 => "and_not",
93			4 => "xor",
94			8 => "assign_bit",
95			9 => "add_bit",
96			10 => "set_bit",
97			11 => "clear_bit",
98			12 => "toggle_bit",
99			_ => "invalid",
100		};
101		write!(f, "Op::{}({})", op, self.bits >> 12 & 0xFFF)
102	}
103}
104
105/// The comparison [`wake_op`][crate::Futex::wake_op] applies to the old value of the second futex.
106///
107/// A [`Cmp`] must be combined with an [`Op`] by using the plus operator. For
108/// example: `Op::assign(1) + Cmp::eq(0)`
109///
110/// The argument to any comparison must be below `1 << 12` (= 4096).
111#[derive(Clone, Copy, PartialEq, Eq)]
112pub struct Cmp {
113	bits: u32,
114}
115
116impl Cmp {
117	/// Check if the old value of the futex equals this value.
118	#[inline]
119	pub fn eq(value: u32) -> Self {
120		Self::new(0, value)
121	}
122
123	/// Check if the old value of the futex does not equal this value.
124	#[inline]
125	pub fn ne(value: u32) -> Self {
126		Self::new(1, value)
127	}
128
129	/// Check if the old value of the futex is less than this value.
130	#[inline]
131	pub fn lt(value: u32) -> Self {
132		Self::new(2, value)
133	}
134
135	/// Check if the old value of the futex is less than or equal to this value.
136	#[inline]
137	pub fn le(value: u32) -> Self {
138		Self::new(3, value)
139	}
140
141	/// Check if the old value of the futex is greater than this value.
142	#[inline]
143	pub fn gt(value: u32) -> Self {
144		Self::new(4, value)
145	}
146
147	/// Check if the old value of the futex is greater than or equal to this value.
148	#[inline]
149	pub fn ge(value: u32) -> Self {
150		Self::new(5, value)
151	}
152
153	#[inline]
154	fn new(op: u32, value: u32) -> Self {
155		if value >= 1 << 12 {
156			panic!("Value too large: {}", value);
157		}
158		Self {
159			bits: value | op << 24,
160		}
161	}
162}
163
164impl std::fmt::Debug for Cmp {
165	fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
166		let op = match self.bits >> 24 & 0xF {
167			0 => "eq",
168			1 => "ne",
169			2 => "lt",
170			3 => "le",
171			4 => "gt",
172			5 => "ge",
173			_ => "invalid",
174		};
175		write!(f, "Cmp::{}({})", op, self.bits & 0xFFF)
176	}
177}
178
179/// The operation and comparison [`wake_op`][crate::Futex::wake_op] applies to the second futex.
180///
181/// See [`Op`] and [`Cmp`].
182///
183/// To obtain a [`OpAndCmp`], an [`Op`] and [`Cmp`] must be combined by using
184/// the plus operator. For example: `Op::assign(1) + Cmp::eq(0)`
185#[derive(Clone, Copy, PartialEq, Eq)]
186pub struct OpAndCmp {
187	bits: u32,
188}
189
190impl OpAndCmp {
191	#[inline]
192	pub const fn from_raw_bits(bits: u32) -> Self {
193		Self { bits }
194	}
195
196	#[inline]
197	pub const fn raw_bits(self) -> u32 {
198		self.bits
199	}
200}
201
202impl std::ops::Add<Cmp> for Op {
203	type Output = OpAndCmp;
204	#[inline]
205	fn add(self, cmp: Cmp) -> OpAndCmp {
206		OpAndCmp {
207			bits: self.bits | cmp.bits,
208		}
209	}
210}
211
212impl std::fmt::Debug for OpAndCmp {
213	fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
214		write!(
215			f,
216			"{:?} + {:?}",
217			Op { bits: self.bits },
218			Cmp { bits: self.bits }
219		)
220	}
221}