abibool/
lib.rs

1#![doc = include_str!("../Readme.md")]
2#![no_std]
3
4use core::borrow::Borrow;
5use core::cmp::Ordering;
6use core::fmt::{self, Debug, Display, Formatter};
7use core::hash::{Hash, Hasher};
8use core::mem::transmute;
9use core::ops::{Deref, DerefMut, Not};
10
11// XXX: REMOVEME: Get rid of these defs in the next breaking revision of abibool.
12// They're too winapi specific.  See other "XXX: REMOVEME: " comments for thoughts.
13use i32 as BOOL;    // use winapi::shared::minwindef::BOOL;
14use u8 as BOOLEAN;  // use winapi::shared::minwindef::BOOLEAN;
15
16
17/// 8-bit boolean type that's ABI-compatible with Win32's [BOOLEAN].
18///
19/// 99% of the time, you should prefer [bool] in your interfaces and simply convert between types.
20/// However, some windows APIs take [BOOLEAN] arrays, or contain structures with [BOOLEAN]s.
21/// [bool8] can be used in these cases to avoid the need for internal allocations or conversions for mere ABI conversions.
22///
23/// `0` is `false`y, all other bit patterns are `true`thy.
24///
25/// [BOOLEAN]:      https://docs.microsoft.com/en-us/windows/win32/winprog/windows-data-types#BOOLEAN
26#[allow(non_camel_case_types)] // Okay, `bool8` is kind of a weird type name I agree... warranted in this case though IMO
27#[derive(Clone, Copy)]
28#[repr(transparent)] pub struct bool8(BOOLEAN);
29pub use bool8 as b8;
30
31impl bool8 {
32    /// bool8(`0`)
33    pub const FALSE : bool8 = bool8(0);
34
35    /// bool8(`1`)
36    pub const TRUE  : bool8 = bool8(1);
37
38    pub fn from(value: impl Into<Self>) -> Self { value.into() }
39}
40
41/// 32-bit boolean type that's ABI-compatible with Win32's [BOOL].
42///
43/// 99% of the time, you should prefer [bool] in your interfaces and simply convert between types.
44/// However, some windows APIs take [BOOL] arrays, or contain structures with [BOOL]s.
45/// [bool32] can be used in these cases to avoid the need for internal allocations or conversions for mere ABI conversions.
46///
47/// `0` is `false`y, all other bit patterns are `true`thy.
48///
49/// [BOOL]:         https://docs.microsoft.com/en-us/windows/win32/winprog/windows-data-types#BOOL
50#[allow(non_camel_case_types)] // Okay, `bool32` is kind of a weird type name I agree... warranted in this case though IMO
51#[derive(Clone, Copy)]
52#[repr(transparent)] pub struct bool32(BOOL);
53pub use bool32 as b32;
54
55impl bool32 {
56    /// bool32(`0`)
57    pub const FALSE : bool32 = bool32(0);
58
59    /// bool32(`1`)
60    pub const TRUE  : bool32 = bool32(1);
61
62    pub fn from(value: impl Into<Self>) -> Self { value.into() }
63}
64
65
66
67impl AsRef<bool>  for bool8  { fn as_ref(&self) -> &bool { if bool::from(*self) { &true } else { &false } } }
68impl AsRef<bool>  for bool32 { fn as_ref(&self) -> &bool { if bool::from(*self) { &true } else { &false } } }
69
70impl Borrow<bool> for bool8  { fn borrow(&self) -> &bool { if bool::from(*self) { &true } else { &false } } }
71impl Borrow<bool> for bool32 { fn borrow(&self) -> &bool { if bool::from(*self) { &true } else { &false } } }
72
73// DON'T IMPLEMENT:
74//  impl Borrow<BOOLEAN> for bool8  { ... }
75//  impl Borrow<BOOL   > for bool32 { ... }
76// "In particular Eq, Ord and Hash must be equivalent for borrowed and owned values" (https://doc.rust-lang.org/std/borrow/trait.Borrow.html)
77// We've gone to pains to make bool32 behave very much like bool, with `true` acting like a single value, even when the internal BOOL might be another truthy value like `-1`.
78
79// XXX: REMOVEME:  Too winapi specific, prone to misuse.  Main intent here is FFI interop.
80// Replace with `as_[mut_]_ptr` type constrained to matching-size integer types?
81impl Deref for bool8  { type Target = BOOLEAN; fn deref(&self) -> &Self::Target { &self.0 } }
82impl Deref for bool32 { type Target = BOOL;    fn deref(&self) -> &Self::Target { &self.0 } }
83impl DerefMut for bool8  { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } }
84impl DerefMut for bool32 { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } }
85
86impl Default for bool8  { fn default() -> Self { Self::FALSE } }
87impl Default for bool32 { fn default() -> Self { Self::FALSE } }
88impl Debug   for bool8  { fn fmt(&self, f: &mut Formatter) -> fmt::Result { Debug  ::fmt(&bool::from(*self), f) } }
89impl Debug   for bool32 { fn fmt(&self, f: &mut Formatter) -> fmt::Result { Debug  ::fmt(&bool::from(*self), f) } }
90impl Display for bool8  { fn fmt(&self, f: &mut Formatter) -> fmt::Result { Display::fmt(&bool::from(*self), f) } }
91impl Display for bool32 { fn fmt(&self, f: &mut Formatter) -> fmt::Result { Display::fmt(&bool::from(*self), f) } }
92
93impl From<bool   > for bool8   { fn from(value: bool   ) -> Self { Self(value as _) } }
94impl From<bool   > for bool32  { fn from(value: bool   ) -> Self { Self(value as _) } }
95impl From<BOOLEAN> for bool8   { fn from(value: BOOLEAN) -> Self { Self(value) } } // XXX: REMOVEME: replace with `{u,i}8`?
96impl From<BOOL   > for bool32  { fn from(value: BOOL   ) -> Self { Self(value) } } // XXX: REMOVEME: replace with `{u,i}32`?
97impl From<bool8  > for BOOLEAN { fn from(value: bool8  ) -> Self { value.0 } } // XXX: REMOVEME: replace with `{u,i}8`?
98impl From<bool32 > for BOOL    { fn from(value: bool32 ) -> Self { value.0 } } // XXX: REMOVEME: replace with `{u,i}32`?
99impl From<bool8  > for bool    { fn from(value: bool8  ) -> Self { value.0 != 0 } }
100impl From<bool32 > for bool    { fn from(value: bool32 ) -> Self { value.0 != 0 } }
101
102impl From<&BOOLEAN> for &bool8   { fn from(value: &BOOLEAN) -> Self { unsafe { transmute(value) } } } // XXX: REMOVEME: replace with `{u,i}8`?
103impl From<&BOOL   > for &bool32  { fn from(value: &BOOL   ) -> Self { unsafe { transmute(value) } } } // XXX: REMOVEME: replace with `{u,i}32`?
104impl From<&bool8  > for &BOOLEAN { fn from(value: &bool8  ) -> Self { unsafe { transmute(value) } } } // XXX: REMOVEME: replace with `{u,i}8`?
105impl From<&bool32 > for &BOOL    { fn from(value: &bool32 ) -> Self { unsafe { transmute(value) } } } // XXX: REMOVEME: replace with `{u,i}32`?
106
107// slices are always foreign, so we can't implement these - transmute yourself I guess
108// impl From<&[BOOLEAN]> for &[bool8  ] { fn from(value: &[BOOLEAN]) -> Self { unsafe { transmute(value) } } }
109// impl From<&[BOOL   ]> for &[bool32 ] { fn from(value: &[BOOL   ]) -> Self { unsafe { transmute(value) } } }
110// impl From<&[bool8  ]> for &[BOOLEAN] { fn from(value: &[bool8  ]) -> Self { unsafe { transmute(value) } } }
111// impl From<&[bool32 ]> for &[BOOL   ] { fn from(value: &[bool32 ]) -> Self { unsafe { transmute(value) } } }
112
113// All comparisons, hashes, etc. are based on truthiness, not the underlying bit patterns!
114
115impl Not               for bool8  { type Output = bool; fn not(self) -> Self::Output { self.0 == 0 } }
116impl Not               for bool32 { type Output = bool; fn not(self) -> Self::Output { self.0 == 0 } }
117
118impl Eq                for bool8  {}
119impl Eq                for bool32 {}
120impl PartialEq<bool8 > for bool8  { fn eq(&self, other: &bool8 ) -> bool { bool::from(*self) == bool::from(*other) } }
121impl PartialEq<bool32> for bool32 { fn eq(&self, other: &bool32) -> bool { bool::from(*self) == bool::from(*other) } }
122impl PartialEq<bool8 > for bool32 { fn eq(&self, other: &bool8 ) -> bool { bool::from(*self) == bool::from(*other) } }
123impl PartialEq<bool32> for bool8  { fn eq(&self, other: &bool32) -> bool { bool::from(*self) == bool::from(*other) } }
124
125impl PartialEq<bool  > for bool8  { fn eq(&self, other: &bool  ) -> bool { bool::from(*self) == *other } }
126impl PartialEq<bool  > for bool32 { fn eq(&self, other: &bool  ) -> bool { bool::from(*self) == *other } }
127impl PartialEq<bool8 > for bool   { fn eq(&self, other: &bool8 ) -> bool { bool::from(*other) == *self } }
128impl PartialEq<bool32> for bool   { fn eq(&self, other: &bool32) -> bool { bool::from(*other) == *self } }
129
130impl PartialOrd<bool8 > for bool8  { fn partial_cmp(&self, other: &bool8 ) -> Option<Ordering> { PartialOrd::partial_cmp(&bool::from(*self), &bool::from(*other)) } }
131impl PartialOrd<bool32> for bool32 { fn partial_cmp(&self, other: &bool32) -> Option<Ordering> { PartialOrd::partial_cmp(&bool::from(*self), &bool::from(*other)) } }
132impl PartialOrd<bool8 > for bool32 { fn partial_cmp(&self, other: &bool8 ) -> Option<Ordering> { PartialOrd::partial_cmp(&bool::from(*self), &bool::from(*other)) } }
133impl PartialOrd<bool32> for bool8  { fn partial_cmp(&self, other: &bool32) -> Option<Ordering> { PartialOrd::partial_cmp(&bool::from(*self), &bool::from(*other)) } }
134
135impl PartialOrd<bool  > for bool8  { fn partial_cmp(&self, other: &bool  ) -> Option<Ordering> { PartialOrd::partial_cmp(&bool::from(*self), other) } }
136impl PartialOrd<bool  > for bool32 { fn partial_cmp(&self, other: &bool  ) -> Option<Ordering> { PartialOrd::partial_cmp(&bool::from(*self), other) } }
137impl PartialOrd<bool8 > for bool   { fn partial_cmp(&self, other: &bool8 ) -> Option<Ordering> { PartialOrd::partial_cmp(self, &bool::from(*other)) } }
138impl PartialOrd<bool32> for bool   { fn partial_cmp(&self, other: &bool32) -> Option<Ordering> { PartialOrd::partial_cmp(self, &bool::from(*other)) } }
139
140impl Ord for bool8  { fn cmp(&self, other: &bool8 ) -> Ordering { Ord::cmp(&bool::from(*self), &bool::from(*other)) } }
141impl Ord for bool32 { fn cmp(&self, other: &bool32) -> Ordering { Ord::cmp(&bool::from(*self), &bool::from(*other)) } }
142
143impl Hash for bool8  { fn hash<H: Hasher>(&self, state: &mut H) { bool::from(*self).hash(state) } }
144impl Hash for bool32 { fn hash<H: Hasher>(&self, state: &mut H) { bool::from(*self).hash(state) } }
145
146#[cfg(feature = "bytemuck")] mod _bytemuck {
147    use super::*;
148
149    unsafe impl bytemuck::Pod for bool8  {}
150    unsafe impl bytemuck::Pod for bool32 {}
151    unsafe impl bytemuck::Zeroable for bool8  {}
152    unsafe impl bytemuck::Zeroable for bool32 {}
153}