diff --git a/Cargo.toml b/Cargo.toml index c38b284..b9adc3b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ edition = "2024" default = ["alloc"] alloc = [] std = ["alloc"] +transposed-option = ["nightly"] nightly = [] [dependencies] diff --git a/src/lib.rs b/src/lib.rs index e263396..a4d7735 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,6 @@ #![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(feature = "nightly", feature(strict_provenance_atomic_ptr))] +#![cfg_attr(feature = "transposed-option", feature(try_trait_v2))] #[cfg(any(test, feature = "std", feature = "alloc"))] extern crate alloc; @@ -10,6 +11,8 @@ extern crate std; pub mod atomic; pub mod cachepadded; pub mod drop_guard; +#[cfg(feature = "transposed-option")] +pub mod option; pub mod ptr; pub mod rand; #[cfg(feature = "alloc")] diff --git a/src/option.rs b/src/option.rs new file mode 100644 index 0000000..fdddc81 --- /dev/null +++ b/src/option.rs @@ -0,0 +1,98 @@ +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Default)] +pub enum TransposedOption { + #[default] + None, + Some(T), +} + +impl TransposedOption { + pub fn new(value: T) -> Self { + TransposedOption::Some(value) + } + + pub fn is_none(&self) -> bool { + matches!(self, TransposedOption::None) + } + + pub fn map(self, f: F) -> TransposedOption + where + F: FnOnce(T) -> U, + { + use TransposedOption::*; + match self { + Some(value) => Some(f(value)), + None => None, + } + } + + pub fn and_then(self, f: F) -> TransposedOption + where + F: FnOnce(T) -> TransposedOption, + { + use TransposedOption::*; + match self { + Some(value) => f(value), + None => None, + } + } +} + +impl From> for TransposedOption { + fn from(option: Option) -> Self { + match option { + Some(value) => TransposedOption::Some(value), + None => TransposedOption::None, + } + } +} + +impl From> for Option { + fn from(transposed: TransposedOption) -> Self { + match transposed { + TransposedOption::Some(value) => Some(value), + TransposedOption::None => None, + } + } +} + +impl core::ops::Try for TransposedOption { + type Output = TransposedOption; + type Residual = T; + + fn from_output(_: Self::Output) -> Self { + use TransposedOption::*; + None + } + + fn branch(self) -> std::ops::ControlFlow { + use TransposedOption::*; + match self { + Some(value) => std::ops::ControlFlow::Break(value), + None => std::ops::ControlFlow::Continue(None), + } + } +} + +impl, U> core::ops::FromResidual for TransposedOption { + fn from_residual(residual: U) -> Self { + Self::new(residual.into()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use TransposedOption::*; + + #[test] + fn transposed_option_try() { + let a: TransposedOption = try { + TransposedOption::Some(42)?; + None::?; + + Some(3) + }; + + assert_eq!(a, TransposedOption::Some(42)); + } +}