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