pub struct ConcurrentOption<T> { /* private fields */ }
Expand description
ConcurrentOption is a thread-safe and lock-free read-write option type.
§ConcurrentOption Methods In Groups
ConcurrentOption methods are based on the standard Option with minor differences in order to better fit concurrent programs.
For example, instead of fn map<U, F>(self, f: F) -> Option<U>
- ConcurrentOption implements
fn map<U, F>(&self, f: F) -> Option<U>
which is specialized to map over the reference while guaranteeing the lack of data race. - Note that the prior result can trivially be obtained by
maybe.exclusive_take().map(f)
when we have the ownership.
§⬤ Methods requiring self or &mut self
These methods are safe by the borrow checker and they behave similar to the original variants.
In order to separate them from the thread-safe versions, methods requiring &mut self
are prefixed with exclusive_.
Some such methods are unwrap
, expect
, exclusive_mut
or exclusive_take
.
§⬤ Thread safe versions of mutating methods
Thread safe variants of mutating methods are available and they can be safely be called with a shared &self
reference.
Some examples are take
, take_if
, replace
, etc.
These methods guarantee that there exist no other mutation or no reading during the mutation.
§⬤ Thread safe versions of read methods
Thread safe variants of methods which access the underlying value to calculate a result are available.
Some examples are is_some
, map
, and_then
, etc.
These methods guarantee that there exist no mutation while reading the data.
§⬤ Partially thread safe methods
Methods which return a shared reference &T
or mutable reference &mut T
to the underlying value of the optional are marked as unsafe
.
These methods internally guarantee the creation of a valid reference in the absence of a data race. In this sense, they are thread safe.
On the other hand, since they return the reference, the reference is leaked outside the type. A succeeding mutation might lead to a data race, and hence, to an undefined behavior.
Some example methods are as_ref
, as_deref
, insert
, etc.
§⬤ Methods to allow manual control on concurrency
ConcurrentOption also exposes methods which accepts a core::sync::atomic::Ordering
and gives the control to the caller. These methods are suffixed with with_order, except for the state.
Some such methods are state
, as_ref_with_order
, get_raw_with_order
, clone_with_order
, etc.
§Examples
§Concurrent Read & Write
The following example demonstrates the ease of concurrently mutating the state of the option while safely reading the underlying data with multiple reader and writer threads.
use orx_concurrent_option::*;
use std::time::Duration;
enum MutOperation {
InitializeIfNone,
UpdateIfSome,
Replace,
Take,
TakeIf,
}
impl MutOperation {
fn new(i: usize) -> Self {
match i % 5 {
0 => Self::InitializeIfNone,
1 => Self::UpdateIfSome,
2 => Self::Replace,
3 => Self::Take,
_ => Self::TakeIf,
}
}
}
let num_readers = 8;
let num_writers = 8;
let values = vec![ConcurrentOption::<String>::none(); 8];
std::thread::scope(|s| {
for _ in 0..num_readers {
s.spawn(|| {
for _ in 0..100 {
std::thread::sleep(Duration::from_millis(100));
let mut num_chars = 0;
for maybe in &values {
// concurrently access the value
num_chars += maybe.map(|x| x.len()).unwrap_or(0);
}
assert!(num_chars <= 100);
}
});
}
for _ in 0..num_writers {
s.spawn(|| {
for i in 0..100 {
std::thread::sleep(Duration::from_millis(100));
let e = i % values.len();
// concurrently update the option
match MutOperation::new(i) {
MutOperation::InitializeIfNone => {
values[e].initialize_if_none(e.to_string());
}
MutOperation::UpdateIfSome => {
values[e].update_if_some(|x| *x = format!("{}!", x));
}
MutOperation::Replace => {
values[e].replace(e.to_string());
}
MutOperation::Take => {
_ = values[e].take();
}
MutOperation::TakeIf => _ = values[e].take_if(|x| x.len() < 2),
}
let e = i % values.len();
_ = values[e].initialize_if_none(e.to_string());
}
});
}
})
§Concurrent Initialize & Read
A common use case for option is to model a delayed initialization; rather than concurrent mutation. In other words, we start with a None variant and at some point we receive the value and convert our option to Some(value), which will then stay as Some(value) throughout its lifetime.
This scenario demonstrates a use case where we can safely leak a reference outside the optional:
- All references provided by ConcurrentOption are valid and data race free at the point they are obtained. In other words, we can only obtain a reference after the value is initialized; i.e., the option becomes Some(value).
- Since we will never mutate the option after initialization, we can safely keep a reference to it without a concern about a data race.
- However, no further mutation is our promise and responsibility as the caller. ConcurrentOption has no control over the leaked references; and hence, obtaining the reference is through the unsafe
as_ref
method.
- However, no further mutation is our promise and responsibility as the caller. ConcurrentOption has no control over the leaked references; and hence, obtaining the reference is through the unsafe
For this scenario, we can make use of two matching methods:
initialize_if_none
is a thread safe method to initialize the value of the option to the given value. It is safe to call the method on a Some variant, it will have no impact. Further, it makes sure that no reader can access the value until it is completely initialized.as_ref
method returns a reference to the underlying value if the option is a Some variant. Otherwise, if the value has not been initialized, we will safely receive None. Note that we could also useas_ref_with_order
paired up withAcquire
orSeqCst
ordering if we want to model the access ordering manually.
use orx_concurrent_option::*;
fn reader(maybe: &ConcurrentOption<String>) {
let mut is_none_at_least_once = false;
let mut is_seven_at_least_once = false;
for _ in 0..100 {
std::thread::sleep(std::time::Duration::from_millis(100));
let read = unsafe { maybe.as_ref() };
let is_none = read.is_none();
let is_seven = read == Some(&7.to_string());
assert!(is_none || is_seven);
is_none_at_least_once |= is_none;
is_seven_at_least_once |= is_seven;
}
assert!(is_none_at_least_once && is_seven_at_least_once);
}
fn initializer(maybe: &ConcurrentOption<String>) {
for _ in 0..50 {
// wait for a while to simulate a delay
std::thread::sleep(std::time::Duration::from_millis(100));
}
let _ = maybe.initialize_if_none(7.to_string());
for _ in 0..50 {
// it is safe to call `initialize_if_none` on Some variant
// it will do nothing
let inserted = maybe.initialize_if_none(1_000_000.to_string());
assert!(!inserted);
}
}
let num_readers = 8;
let num_writers = 8;
let maybe = ConcurrentOption::<String>::none();
let maybe_ref = &maybe;
std::thread::scope(|s| {
for _ in 0..num_readers {
s.spawn(|| reader(maybe_ref));
}
for _ in 0..num_writers {
s.spawn(|| initializer(maybe_ref));
}
});
assert_eq!(maybe.unwrap(), 7.to_string());
Implementations§
Source§impl<T> ConcurrentOption<T>
impl<T> ConcurrentOption<T>
Sourcepub fn initialize_if_none(&self, value: T) -> bool
pub fn initialize_if_none(&self, value: T) -> bool
Thread safe method to initiate the value of the option with the given value
.
- Returns
true
if the option wasis_none
variant and initiated with the given value. - It does nothing if the concurrent option is already of
is_some
variant, and returnsfalse
.
Note that it is safe to call this method with a shared reference &self
.
This method is particularly useful for enabling concurrent read & write operations, while the value is expected to be initialized only once.
§Suggestion on Concurrent Read & Write Operations
Note that this is a one-time-write method which can happen safely while other threads are reading the option.
It is however recommended to call read-methods with a &self
reference,
such as as_ref
, using an ordering stronger than Relaxed
, such as Acquire
or SeqCst
,
if one or more threads are expected to call write methods initialize_if_none
or initialize_unchecked
concurrently.
§Example
use orx_concurrent_option::*;
let x = ConcurrentOption::<String>::none();
let inserted = x.initialize_if_none(3.to_string());
assert!(inserted);
assert_eq!(unsafe { x.as_ref() }, Some(&3.to_string()));
let x = ConcurrentOption::some(7.to_string());
let inserted = x.initialize_if_none(3.to_string()); // does nothing
assert!(!inserted);
assert_eq!(unsafe { x.as_ref() }, Some(&7.to_string()));
A more advanced and useful example is demonstrated below:
- there exist multiple readers checking the value of an optional; they will receive
- None if the value is not initialized yet;
- a reference to the value otherwise.
- there exist multiple initializers each trying to set the value of optional;
- only the first one will succeed,
- since this is an initialization method, succeeding calls will safely be ignored.
use orx_concurrent_option::*;
fn reader(maybe: &ConcurrentOption<String>) {
let mut is_none_at_least_once = false;
let mut is_seven_at_least_once = false;
for _ in 0..100 {
std::thread::sleep(std::time::Duration::from_millis(100));
let read = unsafe { maybe.as_ref() };
let is_none = read.is_none();
let is_seven = read == Some(&7.to_string());
assert!(is_none || is_seven);
is_none_at_least_once |= is_none;
is_seven_at_least_once |= is_seven;
}
assert!(is_none_at_least_once && is_seven_at_least_once);
}
fn initializer(maybe: &ConcurrentOption<String>) {
for _ in 0..50 {
// wait for a while to simulate a delay
std::thread::sleep(std::time::Duration::from_millis(100));
}
let _ = maybe.initialize_if_none(7.to_string());
for _ in 0..50 {
// it is safe to call `initialize_if_none` on Some variant, it will do nothing
let inserted = maybe.initialize_if_none(1_000_000.to_string());
assert!(!inserted);
}
}
let num_readers = 8;
let num_writers = 8;
let maybe = ConcurrentOption::<String>::none();
let maybe_ref = &maybe;
std::thread::scope(|s| {
for _ in 0..num_readers {
s.spawn(|| reader(maybe_ref));
}
for _ in 0..num_writers {
s.spawn(|| initializer(maybe_ref));
}
});
assert_eq!(maybe.unwrap(), 7.to_string());
Sourcepub unsafe fn initialize_unchecked(&self, value: T)
pub unsafe fn initialize_unchecked(&self, value: T)
Thread safe method to initiate the value of the option with the given value
provided that the concurrent option is_none
at the point of initializing.
See initialize_if_none
for checked version.
Note that it is safe to call this method with a shared reference &self
provided that the concurrent option is_none
at the point of initializing.
This method is particularly useful for enabling concurrent read & write operations, while the value is expected to be initialized only once.
§Safety
This method can be safely called when the concurrent option is guaranteed to be of None variant.
On the other hand, calling it when the option has a value leads to undefined behavior
due to the following possible data race where we can be reading the value with a &self
reference,
while at the same time writing with this unsafe method and a &self
reference.
§Suggestion on Concurrent Read & Write Operations
Note that this is a one-time-write method which can happen safely while other threads are reading the option.
It is however recommended to call read-methods with a &self
reference,
such as as_ref
, using an ordering stronger than Relaxed
, such as Acquire
or SeqCst
,
if one or more threads are expected to call write methods initialize_if_none
or initialize_unchecked
concurrently.
§Example
use orx_concurrent_option::*;
use core::sync::atomic::Ordering;
let x = ConcurrentOption::<String>::none();
unsafe { x.initialize_unchecked(3.to_string()) };
assert_eq!(unsafe { x.as_ref() }, Some(&3.to_string()));
#[cfg(not(miri))]
{
let x = ConcurrentOption::some(7.to_string());
unsafe { x.initialize_unchecked(3.to_string()) }; // undefined behavior!
assert_eq!(unsafe { x.as_ref() }, Some(&3.to_string()));
}
A more advanced and useful example is demonstrated below:
- there exist multiple readers checking the value of an optional; they will receive
- None if the value is not initialized yet;
- a reference to the value otherwise.
- there exist multiple initializers each trying to set the value of optional;
- only the first one will succeed,
- since this is an initialization method, succeeding calls will safely be ignored.
use orx_concurrent_option::*;
use core::sync::atomic::Ordering;
fn reader(maybe: &ConcurrentOption<String>) {
let mut is_none_at_least_once = false;
let mut is_seven_at_least_once = false;
for _ in 0..100 {
std::thread::sleep(std::time::Duration::from_millis(100));
let read = unsafe { maybe.as_ref() };
let is_none = read.is_none();
let is_seven = read == Some(&7.to_string());
assert!(is_none || is_seven);
is_none_at_least_once |= is_none;
is_seven_at_least_once |= is_seven;
}
assert!(is_none_at_least_once && is_seven_at_least_once);
}
fn unsafe_initializer(maybe: &ConcurrentOption<String>) {
for _ in 0..50 {
// wait for a while to simulate a delay
std::thread::sleep(std::time::Duration::from_millis(100));
}
// we need to make sure to call initialize_unchecked only once
unsafe { maybe.initialize_unchecked(7.to_string()) };
}
let num_readers = 8;
let maybe = ConcurrentOption::<String>::none();
let maybe_ref = &maybe;
std::thread::scope(|s| {
for _ in 0..num_readers {
s.spawn(|| reader(maybe_ref));
}
s.spawn(|| unsafe_initializer(maybe_ref));
});
assert_eq!(maybe.unwrap(), 7.to_string());
Sourcepub fn update_if_some<F>(&self, f: F) -> bool
pub fn update_if_some<F>(&self, f: F) -> bool
Thread safe method to update the value of the option if it is of Some variant. Does nothing if it is None. Returns whether or not the value is updated.
§Example
use orx_concurrent_option::*;
let maybe = ConcurrentOption::<String>::none();
let updated = maybe.update_if_some(|x| *x = format!("{}!", x));
assert!(maybe.is_none());
assert_eq!(updated, false);
let maybe = ConcurrentOption::some(42.to_string());
let updated = maybe.update_if_some(|x| *x = format!("{}!", x));
assert!(maybe.is_some_and(|x| x == &"42!".to_string()));
assert_eq!(updated, true);
Sourcepub fn take(&self) -> Option<T>
pub fn take(&self) -> Option<T>
Thread safe method to take the value out of the option if Some, leaving a None in its place.
Has no impact and returns None, if the option is of None variant.
§Examples
use orx_concurrent_option::*;
let x = ConcurrentOption::some(42);
let y = x.take();
assert_eq!(x, ConcurrentOption::none());
assert_eq!(y, Some(42));
let x: ConcurrentOption<u32> = ConcurrentOption::none();
let y = x.take();
assert_eq!(x, ConcurrentOption::none());
assert_eq!(y, None);
Sourcepub fn take_if<P>(&self, predicate: P) -> Option<T>
pub fn take_if<P>(&self, predicate: P) -> Option<T>
Thread safe method to take the value out of the option, but only if the predicate evaluates to
true
on a mutable reference to the value.
In other words, replaces self
with None if the predicate returns true
.
This method operates similar to ConcurrentOption::take
but conditional.
§Examples
use orx_concurrent_option::*;
let x = ConcurrentOption::some(42);
let prev = x.take_if(|v| if *v == 42 {
*v += 1;
false
} else {
false
});
assert_eq!(x, ConcurrentOption::some(43));
assert_eq!(prev, None);
let prev = x.take_if(|v| *v == 43);
assert_eq!(x, ConcurrentOption::none());
assert_eq!(prev, Some(43));
Sourcepub fn replace(&self, value: T) -> Option<T>
pub fn replace(&self, value: T) -> Option<T>
Thread safe method to replace the actual value in the option by the value given in parameter, returning the old value if present, leaving a Some in its place without de-initializing either one.
§Examples
use orx_concurrent_option::*;
let x = ConcurrentOption::some(2);
let old = x.replace(5);
assert_eq!(x, ConcurrentOption::some(5));
assert_eq!(old, Some(2));
let x: ConcurrentOption<u32> = ConcurrentOption::none();
let old = x.replace(3);
assert_eq!(x, ConcurrentOption::some(3));
assert_eq!(old, None);
Sourcepub unsafe fn insert(&self, value: T) -> &mut T
pub unsafe fn insert(&self, value: T) -> &mut T
Partially thread safe method to insert value
into the option, and then to return a mutable reference to it.
If the option already contains a value, the old value is dropped.
See also Option::get_or_insert
, which doesn’t update the value if
the option already contains Some.
§Safety
Note that the insertion part of this method is thread safe.
The method is unsafe
due to the returned mutable reference to the underlying value.
- It is safe to use this method if the returned mutable reference is discarded (miri would still complain).
- It is also safe to use this method if the caller is able to guarantee that there exist no concurrent reads or writes while mutating the value.
- Otherwise, it will lead to an Undefined Behavior due to data race.
§Examples
use orx_concurrent_option::*;
let opt: ConcurrentOption<_> = ConcurrentOption::none();
let val = unsafe { opt.insert(1) };
assert_eq!(*val, 1);
assert_eq!(unsafe { opt.as_ref() }, Some(&1));
let val = unsafe { opt.insert(2) };
assert_eq!(*val, 2);
*val = 3;
assert_eq!(opt.unwrap(), 3);
Sourcepub unsafe fn get_or_insert(&self, value: T) -> &mut T
pub unsafe fn get_or_insert(&self, value: T) -> &mut T
Inserts value
into the option if it is None, then
returns a mutable reference to the contained value.
See also ConcurrentOption::insert
, which updates the value even if
the option already contains Some.
§Safety
Note that the insertion part of this method is thread safe.
The method is unsafe
due to the returned mutable reference to the underlying value.
- It is safe to use this method if the returned mutable reference is discarded (miri would still complain).
- It is also safe to use this method if the caller is able to guarantee that there exist no concurrent reads or writes while mutating the value.
- Otherwise, it will lead to an Undefined Behavior due to data race.
§Examples
use orx_concurrent_option::*;
let x = ConcurrentOption::none();
{
let y: &mut u32 = unsafe { x.get_or_insert(5) };
assert_eq!(y, &5);
*y = 7;
}
assert_eq!(x, ConcurrentOption::some(7));
Sourcepub unsafe fn get_or_insert_with<F>(&self, f: F) -> &mut Twhere
F: FnOnce() -> T,
pub unsafe fn get_or_insert_with<F>(&self, f: F) -> &mut Twhere
F: FnOnce() -> T,
Partially thread safe method to insert a value computed from f
into the option if it is None,
then returns a mutable reference to the contained value.
§Safety
Note that the insertion part of this method is thread safe.
The method is unsafe
due to the returned mutable reference to the underlying value.
- It is safe to use this method if the returned mutable reference is discarded (miri would still complain).
- It is also safe to use this method if the caller is able to guarantee that there exist no concurrent reads or writes while mutating the value.
- Otherwise, it will lead to an Undefined Behavior due to data race.
§Examples
use orx_concurrent_option::*;
let x = ConcurrentOption::none();
{
let y: &mut u32 = unsafe { x.get_or_insert_with(|| 5) };
assert_eq!(y, &5);
*y = 7;
}
assert_eq!(x, ConcurrentOption::some(7));
Source§impl<T> ConcurrentOption<T>
impl<T> ConcurrentOption<T>
Sourcepub unsafe fn mut_handle(
&self,
initial_state: StateU8,
success_state: StateU8,
) -> Option<MutHandle<'_, T>>
pub unsafe fn mut_handle( &self, initial_state: StateU8, success_state: StateU8, ) -> Option<MutHandle<'_, T>>
Provides the mut handle on the value of the optional:
- the optional must be in the
initial_state
for this method to succeed, - the optional will be brought to
success_state
once the handle is dropped.
§Safety
This method is unsafe since the handle provides direct access to the underlying value, skipping thread-safety guarantees.
Source§impl<T> ConcurrentOption<T>
impl<T> ConcurrentOption<T>
Sourcepub fn exclusive_as_deref_mut(&mut self) -> Option<&mut <T as Deref>::Target>where
T: DerefMut,
pub fn exclusive_as_deref_mut(&mut self) -> Option<&mut <T as Deref>::Target>where
T: DerefMut,
Converts from Option<T>
(or &mut Option<T>
) to Option<&mut T::Target>
.
Leaves the original Option
in-place, creating a new one containing a mutable reference to
the inner type’s Deref::Target
type.
§Examples
use orx_concurrent_option::*;
let mut x: ConcurrentOption<String> = ConcurrentOption::some("hey".to_owned());
assert_eq!(x.exclusive_as_deref_mut().map(|x| {
x.make_ascii_uppercase();
x
}), Some("HEY".to_owned().as_mut_str()));
Sourcepub fn exclusive_as_mut(&mut self) -> Option<&mut T>
pub fn exclusive_as_mut(&mut self) -> Option<&mut T>
Converts from &mut Option<T>
to Option<&mut T>
.
§Examples
use orx_concurrent_option::*;
let mut x = ConcurrentOption::some(2);
match x.exclusive_as_mut() {
Some(v) => *v = 42,
None => {},
}
assert_eq!(unsafe { x.as_ref() }, Some(&42));
Sourcepub fn exclusive_take(&mut self) -> Option<T>
pub fn exclusive_take(&mut self) -> Option<T>
Takes the value out of the option, leaving a None in its place.
§Examples
use orx_concurrent_option::*;
let mut x = ConcurrentOption::some(42);
let y = x.exclusive_take();
assert_eq!(x, ConcurrentOption::none());
assert_eq!(y, Some(42));
let mut x: ConcurrentOption<u32> = ConcurrentOption::none();
let y = x.exclusive_take();
assert_eq!(x, ConcurrentOption::none());
assert_eq!(y, None);
Sourcepub fn exclusive_take_if<P>(&mut self, predicate: P) -> Option<T>
pub fn exclusive_take_if<P>(&mut self, predicate: P) -> Option<T>
Takes the value out of the option, but only if the predicate evaluates to
true
on a mutable reference to the value.
In other words, replaces self
with None if the predicate returns true
.
This method operates similar to ConcurrentOption::exclusive_take
but conditional.
§Examples
use orx_concurrent_option::*;
let mut x = ConcurrentOption::some(42);
let prev = x.exclusive_take_if(|v| if *v == 42 {
*v += 1;
false
} else {
false
});
assert_eq!(x, ConcurrentOption::some(43));
assert_eq!(prev, None);
let prev = x.exclusive_take_if(|v| *v == 43);
assert_eq!(x, ConcurrentOption::none());
assert_eq!(prev, Some(43));
Sourcepub fn exclusive_iter_mut(&mut self) -> IterMut<'_, T> ⓘ
pub fn exclusive_iter_mut(&mut self) -> IterMut<'_, T> ⓘ
Returns a mutable iterator over the possibly contained value; yields
- the single element if the option is of Some variant;
- no elements otherwise.
§Examples
use orx_concurrent_option::*;
let mut x = ConcurrentOption::some(4);
match x.exclusive_iter_mut().next() {
Some(v) => *v = 42,
None => {},
}
assert_eq!(x, ConcurrentOption::some(42));
let mut x: ConcurrentOption<u32> = ConcurrentOption::none();
assert_eq!(x.exclusive_iter_mut().next(), None);
Sourcepub fn exclusive_replace(&mut self, value: T) -> Option<T>
pub fn exclusive_replace(&mut self, value: T) -> Option<T>
Replaces the actual value in the option by the value given in parameter, returning the old value if present, leaving a Some in its place without de-initializing either one.
§Examples
use orx_concurrent_option::*;
let mut x = ConcurrentOption::some(2);
let old = x.exclusive_replace(5);
assert_eq!(x, ConcurrentOption::some(5));
assert_eq!(old, Some(2));
let mut x: ConcurrentOption<u32> = ConcurrentOption::none();
let old = x.exclusive_replace(3);
assert_eq!(x, ConcurrentOption::some(3));
assert_eq!(old, None);
Sourcepub fn exclusive_insert(&mut self, value: T) -> &mut T
pub fn exclusive_insert(&mut self, value: T) -> &mut T
Inserts value
into the option, then returns a mutable reference to it.
If the option already contains a value, the old value is dropped.
See also Option::get_or_insert
, which doesn’t update the value if
the option already contains Some.
§Examples
use orx_concurrent_option::*;
let mut opt: ConcurrentOption<_> = ConcurrentOption::none();
let val = opt.exclusive_insert(1);
assert_eq!(*val, 1);
assert_eq!(unsafe { opt.as_ref() }, Some(&1));
let val = opt.exclusive_insert(2);
assert_eq!(*val, 2);
*val = 3;
assert_eq!(opt.unwrap(), 3);
Sourcepub fn exclusive_get_or_insert(&mut self, value: T) -> &mut T
pub fn exclusive_get_or_insert(&mut self, value: T) -> &mut T
Inserts value
into the option if it is None, then
returns a mutable reference to the contained value.
See also ConcurrentOption::insert
, which updates the value even if
the option already contains Some.
§Examples
use orx_concurrent_option::*;
let mut x = ConcurrentOption::none();
{
let y: &mut u32 = x.exclusive_get_or_insert(5);
assert_eq!(y, &5);
*y = 7;
}
assert_eq!(x, ConcurrentOption::some(7));
Sourcepub fn exclusive_get_or_insert_with<F>(&mut self, f: F) -> &mut Twhere
F: FnOnce() -> T,
pub fn exclusive_get_or_insert_with<F>(&mut self, f: F) -> &mut Twhere
F: FnOnce() -> T,
Inserts a value computed from f
into the option if it is None,
then returns a mutable reference to the contained value.
§Examples
use orx_concurrent_option::*;
let mut x = ConcurrentOption::none();
{
let y: &mut u32 = x.exclusive_get_or_insert_with(|| 5);
assert_eq!(y, &5);
*y = 7;
}
assert_eq!(x, ConcurrentOption::some(7));
Source§impl<T> ConcurrentOption<T>
impl<T> ConcurrentOption<T>
Sourcepub fn expect(self, message: &str) -> T
pub fn expect(self, message: &str) -> T
Returns the contained Some value, consuming the self
value.
§Panics
Panics if the value is a None with a custom panic message provided by
message
.
§Examples
use orx_concurrent_option::*;
let x = ConcurrentOption::some("value");
assert_eq!(x.expect("fruits are healthy"), "value");
use orx_concurrent_option::*;
let x: ConcurrentOption<&str> = ConcurrentOption::none();
x.expect("fruits are healthy"); // panics with `fruits are healthy`
Sourcepub fn unwrap(self) -> T
pub fn unwrap(self) -> T
Returns the contained Some value, consuming the self
value.
Because this function may panic, its use is generally discouraged.
Instead, prefer to use pattern matching and handle the None
case explicitly, or call ConcurrentOption::unwrap_or
, ConcurrentOption::unwrap_or_else
, or
ConcurrentOption::unwrap_or_default
.
§Panics
Panics if the self value equals None.
§Examples
use orx_concurrent_option::*;
let x = ConcurrentOption::some("air");
assert_eq!(x.unwrap(), "air");
use orx_concurrent_option::*;
let x: ConcurrentOption<&str> = ConcurrentOption::none();
assert_eq!(x.unwrap(), "air"); // fails
Sourcepub fn unwrap_or(self, default: T) -> T
pub fn unwrap_or(self, default: T) -> T
Returns the contained Some value or a provided default.
Arguments passed to unwrap_or
are eagerly evaluated; if you are passing
the result of a function call, it is recommended to use ConcurrentOption::unwrap_or_else
,
which is lazily evaluated.
§Examples
use orx_concurrent_option::*;
assert_eq!(ConcurrentOption::some("car").unwrap_or("bike"), "car");
assert_eq!(ConcurrentOption::none().unwrap_or("bike"), "bike");
Sourcepub fn unwrap_or_default(self) -> Twhere
T: Default,
pub fn unwrap_or_default(self) -> Twhere
T: Default,
Returns the contained Some value or a default.
Consumes the self
argument then, if Some, returns the contained
value, otherwise if None, returns the [default value] for that
type.
§Examples
use orx_concurrent_option::*;
let x: ConcurrentOption<u32> = ConcurrentOption::none();
let y: ConcurrentOption<u32> = ConcurrentOption::some(12);
assert_eq!(x.unwrap_or_default(), 0);
assert_eq!(y.unwrap_or_default(), 12);
Sourcepub fn unwrap_or_else<F>(self, f: F) -> Twhere
F: FnOnce() -> T,
pub fn unwrap_or_else<F>(self, f: F) -> Twhere
F: FnOnce() -> T,
Returns the contained Some value or computes it from a closure.
§Examples
use orx_concurrent_option::*;
let k = 10;
assert_eq!(ConcurrentOption::some(4).unwrap_or_else(|| 2 * k), 4);
assert_eq!(ConcurrentOption::none().unwrap_or_else(|| 2 * k), 20);
Sourcepub unsafe fn unwrap_unchecked(self) -> T
pub unsafe fn unwrap_unchecked(self) -> T
Returns the contained Some value, consuming the self
value,
without checking that the value is not None.
§Safety
Calling this method on None is undefined behavior.
§Examples
use orx_concurrent_option::*;
let x = ConcurrentOption::some("air");
assert_eq!(unsafe { x.unwrap_unchecked() }, "air");
use orx_concurrent_option::*;
let x: ConcurrentOption<&str> = ConcurrentOption::none();
assert_eq!(unsafe { x.unwrap_unchecked() }, "air"); // Undefined behavior!
Source§impl<T> ConcurrentOption<T>
impl<T> ConcurrentOption<T>
Sourcepub fn some(value: T) -> Self
pub fn some(value: T) -> Self
Creates a concurrent option of the Some variant with an existing value.
§Examples
use orx_concurrent_option::*;
let x = ConcurrentOption::some(3.to_string());
assert_eq!(x, ConcurrentOption::some(3.to_string()));
assert_ne!(x, ConcurrentOption::none());
assert!(x.is_some());
assert!(!x.is_none());
Sourcepub fn none() -> Self
pub fn none() -> Self
Creates a concurrent option of the None variant with a missing value.
§Examples
use orx_concurrent_option::*;
let x = ConcurrentOption::<String>::none();
assert_ne!(x, ConcurrentOption::some(3.to_string()));
assert_eq!(x, ConcurrentOption::none());
assert!(!x.is_some());
assert!(x.is_none());
let x = ConcurrentOption::default();
assert_ne!(x, ConcurrentOption::some(3.to_string()));
assert_eq!(x, ConcurrentOption::none());
assert!(!x.is_some());
assert!(x.is_none());
Source§impl<T> ConcurrentOption<T>
impl<T> ConcurrentOption<T>
Sourcepub fn is_some(&self) -> bool
pub fn is_some(&self) -> bool
Returns true
if the option is a Some variant.
§Examples
use orx_concurrent_option::*;
use core::sync::atomic::Ordering;
let x: ConcurrentOption<u32> = ConcurrentOption::some(2);
assert_eq!(x.is_some(), true);
let x: ConcurrentOption<u32> = ConcurrentOption::none();
assert_eq!(x.is_some(), false);
Sourcepub fn is_none(&self) -> bool
pub fn is_none(&self) -> bool
Returns true
if the option is a None variant.
§Examples
use orx_concurrent_option::*;
let x: ConcurrentOption<u32> = ConcurrentOption::some(2);
assert_eq!(x.is_none(), false);
let x: ConcurrentOption<u32> = ConcurrentOption::none();
assert_eq!(x.is_none(), true);
Sourcepub unsafe fn as_ref(&self) -> Option<&T>
pub unsafe fn as_ref(&self) -> Option<&T>
Partially thread safe method to convert from &Option<T>
to Option<&T>
.
§Safety
Note that creating a valid reference part of this method is thread safe.
The method is unsafe
due to the returned reference to the underlying value.
- It is safe to use this method if the returned reference is discarded (miri would still complain).
- It is also safe to use this method if the caller is able to guarantee that there exist
no concurrent writes while holding onto this reference.
- One such case is using
as_ref
together withinitialize_when_none
method. This is perfectly safe since the value will be written only once, andas_ref
returns a valid reference only after the value is initialized.
- One such case is using
- Otherwise, it will lead to an Undefined Behavior due to data race.
§Examples
use orx_concurrent_option::*;
let x = ConcurrentOption::some(3.to_string());
assert_eq!(unsafe { x.as_ref() }, Some(&3.to_string()));
_ = x.take();
assert_eq!(unsafe { x.as_ref() }, None);
Sourcepub unsafe fn as_deref(&self) -> Option<&<T as Deref>::Target>where
T: Deref,
pub unsafe fn as_deref(&self) -> Option<&<T as Deref>::Target>where
T: Deref,
Partially thread safe method to convert from Option<T>
(or &Option<T>
) to Option<&T::Target>
.
Leaves the original Option in-place, creating a new one with a reference
to the original one, additionally coercing the contents via Deref
.
§Safety
Note that creating a valid reference part of this method is thread safe.
The method is unsafe
due to the returned reference to the underlying value.
- It is safe to use this method if the returned reference is discarded (miri would still complain).
- It is also safe to use this method if the caller is able to guarantee that there exist
no concurrent writes while holding onto this reference.
- One such case is using
as_ref
together withinitialize_when_none
method. This is perfectly safe since the value will be written only once, andas_ref
returns a valid reference only after the value is initialized.
- One such case is using
- Otherwise, it will lead to an Undefined Behavior due to data race.
§Examples
use orx_concurrent_option::*;
let x: ConcurrentOption<String> = ConcurrentOption::some("hey".to_owned());
assert_eq!(unsafe { x.as_deref() }, Some("hey"));
let x: ConcurrentOption<String> = ConcurrentOption::none();
assert_eq!(unsafe { x.as_deref() }, None);
Sourcepub unsafe fn iter(&self) -> Iter<'_, T> ⓘ
pub unsafe fn iter(&self) -> Iter<'_, T> ⓘ
Partially thread safe method to return an iterator over the possibly contained value; yields
- the single element if the option is of Some variant;
- no elements otherwise.
§Safety
Note that creating a valid reference part of this method is thread safe.
The method is unsafe
due to the returned reference to the underlying value.
- It is safe to use this method if the returned reference is discarded (miri would still complain).
- It is also safe to use this method if the caller is able to guarantee that there exist
no concurrent writes while holding onto this reference.
- One such case is using
as_ref
together withinitialize_when_none
method. This is perfectly safe since the value will be written only once, andas_ref
returns a valid reference only after the value is initialized.
- One such case is using
- Otherwise, it will lead to an Undefined Behavior due to data race.
§Examples
use orx_concurrent_option::*;
fn validate<'a>(mut iter: impl ExactSizeIterator<Item = &'a String>) {
assert_eq!(iter.len(), 0);
assert!(iter.next().is_none());
assert!(iter.next().is_none());
}
let x = ConcurrentOption::<String>::none();
validate(unsafe { x.iter() });
validate(unsafe { x.iter() }.rev());
validate((&x).into_iter());
Sourcepub fn clone_into_option(&self) -> Option<T>where
T: Clone,
pub fn clone_into_option(&self) -> Option<T>where
T: Clone,
Clones the value of the ConcurrentOption<T>
into a Some
of T
if the concurrent option is some; returns None otherwise.
§Examples
use orx_concurrent_option::*;
let opt = ConcurrentOption::some(12);
assert_eq!(unsafe { opt.as_ref() }, Some(&12));
let clone = opt.clone_into_option();
assert_eq!(clone, Some(12));
Sourcepub fn map<U, F>(&self, f: F) -> Option<U>
pub fn map<U, F>(&self, f: F) -> Option<U>
Thread safe method to map the reference of the underlying value with the given function f
.
Returns
- None if the option is None
f(&value)
if the option is Some(value)
§Concurrency Notes
Notice that map
is a composition of as_ref
and map
.
However, it is stronger in terms of thread safety since the access to the value is controlled
and a reference to the underlying value is not leaked outside the option.
Therefore, map
must be preferred in a concurrent program:
- the map operation via
map
guarantees that the underlying value will not be updated before the operation; while - the alternative approach with
as_ref
is subject to data race if the state of the optional is concurrently being updated by methods such astake
.- an exception to this is the
initialize_if_none
method which fits very well the initialize-once scenarios; here,as_ref
andinitialize_if_none
can safely be called concurrently from multiple threads.
- an exception to this is the
§Examples
use orx_concurrent_option::*;
let x = ConcurrentOption::<String>::none();
let len = x.map(|x| x.len());
assert_eq!(len, None);
let x = ConcurrentOption::some("foo".to_string());
let len = x.map(|x| x.len());
assert_eq!(len, Some(3));
Sourcepub fn map_or<U, F>(&self, default: U, f: F) -> U
pub fn map_or<U, F>(&self, default: U, f: F) -> U
Returns the provided default result (if none), or applies a function to the contained value (if any).
Arguments passed to map_or
are eagerly evaluated; if you are passing
the result of a function call, it is recommended to use map_or_else
,
which is lazily evaluated.
§Examples
use orx_concurrent_option::*;
let x = ConcurrentOption::some("foo");
assert_eq!(x.map_or(42, |v| v.len()), 3);
let x: ConcurrentOption<&str> = ConcurrentOption::none();
assert_eq!(x.map_or(42, |v| v.len()), 42);
Sourcepub fn map_or_else<U, D, F>(&self, default: D, f: F) -> U
pub fn map_or_else<U, D, F>(&self, default: D, f: F) -> U
Computes a default function result (if none), or applies a different function to the contained value (if any).
§Basic examples
use orx_concurrent_option::*;
let k = 21;
let x = ConcurrentOption::some("foo");
assert_eq!(x.map_or_else(|| 2 * k, |v| v.len()), 3);
let x: ConcurrentOption<&str> = ConcurrentOption::none();
assert_eq!(x.map_or_else(|| 2 * k, |v| v.len()), 42);
Sourcepub fn is_some_and(&self, f: impl FnOnce(&T) -> bool) -> bool
pub fn is_some_and(&self, f: impl FnOnce(&T) -> bool) -> bool
Thread safe method that returns true
if the option is a Some and the value inside of it matches a predicate.
§Examples
use orx_concurrent_option::*;
let x = ConcurrentOption::some(2);
assert_eq!(x.is_some_and(|x| *x > 1), true);
let x = ConcurrentOption::some(0);
assert_eq!(x.is_some_and(|x| *x > 1), false);
let x: ConcurrentOption<i32> = ConcurrentOption::none();
assert_eq!(x.is_some_and(|x| *x > 1), false);
Sourcepub fn and<U>(&self, other: impl IntoOption<U>) -> Option<U>
pub fn and<U>(&self, other: impl IntoOption<U>) -> Option<U>
Returns None if the option is None, otherwise returns other
.
Arguments passed to and
are eagerly evaluated; if you are passing the
result of a function call, it is recommended to use and_then
, which is
lazily evaluated.
§Examples
use orx_concurrent_option::*;
let x = ConcurrentOption::some(2);
let y: ConcurrentOption<&str> = ConcurrentOption::none();
assert_eq!(x.and(y), None);
let x: ConcurrentOption<u32> = ConcurrentOption::none();
let y = ConcurrentOption::some("foo");
assert_eq!(x.and(y), None);
let x = ConcurrentOption::some(2);
let y = Some("foo");
assert_eq!(x.and(y), Some("foo"));
let x: ConcurrentOption<u32> = ConcurrentOption::none();
let y: Option<&str> = None;
assert_eq!(x.and(y), None);
Sourcepub fn and_then<U, V, F>(&self, f: F) -> Option<U>
pub fn and_then<U, V, F>(&self, f: F) -> Option<U>
Returns None if the option is None, otherwise calls f
with the
wrapped value and returns the result.
Some languages call this operation flatmap.
§Examples
use orx_concurrent_option::*;
fn sq_then_to_string(x: &u32) -> Option<String> {
x.checked_mul(*x).map(|sq| sq.to_string())
}
assert_eq!(ConcurrentOption::some(2).and_then(sq_then_to_string), Some(4.to_string()));
assert_eq!(ConcurrentOption::some(1_000_000).and_then(sq_then_to_string), None); // overflowed!
assert_eq!(ConcurrentOption::none().and_then(sq_then_to_string), None);
Since ConcurrentOption
also implements IntoOption
; and_then can also be called with
a function returning a concurrent option.
use orx_concurrent_option::*;
fn sq_then_to_string(x: &u32) -> ConcurrentOption<String> {
x.checked_mul(*x).map(|sq| sq.to_string()).into()
}
assert_eq!(ConcurrentOption::some(2).and_then(sq_then_to_string), Some(4.to_string()));
assert_eq!(ConcurrentOption::some(1_000_000).and_then(sq_then_to_string), None); // overflowed!
assert_eq!(ConcurrentOption::none().and_then(sq_then_to_string), None);
Sourcepub unsafe fn filter<P>(&self, predicate: P) -> Option<&T>
pub unsafe fn filter<P>(&self, predicate: P) -> Option<&T>
Returns None if the option is None, otherwise calls predicate
with the wrapped value and returns:
- Some(t) if
predicate
returnstrue
(wheret
is the wrapped value), and - None if
predicate
returnsfalse
.
This function works similar to Iterator::filter()
. You can imagine
the Option<T>
being an iterator over one or zero elements. filter()
lets you decide which elements to keep.
§Safety
Note that creating a valid reference part of this method is thread safe.
The method is unsafe
due to the returned reference to the underlying value.
- It is safe to use this method if the returned reference is discarded (miri would still complain).
- It is also safe to use this method if the caller is able to guarantee that there exist
no concurrent writes while holding onto this reference.
- One such case is using
as_ref
together withinitialize_when_none
method. This is perfectly safe since the value will be written only once, andas_ref
returns a valid reference only after the value is initialized.
- One such case is using
- Otherwise, it will lead to an Undefined Behavior due to data race.
§Examples
use orx_concurrent_option::*;
fn is_even(n: &i32) -> bool {
n % 2 == 0
}
unsafe
{
assert_eq!(ConcurrentOption::none().filter(is_even), None);
assert_eq!(ConcurrentOption::some(3).filter(is_even), None);
assert_eq!(ConcurrentOption::some(4).filter(is_even), Some(&4));
}
Source§impl<T> ConcurrentOption<&T>
impl<T> ConcurrentOption<&T>
Sourcepub fn cloned(self) -> Option<T>where
T: Clone,
pub fn cloned(self) -> Option<T>where
T: Clone,
Maps an ConcurrentOption<&T>
to an Option<T>
by cloning the contents of the
option.
§Examples
use orx_concurrent_option::*;
use core::sync::atomic::Ordering;
let x = 12;
let opt_x = ConcurrentOption::some(&x);
assert_eq!(unsafe { opt_x.as_ref() }, Some(&&12));
let cloned = opt_x.cloned();
assert_eq!(cloned, Some(12));
Sourcepub fn copied(self) -> Option<T>where
T: Copy,
pub fn copied(self) -> Option<T>where
T: Copy,
Maps an ConcurrentOption<&T>
to an Option<T>
by copying the contents of the
option.
§Examples
use orx_concurrent_option::*;
let x = 12;
let opt_x = ConcurrentOption::some(&x);
assert_eq!(unsafe { opt_x.as_ref() }, Some(&&12));
let copied = opt_x.copied();
assert_eq!(copied, Some(12));
Source§impl<T> ConcurrentOption<ConcurrentOption<T>>
impl<T> ConcurrentOption<ConcurrentOption<T>>
Sourcepub fn flatten(self) -> Option<T>
pub fn flatten(self) -> Option<T>
Converts from ConcurrentOption<ConcurrentOption<T>>
to Option<T>
.
§Examples
Basic usage:
use orx_concurrent_option::*;
let x: ConcurrentOption<ConcurrentOption<u32>> = ConcurrentOption::some(ConcurrentOption::some(6));
assert_eq!(Some(6), x.flatten());
let x: ConcurrentOption<ConcurrentOption<u32>> = ConcurrentOption::some(ConcurrentOption::none());
assert_eq!(None, x.flatten());
let x: ConcurrentOption<ConcurrentOption<u32>> = ConcurrentOption::none();
assert_eq!(None, x.flatten());
Source§impl<T> ConcurrentOption<Option<T>>
impl<T> ConcurrentOption<Option<T>>
Sourcepub fn flatten(self) -> Option<T>
pub fn flatten(self) -> Option<T>
Converts from ConcurrentOption<Option<T>>
to Option<T>
.
§Examples
Basic usage:
use orx_concurrent_option::*;
let x: ConcurrentOption<Option<u32>> = ConcurrentOption::some(Some(6));
assert_eq!(Some(6), x.flatten());
let x: ConcurrentOption<Option<u32>> = ConcurrentOption::some(None);
assert_eq!(None, x.flatten());
let x: ConcurrentOption<Option<u32>> = ConcurrentOption::none();
assert_eq!(None, x.flatten());
Source§impl<T> ConcurrentOption<T>
impl<T> ConcurrentOption<T>
Sourcepub fn get_raw(&self) -> Option<*const T>
pub fn get_raw(&self) -> Option<*const T>
Returns:
- a raw
*const T
pointer to the underlying data when the option is of Some variant; None
otherwise.
See get_raw_with_order
to explicitly set the ordering.
§Example
use orx_concurrent_option::*;
let x = ConcurrentOption::<String>::none();
let p = x.get_raw();
assert!(p.is_none());
let x = ConcurrentOption::some(3.to_string());
let p = x.get_raw();
assert!(p.is_some());
assert_eq!(unsafe { p.unwrap().as_ref() }, Some(&3.to_string()));
Sourcepub fn get_raw_mut(&self) -> Option<*mut T>
pub fn get_raw_mut(&self) -> Option<*mut T>
Returns:
- a raw
*mut T
pointer to the underlying data when the option is of Some variant; None
otherwise.
See get_raw_mut_with_order
to explicitly set the ordering.
use orx_concurrent_option::*;
let x = ConcurrentOption::<String>::none();
let p = x.get_raw_mut();
assert!(p.is_none());
let x = ConcurrentOption::some(3.to_string());
let p = x.get_raw_mut();
assert!(p.is_some());
assert_eq!(unsafe { p.unwrap().as_ref() }, Some(&3.to_string()));
let p = x.get_raw().unwrap();
assert_eq!(unsafe { p.as_ref() }, Some(&3.to_string()));
let p = x.get_raw_mut();
let p = p.unwrap();
let _ = unsafe { p.replace(7.to_string()) }; // only write leads to memory leak
assert_eq!(unsafe { x.as_ref() }, Some(&7.to_string()));
Sourcepub fn get_raw_with_order(&self, order: Ordering) -> Option<*const T>
pub fn get_raw_with_order(&self, order: Ordering) -> Option<*const T>
Returns:
- a raw
*const T
pointer to the underlying data when the option is of Some variant; None
otherwise.
Depending on requirement of the use case, Relaxed
, Acquire
or SeqCst
can be used as the order
.
§Example
use orx_concurrent_option::*;
use core::sync::atomic::Ordering;
let x = ConcurrentOption::<String>::none();
let p = x.get_raw_with_order(Ordering::SeqCst);
assert!(p.is_none());
let x = ConcurrentOption::some(3.to_string());
let p = x.get_raw_with_order(Ordering::Acquire);
assert!(p.is_some());
assert_eq!(unsafe { p.unwrap().as_ref() }, Some(&3.to_string()));
Sourcepub fn get_raw_mut_with_order(&self, order: Ordering) -> Option<*mut T>
pub fn get_raw_mut_with_order(&self, order: Ordering) -> Option<*mut T>
Returns:
- a raw
*mut T
pointer to the underlying data when the option is of Some variant; None
otherwise.
Depending on requirement of the use case, Relaxed
, Acquire
or SeqCst
can be used as the order
.
use orx_concurrent_option::*;
use core::sync::atomic::Ordering;
let x = ConcurrentOption::<String>::none();
let p = x.get_raw_mut_with_order(Ordering::SeqCst);
assert!(p.is_none());
let x = ConcurrentOption::some(3.to_string());
let p = x.get_raw_mut_with_order(Ordering::Acquire);
assert!(p.is_some());
assert_eq!(unsafe { p.unwrap().as_ref() }, Some(&3.to_string()));
let p = x.get_raw_mut_with_order(Ordering::Relaxed).unwrap();
assert_eq!(unsafe { p.as_ref() }, Some(&3.to_string()));
let p = x.get_raw_mut_with_order(Ordering::Relaxed);
let p = p.unwrap();
let _ = unsafe { p.replace(7.to_string()) }; // only write leads to memory leak
assert_eq!(unsafe { x.as_ref() }, Some(&7.to_string()));
Source§impl<T> ConcurrentOption<T>
impl<T> ConcurrentOption<T>
Sourcepub fn state(&self, order: Ordering) -> State
pub fn state(&self, order: Ordering) -> State
Loads and returns the concurrent state of the option with the given order
.
§Examples
use orx_concurrent_option::*;
use core::sync::atomic::Ordering;
let x: ConcurrentOption<u32> = ConcurrentOption::some(2);
assert_eq!(x.state(Ordering::Relaxed), State::Some);
let x: ConcurrentOption<u32> = ConcurrentOption::none();
assert_eq!(x.state(Ordering::SeqCst), State::None);
Sourcepub fn is_some_with_order(&self, order: Ordering) -> bool
pub fn is_some_with_order(&self, order: Ordering) -> bool
Returns true
if the option is a Some variant.
§Examples
use orx_concurrent_option::*;
use core::sync::atomic::Ordering;
let x: ConcurrentOption<u32> = ConcurrentOption::some(2);
assert_eq!(x.is_some(), true);
let x: ConcurrentOption<u32> = ConcurrentOption::none();
assert_eq!(x.is_some(), false);
Sourcepub fn is_none_with_order(&self, order: Ordering) -> bool
pub fn is_none_with_order(&self, order: Ordering) -> bool
Returns true
if the option is a None variant.
§Examples
use orx_concurrent_option::*;
let x: ConcurrentOption<u32> = ConcurrentOption::some(2);
assert_eq!(x.is_none(), false);
let x: ConcurrentOption<u32> = ConcurrentOption::none();
assert_eq!(x.is_none(), true);
Sourcepub unsafe fn as_ref_with_order(&self, order: Ordering) -> Option<&T>
pub unsafe fn as_ref_with_order(&self, order: Ordering) -> Option<&T>
Converts from &Option<T>
to Option<&T>
.
Depending on requirement of the use case, Relaxed
, Acquire
or SeqCst
can be used as the order
.
§Safety
Note that creating a valid reference part of this method is thread safe.
The method is unsafe
due to the returned reference to the underlying value.
- It is safe to use this method if the returned reference is discarded (miri would still complain).
- It is also safe to use this method if the caller is able to guarantee that there exist
no concurrent writes while holding onto this reference.
- One such case is using
as_ref
together withinitialize_when_none
method. This is perfectly safe since the value will be written only once, andas_ref
returns a valid reference only after the value is initialized.
- One such case is using
- Otherwise, it will lead to an Undefined Behavior due to data race.
§Examples
use orx_concurrent_option::*;
use core::sync::atomic::Ordering;
let x = ConcurrentOption::some(3.to_string());
assert_eq!(unsafe { x.as_ref_with_order(Ordering::Relaxed) }, Some(&3.to_string()));
_ = x.take();
assert_eq!(unsafe { x.as_ref_with_order(Ordering::Acquire) }, None);
Sourcepub unsafe fn as_deref_with_order(
&self,
order: Ordering,
) -> Option<&<T as Deref>::Target>where
T: Deref,
pub unsafe fn as_deref_with_order(
&self,
order: Ordering,
) -> Option<&<T as Deref>::Target>where
T: Deref,
Converts from Option<T>
(or &Option<T>
) to Option<&T::Target>
.
Leaves the original Option in-place, creating a new one with a reference
to the original one, additionally coercing the contents via Deref
.
Depending on requirement of the use case, Relaxed
, Acquire
or SeqCst
can be used as the order
.
§Safety
Note that creating a valid reference part of this method is thread safe.
The method is unsafe
due to the returned reference to the underlying value.
- It is safe to use this method if the returned reference is discarded (miri would still complain).
- It is also safe to use this method if the caller is able to guarantee that there exist
no concurrent writes while holding onto this reference.
- One such case is using
as_ref
together withinitialize_when_none
method. This is perfectly safe since the value will be written only once, andas_ref
returns a valid reference only after the value is initialized.
- One such case is using
- Otherwise, it will lead to an Undefined Behavior due to data race.
§Examples
use orx_concurrent_option::*;
use core::sync::atomic::Ordering;
unsafe
{
let x: ConcurrentOption<String> = ConcurrentOption::some("hey".to_owned());
assert_eq!(x.as_deref_with_order(Ordering::Acquire), Some("hey"));
let x: ConcurrentOption<String> = ConcurrentOption::none();
assert_eq!(x.as_deref_with_order(Ordering::SeqCst), None);
}
Sourcepub unsafe fn iter_with_order(&self, order: Ordering) -> Iter<'_, T> ⓘ
pub unsafe fn iter_with_order(&self, order: Ordering) -> Iter<'_, T> ⓘ
Returns an iterator over the possibly contained value; yields
- the single element if the option is of Some variant;
- no elements otherwise.
Depending on requirement of the use case, Relaxed
, Acquire
or SeqCst
can be used as the order
.
§Safety
Note that creating a valid reference part of this method is thread safe.
The method is unsafe
due to the returned reference to the underlying value.
- It is safe to use this method if the returned reference is discarded (miri would still complain).
- It is also safe to use this method if the caller is able to guarantee that there exist
no concurrent writes while holding onto this reference.
- One such case is using
as_ref
together withinitialize_when_none
method. This is perfectly safe since the value will be written only once, andas_ref
returns a valid reference only after the value is initialized.
- One such case is using
- Otherwise, it will lead to an Undefined Behavior due to data race.
§Examples
use orx_concurrent_option::*;
use core::sync::atomic::Ordering;
fn validate<'a>(mut iter: impl ExactSizeIterator<Item = &'a String>) {
assert_eq!(iter.len(), 0);
assert!(iter.next().is_none());
assert!(iter.next().is_none());
}
let x = ConcurrentOption::<String>::none();
unsafe
{
validate(x.iter_with_order(Ordering::SeqCst));
validate(x.iter_with_order(Ordering::Relaxed).rev());
validate((&x).into_iter());
}
Sourcepub fn clone_with_order(&self, order: Ordering) -> Option<T>where
T: Clone,
pub fn clone_with_order(&self, order: Ordering) -> Option<T>where
T: Clone,
Clones the concurrent option with the desired order
into an Option.
Note that the Clone
trait implementation clones the concurrent option with the default ordering.
You may use clone_with_order
in order to clone with the desired ordering.
use orx_concurrent_option::*;
use core::sync::atomic::Ordering;
let mut x = ConcurrentOption::some(42);
let y = x.clone_with_order(Ordering::SeqCst);
assert_eq!(x.take(), y);
Sourcepub fn eq_with_order(&self, other: &Self, order: Ordering) -> boolwhere
T: PartialEq,
pub fn eq_with_order(&self, other: &Self, order: Ordering) -> boolwhere
T: PartialEq,
Returns whether or not self is equal to the other
with the desired order
.
Note that the PartialEq
trait implementation checks equality with the default ordering.
You may use eq_with_order
in order to check equality with the desired ordering.
use orx_concurrent_option::*;
use core::sync::atomic::Ordering;
let x = ConcurrentOption::some(3);
let y = ConcurrentOption::some(7);
let z = ConcurrentOption::<i32>::none();
let o = Ordering::SeqCst;
assert!(x.eq_with_order(&x, o));
assert!(!x.eq_with_order(&y, o));
assert!(!x.eq_with_order(&z, o));
assert!(!z.eq_with_order(&x, o));
assert!(!z.eq_with_order(&y, o));
assert!(z.eq_with_order(&z, o));
Sourcepub fn partial_cmp_with_order(
&self,
other: &Self,
order: Ordering,
) -> Option<Ordering>where
T: PartialOrd,
pub fn partial_cmp_with_order(
&self,
other: &Self,
order: Ordering,
) -> Option<Ordering>where
T: PartialOrd,
Returns an ordering between self
and other
with the desired order
.
Note that the PartialOrd
trait implementation checks equality with the default ordering.
You may use partial_cmp_with_order
in order to check equality with the desired ordering.
use orx_concurrent_option::*;
use core::cmp::Ordering::*;
let x = ConcurrentOption::some(3);
let y = ConcurrentOption::some(7);
let z = ConcurrentOption::<i32>::none();
let ord = core::sync::atomic::Ordering::SeqCst;
assert_eq!(x.partial_cmp_with_order(&x, ord), Some(Equal));
assert_eq!(x.partial_cmp_with_order(&y, ord), Some(Less));
assert_eq!(x.partial_cmp_with_order(&z, ord), Some(Greater));
assert_eq!(y.partial_cmp_with_order(&x, ord), Some(Greater));
assert_eq!(y.partial_cmp_with_order(&y, ord), Some(Equal));
assert_eq!(y.partial_cmp_with_order(&z, ord), Some(Greater));
assert_eq!(z.partial_cmp_with_order(&x, ord), Some(Less));
assert_eq!(z.partial_cmp_with_order(&y, ord), Some(Less));
assert_eq!(z.partial_cmp_with_order(&z, ord), Some(Equal));
Sourcepub fn cmp_with_order(&self, other: &Self, order: Ordering) -> Orderingwhere
T: Ord,
pub fn cmp_with_order(&self, other: &Self, order: Ordering) -> Orderingwhere
T: Ord,
Returns an ordering between self
and other
with the desired order
.
Note that the Ord
trait implementation checks equality with the default ordering.
You may use cmp_with_order
in order to check equality with the desired ordering.
use orx_concurrent_option::*;
use core::cmp::Ordering::*;
let x = ConcurrentOption::some(3);
let y = ConcurrentOption::some(7);
let z = ConcurrentOption::<i32>::none();
let ord = core::sync::atomic::Ordering::SeqCst;
assert_eq!(x.cmp_with_order(&x, ord), Equal);
assert_eq!(x.cmp_with_order(&y, ord), Less);
assert_eq!(x.cmp_with_order(&z, ord), Greater);
assert_eq!(y.cmp_with_order(&x, ord), Greater);
assert_eq!(y.cmp_with_order(&y, ord), Equal);
assert_eq!(y.cmp_with_order(&z, ord), Greater);
assert_eq!(z.cmp_with_order(&x, ord), Less);
assert_eq!(z.cmp_with_order(&y, ord), Less);
assert_eq!(z.cmp_with_order(&z, ord), Equal);
Trait Implementations§
Source§impl<T: Clone> Clone for ConcurrentOption<T>
impl<T: Clone> Clone for ConcurrentOption<T>
Source§fn clone(&self) -> Self
fn clone(&self) -> Self
Clones the concurrent option with the Relaxed
ordering.
In order to clone with a stronger ordering,
you may call clone_with_order
with the desired ordering.
use orx_concurrent_option::*;
use core::sync::atomic::Ordering;
let x = ConcurrentOption::some(42);
let y = x.clone(); // clone with default Relaxed ordering
assert_eq!(x, y);
let x = ConcurrentOption::some(42);
let y = x.clone_with_order(Ordering::SeqCst).into(); // clone with desired ordering SeqCst
assert_eq!(x, y);
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source
. Read moreSource§impl<T: Debug> Debug for ConcurrentOption<T>
impl<T: Debug> Debug for ConcurrentOption<T>
Source§fn fmt(&self, f: &mut Formatter<'_>) -> Result
fn fmt(&self, f: &mut Formatter<'_>) -> Result
Creates the debug representation.
use orx_concurrent_option::*;
use core::sync::atomic::Ordering;
let x = ConcurrentOption::some(3.to_string());
let y = format!("{:?}", x); // debug with default Relaxed ordering
assert_eq!(y, "ConcurrentSome(\"3\")");
let x = ConcurrentOption::<String>::none();
let y = format!("{:?}", x);
assert_eq!(y, "ConcurrentNone");
Source§impl<T> Default for ConcurrentOption<T>
impl<T> Default for ConcurrentOption<T>
Source§impl<T> Drop for ConcurrentOption<T>
impl<T> Drop for ConcurrentOption<T>
Source§impl<T> From<ConcurrentOption<T>> for Option<T>
impl<T> From<ConcurrentOption<T>> for Option<T>
Source§fn from(value: ConcurrentOption<T>) -> Self
fn from(value: ConcurrentOption<T>) -> Self
Converts a ConcurrentOption
to a Option
.
§Examples
use orx_concurrent_option::*;
let x = ConcurrentOption::some(3.to_string());
let y: Option<_> = x.into();
assert_eq!(y, Some(3.to_string()));
let x: ConcurrentOption<String> = ConcurrentOption::none();
let y: Option<String> = x.into();
assert_eq!(y, None);
Source§impl<T> From<Option<T>> for ConcurrentOption<T>
impl<T> From<Option<T>> for ConcurrentOption<T>
Source§fn from(value: Option<T>) -> Self
fn from(value: Option<T>) -> Self
Converts an Option
to a ConcurrentOption
.
§Examples
use orx_concurrent_option::*;
let x: ConcurrentOption<String> = Some(3.to_string()).into();
assert_eq!(unsafe { x.as_ref() }, Some(&3.to_string()));
let x: ConcurrentOption<String> = None.into();
assert_eq!(unsafe { x.as_ref() }, None);
Source§impl<T> From<T> for ConcurrentOption<T>
impl<T> From<T> for ConcurrentOption<T>
Source§impl<'a, T> IntoIterator for &'a ConcurrentOption<T>
impl<'a, T> IntoIterator for &'a ConcurrentOption<T>
Source§impl<'a, T> IntoIterator for &'a mut ConcurrentOption<T>
impl<'a, T> IntoIterator for &'a mut ConcurrentOption<T>
Source§impl<T> IntoIterator for ConcurrentOption<T>
impl<T> IntoIterator for ConcurrentOption<T>
Source§impl<T> IntoOption<T> for ConcurrentOption<T>
impl<T> IntoOption<T> for ConcurrentOption<T>
Source§fn into_option(self) -> Option<T>
fn into_option(self) -> Option<T>
Source§impl<T: Ord> Ord for ConcurrentOption<T>
impl<T: Ord> Ord for ConcurrentOption<T>
Source§fn cmp(&self, other: &Self) -> Ordering
fn cmp(&self, other: &Self) -> Ordering
Returns an ordering between self
and other
with the default ordering.
You may call cmp_with_order
to use the desired ordering.
use orx_concurrent_option::*;
use core::cmp::Ordering::*;
let x = ConcurrentOption::some(3);
let y = ConcurrentOption::some(7);
let z = ConcurrentOption::<i32>::none();
assert_eq!(x.cmp(&x), Equal);
assert_eq!(x.cmp(&y), Less);
assert_eq!(x.cmp(&z), Greater);
assert_eq!(y.cmp(&x), Greater);
assert_eq!(y.cmp(&y), Equal);
assert_eq!(y.cmp(&z), Greater);
assert_eq!(z.cmp(&x), Less);
assert_eq!(z.cmp(&y), Less);
assert_eq!(z.cmp(&z), Equal);
1.21.0 · Source§fn max(self, other: Self) -> Selfwhere
Self: Sized,
fn max(self, other: Self) -> Selfwhere
Self: Sized,
Source§impl<T: PartialEq> PartialEq for ConcurrentOption<T>
impl<T: PartialEq> PartialEq for ConcurrentOption<T>
Source§fn eq(&self, other: &Self) -> bool
fn eq(&self, other: &Self) -> bool
Returns whether or not self is equal to the other
with the default ordering.
You may call eq_with_order
to use the desired ordering.
use orx_concurrent_option::*;
let x = ConcurrentOption::some(3);
let y = ConcurrentOption::some(7);
let z = ConcurrentOption::<i32>::none();
assert!(x.eq(&x));
assert!(!x.eq(&y));
assert!(!x.eq(&z));
assert!(!z.eq(&x));
assert!(!z.eq(&y));
assert!(z.eq(&z));
Source§impl<T: PartialOrd> PartialOrd for ConcurrentOption<T>
impl<T: PartialOrd> PartialOrd for ConcurrentOption<T>
Source§fn partial_cmp(&self, other: &Self) -> Option<Ordering>
fn partial_cmp(&self, other: &Self) -> Option<Ordering>
Returns an ordering between self
and other
with the default ordering.
You may call partial_cmp_with_order
to use the desired ordering.
use orx_concurrent_option::*;
use core::cmp::Ordering::*;
let x = ConcurrentOption::some(3);
let y = ConcurrentOption::some(7);
let z = ConcurrentOption::<i32>::none();
assert_eq!(x.partial_cmp(&x), Some(Equal));
assert_eq!(x.partial_cmp(&y), Some(Less));
assert_eq!(x.partial_cmp(&z), Some(Greater));
assert_eq!(y.partial_cmp(&x), Some(Greater));
assert_eq!(y.partial_cmp(&y), Some(Equal));
assert_eq!(y.partial_cmp(&z), Some(Greater));
assert_eq!(z.partial_cmp(&x), Some(Less));
assert_eq!(z.partial_cmp(&y), Some(Less));
assert_eq!(z.partial_cmp(&z), Some(Equal));