Struct ConcurrentOption

Source
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.

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 use as_ref_with_order paired up with Acquire or SeqCst 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>

Source

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 was is_none variant and initiated with the given value.
  • It does nothing if the concurrent option is already of is_some variant, and returns false.

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());
Source

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());
Source

pub fn update_if_some<F>(&self, f: F) -> bool
where F: FnMut(&mut T),

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);
Source

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);
Source

pub fn take_if<P>(&self, predicate: P) -> Option<T>
where P: FnOnce(&mut T) -> bool,

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));
Source

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);
Source

pub fn set_some(&self, value: T) -> bool

true if updated; false if initiated

Source

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);
Source

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));
Source

pub unsafe fn get_or_insert_with<F>(&self, f: F) -> &mut T
where 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>

Source

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>

Source

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()));
Source

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));
Source

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);
Source

pub fn exclusive_take_if<P>(&mut self, predicate: P) -> Option<T>
where P: FnOnce(&mut T) -> bool,

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));
Source

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);
Source

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);
Source

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);
Source

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));
Source

pub fn exclusive_get_or_insert_with<F>(&mut self, f: F) -> &mut T
where 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>

Source

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`
Source

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
Source

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");
Source

pub fn unwrap_or_default(self) -> T
where 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);
Source

pub fn unwrap_or_else<F>(self, f: F) -> T
where 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);
Source

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>

Source

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());
Source

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>

Source

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);
Source

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);
Source

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 with initialize_when_none method. This is perfectly safe since the value will be written only once, and as_ref returns a valid reference only after the value is initialized.
  • 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);
Source

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 with initialize_when_none method. This is perfectly safe since the value will be written only once, and as_ref returns a valid reference only after the value is initialized.
  • 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);
Source

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 with initialize_when_none method. This is perfectly safe since the value will be written only once, and as_ref returns a valid reference only after the value is initialized.
  • 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());
Source

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));
Source

pub fn map<U, F>(&self, f: F) -> Option<U>
where F: FnOnce(&T) -> 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 as take.
    • an exception to this is the initialize_if_none method which fits very well the initialize-once scenarios; here, as_ref and initialize_if_none can safely be called concurrently from multiple threads.
§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));
Source

pub fn map_or<U, F>(&self, default: U, f: F) -> U
where F: FnOnce(&T) -> 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);
Source

pub fn map_or_else<U, D, F>(&self, default: D, f: F) -> U
where D: FnOnce() -> U, F: FnOnce(&T) -> 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);
Source

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);
Source

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);
Source

pub fn and_then<U, V, F>(&self, f: F) -> Option<U>
where V: IntoOption<U>, F: FnOnce(&T) -> V,

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);
Source

pub unsafe fn filter<P>(&self, predicate: P) -> Option<&T>
where P: FnOnce(&T) -> bool,

Returns None if the option is None, otherwise calls predicate with the wrapped value and returns:

  • Some(t) if predicate returns true (where t is the wrapped value), and
  • None if predicate returns false.

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 with initialize_when_none method. This is perfectly safe since the value will be written only once, and as_ref returns a valid reference only after the value is initialized.
  • 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>

Source

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));
Source

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>>

Source

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>>

Source

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>

Source

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()));
Source

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()));
Source

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()));
Source

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>

Source

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);
Source

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);
Source

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);
Source

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 with initialize_when_none method. This is perfectly safe since the value will be written only once, and as_ref returns a valid reference only after the value is initialized.
  • 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);
Source

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 with initialize_when_none method. This is perfectly safe since the value will be written only once, and as_ref returns a valid reference only after the value is initialized.
  • 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);
}
Source

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 with initialize_when_none method. This is perfectly safe since the value will be written only once, and as_ref returns a valid reference only after the value is initialized.
  • 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());
}
Source

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);
Source

pub fn eq_with_order(&self, other: &Self, order: Ordering) -> bool
where 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));
Source

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));
Source

pub fn cmp_with_order(&self, other: &Self, order: Ordering) -> Ordering
where 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>

Source§

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)

Performs copy-assignment from source. Read more
Source§

impl<T: Debug> Debug for ConcurrentOption<T>

Source§

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>

Source§

fn default() -> Self

Returns the default value of ConcurrentOption, which is Concurrent::none().

§Examples
use orx_concurrent_option::*;

let x: ConcurrentOption::<String> = Default::default();
assert_eq!(x, ConcurrentOption::none());
Source§

impl<T> Drop for ConcurrentOption<T>

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

impl<T> From<ConcurrentOption<T>> for Option<T>

Source§

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>

Source§

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>

Source§

fn from(value: T) -> Self

Wraps the existing value to a ConcurrentOption of Some variant.

§Examples
use orx_concurrent_option::*;

let x: ConcurrentOption<String> = 3.to_string().into();
assert_eq!(unsafe { x.as_ref() }, Some(&3.to_string()));
Source§

impl<'a, T> IntoIterator for &'a ConcurrentOption<T>

Source§

type Item = &'a T

The type of the elements being iterated over.
Source§

type IntoIter = Iter<'a, T>

Which kind of iterator are we turning this into?
Source§

fn into_iter(self) -> Self::IntoIter

Creates an iterator from a value. Read more
Source§

impl<'a, T> IntoIterator for &'a mut ConcurrentOption<T>

Source§

type Item = &'a mut T

The type of the elements being iterated over.
Source§

type IntoIter = IterMut<'a, T>

Which kind of iterator are we turning this into?
Source§

fn into_iter(self) -> Self::IntoIter

Creates an iterator from a value. Read more
Source§

impl<T> IntoIterator for ConcurrentOption<T>

Source§

type Item = T

The type of the elements being iterated over.
Source§

type IntoIter = IntoIter<T>

Which kind of iterator are we turning this into?
Source§

fn into_iter(self) -> Self::IntoIter

Creates an iterator from a value. Read more
Source§

impl<T> IntoOption<T> for ConcurrentOption<T>

Source§

fn into_option(self) -> Option<T>

Converts self into Option. Read more
Source§

impl<T: Ord> Ord for ConcurrentOption<T>

Source§

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) -> Self
where Self: Sized,

Compares and returns the maximum of two values. Read more
1.21.0 · Source§

fn min(self, other: Self) -> Self
where Self: Sized,

Compares and returns the minimum of two values. Read more
1.50.0 · Source§

fn clamp(self, min: Self, max: Self) -> Self
where Self: Sized,

Restrict a value to a certain interval. Read more
Source§

impl<T: PartialEq> PartialEq for ConcurrentOption<T>

Source§

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));
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl<T: PartialOrd> PartialOrd for ConcurrentOption<T>

Source§

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));
1.0.0 · Source§

fn lt(&self, other: &Rhs) -> bool

Tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · Source§

fn le(&self, other: &Rhs) -> bool

Tests less than or equal to (for self and other) and is used by the <= operator. Read more
1.0.0 · Source§

fn gt(&self, other: &Rhs) -> bool

Tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · Source§

fn ge(&self, other: &Rhs) -> bool

Tests greater than or equal to (for self and other) and is used by the >= operator. Read more
Source§

impl<T: Eq> Eq for ConcurrentOption<T>

Source§

impl<T: Send> Send for ConcurrentOption<T>

Source§

impl<T: Sync> Sync for ConcurrentOption<T>

Auto Trait Implementations§

§

impl<T> !Freeze for ConcurrentOption<T>

§

impl<T> !RefUnwindSafe for ConcurrentOption<T>

§

impl<T> Unpin for ConcurrentOption<T>
where T: Unpin,

§

impl<T> UnwindSafe for ConcurrentOption<T>
where T: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<!> for T

Source§

fn from(t: !) -> T

Converts to this type from the input type.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.