palette/
bool_mask.rs

1//! Traits for abstracting over Boolean types.
2//!
3//! These traits are mainly useful for allowing SIMD values, where bit masks are
4//! typically used instead of `bool`.
5
6use core::ops::{BitAnd, BitOr, BitXor, Not};
7
8#[cfg(feature = "wide")]
9mod wide;
10
11/// Associates a Boolean type to the implementing type.
12///
13/// This is primarily used in traits and functions that can accept SIMD values
14/// and return a Boolean result. SIMD values use masks to select different values for
15/// each lane and `HasBoolMask::Mask` can be used to know which type that mask
16/// has.
17pub trait HasBoolMask {
18    /// The mask type to use for selecting `Self` values.
19    type Mask: BoolMask;
20}
21
22impl<T> HasBoolMask for &'_ T
23where
24    T: HasBoolMask,
25{
26    type Mask = T::Mask;
27}
28
29impl<T> HasBoolMask for &'_ mut T
30where
31    T: HasBoolMask,
32{
33    type Mask = T::Mask;
34}
35
36impl<T> HasBoolMask for [T]
37where
38    T: HasBoolMask,
39{
40    type Mask = T::Mask;
41}
42
43impl<T, const N: usize> HasBoolMask for [T; N]
44where
45    T: HasBoolMask,
46{
47    type Mask = T::Mask;
48}
49
50macro_rules! impl_has_bool_mask {
51    ($($ty:ident),+) => {
52        $(
53            impl HasBoolMask for $ty {
54                type Mask = bool;
55            }
56        )+
57    };
58}
59
60impl_has_bool_mask!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, f32, f64);
61
62/// Basic methods for boolean masks.
63pub trait BoolMask {
64    /// Create a new mask where each lane is set to `value`.
65    #[must_use]
66    fn from_bool(value: bool) -> Self;
67
68    /// Checks if all lanes in the mask are `true`.
69    #[must_use]
70    fn is_true(&self) -> bool;
71
72    /// Checks if all lanes in the mask are `false`.
73    #[must_use]
74    fn is_false(&self) -> bool;
75}
76
77impl BoolMask for bool {
78    #[inline]
79    fn from_bool(value: bool) -> Self {
80        value
81    }
82
83    #[inline]
84    fn is_true(&self) -> bool {
85        *self
86    }
87
88    #[inline]
89    fn is_false(&self) -> bool {
90        !*self
91    }
92}
93
94/// Makes a mask bale to select between two values.
95pub trait Select<T>
96where
97    T: HasBoolMask<Mask = Self>,
98{
99    /// Select lanes from `a` when corresponding lanes in `self` are `true`, and
100    /// select from `b` when `false`.
101    #[must_use]
102    fn select(self, a: T, b: T) -> T;
103}
104
105impl<T> Select<T> for bool
106where
107    T: HasBoolMask<Mask = Self>,
108{
109    #[inline(always)]
110    fn select(self, a: T, b: T) -> T {
111        if self {
112            a
113        } else {
114            b
115        }
116    }
117}
118
119/// Like [`Select`], but can avoid evaluating the input.
120pub trait LazySelect<T>: Select<T>
121where
122    T: HasBoolMask<Mask = Self>,
123{
124    /// Select lanes from the output of `a` when corresponding lanes in `self`
125    /// are `true`, and select from the output of `b` when `false`. May avoid
126    /// evaluating either option if it's not selected.
127    #[must_use]
128    fn lazy_select<A, B>(self, a: A, b: B) -> T
129    where
130        A: FnOnce() -> T,
131        B: FnOnce() -> T;
132}
133
134impl<T> LazySelect<T> for bool
135where
136    T: HasBoolMask<Mask = Self>,
137{
138    #[inline(always)]
139    fn lazy_select<A, B>(self, a: A, b: B) -> T
140    where
141        A: FnOnce() -> T,
142        B: FnOnce() -> T,
143    {
144        if self {
145            a()
146        } else {
147            b()
148        }
149    }
150}
151
152/// A helper trait that collects bit traits under one name.
153pub trait BitOps:
154    Sized
155    + BitAnd<Output = Self>
156    + BitOr<Output = Self>
157    + BitXor<Output = Self>
158    + Not<Output = Self>
159    + for<'a> BitAnd<&'a Self, Output = Self>
160    + for<'a> BitOr<&'a Self, Output = Self>
161    + for<'a> BitXor<&'a Self, Output = Self>
162{
163}
164
165impl<T> BitOps for T where
166    T: Sized
167        + BitAnd<Output = Self>
168        + BitOr<Output = Self>
169        + BitXor<Output = Self>
170        + Not<Output = Self>
171        + for<'a> BitAnd<&'a Self, Output = Self>
172        + for<'a> BitOr<&'a Self, Output = Self>
173        + for<'a> BitXor<&'a Self, Output = Self>
174{
175}