1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
//! Provides the ability to unwrap elements of tuples.
//!
//! This module is only available when the `unwrap` feature is enabled (enabled by default).
//!
//! Since this module introduces the [`unwrap()`](Unwrap::unwrap()) method that may cause panic,
//! you may choose to disable it to avoid. Even if you accept it, it is more recommended that you use [`unwrap_or_default()`](UnwrapOrDefault::unwrap_or_default()) or
//! [`try_unwrap()`](Tuple::try_unwrap()) to avoid panic.
use crate::{Tuple, TupleLike, Unit};
/// Indicate that a type is a wrapper of a value and can be unwrapped into it.
///
/// [`Unwrap`] is implemented by default for four types:
/// * [`Option<T>`](std::option::Option)
/// * [`Result<T, E>`](std::result::Result)
/// * [`Unit`]
/// * [`Tuple<T0, T1, ... Tn>`](crate::Tuple) if all types `T0`, `T1`, ... `Tn` implement [`Unwrap`].
///
/// Implement [`Unwrap`] for your own wrapper types so that a [`Tuple`] containing your wrappers can be [`unwrap()`](Unwrap::unwrap()).
#[cfg_attr(docsrs, doc(cfg(feature = "unwrap")))]
pub trait Unwrap {
/// Type of the contained value.
type UnwrapOutput;
/// Get the contained value.
///
/// Because this function may panic, its use is generally discouraged. Instead,
/// use [`unwrap_or_default()`](UnwrapOrDefault::unwrap_or_default()) or
/// [`try_unwrap()`](Tuple::try_unwrap()).
///
/// Hint: The [`TupleLike`] trait provides the [`unwrap()`](TupleLike::unwrap()) method as the wrapper
/// for this [`unwrap()`](Unwrap::unwrap()) method.
///
/// # Panic
///
/// Panic if self does not contain a value.
///
/// # Example
///
/// ```
/// use tuplez::{tuple, TupleLike};
///
/// let tup = tuple!(Some(1), Ok::<f32, ()>(3.14), Some("hello"));
/// assert_eq!(tup.unwrap(), tuple!(1, 3.14, "hello"));
/// ```
fn unwrap(self) -> Self::UnwrapOutput;
/// Check if self contains a value.
///
/// Soundness requirement: When [`has_value()`](Unwrap::has_value()) returns true, [`unwrap()`](Unwrap::unwrap()) cannot panic.
///
/// Hint: The [`TupleLike`] trait provides the [`has_value()`](TupleLike::has_value()) method as the wrapper
/// for this [`has_value()`](Unwrap::has_value()) method.
///
/// # Example
///
/// ```
/// use tuplez::{tuple, TupleLike};
///
/// assert_eq!(tuple!(Some(1), Some(3.14), Ok::<&str, ()>("hello")).has_value(), true);
/// assert_eq!(tuple!(None::<i32>, Some(3.14), Err::<&str, ()>(())).has_value(), false);
/// ```
fn has_value(&self) -> bool;
}
/// Indicate that a type is a wrapper of a value and can be unwrapped into it or the default value.
///
/// Unlike [`Unwrap`], the trait [`UnwrapOrDefault`] indicates that when the wrapper does not contain a value,
/// it's able to create a default value instead of panic.
///
/// [`UnwrapOrDefault`] is implemented by default for four types:
/// * [`Option<T>`](std::option::Option)
/// * [`Result<T, E>`](std::result::Result)
/// * [`Unit`]
/// * [`Tuple<T0, T1, ... Tn>`](crate::Tuple) if all types `T0`, `T1`, ... `Tn` implement [`UnwrapOrDefault`].
///
/// Implement [`UnwrapOrDefault`] for your own wrapper types so that a [`Tuple`] containing your wrappers can
/// be [`unwrap_or_default()`](UnwrapOrDefault::unwrap_or_default()).
#[cfg_attr(docsrs, doc(cfg(feature = "unwrap")))]
pub trait UnwrapOrDefault {
/// Type of the contained value.
type UnwrapOutput;
/// Get the contained value, or the default value if self does not contain a value.
///
/// Hint: The [`TupleLike`] trait provides the [`unwrap_or_default()`](TupleLike::unwrap_or_default())
/// method as the wrapper for this [`unwrap_or_default()`](UnwrapOrDefault::unwrap_or_default()) method.
///
/// # Example
///
/// ```
/// use tuplez::{tuple, TupleLike};
///
/// let tup = tuple!(Some(1), Err::<f32, &str>("failed"), Some("hello"));
/// assert_eq!(tup.unwrap_or_default(), tuple!(1, 0.0, "hello"));
/// ```
fn unwrap_or_default(self) -> Self::UnwrapOutput;
}
impl<T> Unwrap for Option<T> {
type UnwrapOutput = T;
fn unwrap(self) -> Self::UnwrapOutput {
self.unwrap()
}
fn has_value(&self) -> bool {
self.is_some()
}
}
impl<T, E: std::fmt::Debug> Unwrap for Result<T, E> {
type UnwrapOutput = T;
fn unwrap(self) -> Self::UnwrapOutput {
self.unwrap()
}
fn has_value(&self) -> bool {
self.is_ok()
}
}
impl<T: Default> UnwrapOrDefault for Option<T> {
type UnwrapOutput = T;
fn unwrap_or_default(self) -> Self::UnwrapOutput {
self.unwrap_or_default()
}
}
impl<T: Default, E> UnwrapOrDefault for Result<T, E> {
type UnwrapOutput = T;
fn unwrap_or_default(self) -> Self::UnwrapOutput {
self.unwrap_or_default()
}
}
impl Unwrap for Unit {
type UnwrapOutput = Unit;
fn unwrap(self) -> Self::UnwrapOutput {
Self
}
fn has_value(&self) -> bool {
true
}
}
impl<First, Other> Unwrap for Tuple<First, Other>
where
Other: TupleLike + Unwrap,
First: Unwrap,
{
type UnwrapOutput = Tuple<First::UnwrapOutput, Other::UnwrapOutput>;
fn unwrap(self) -> Self::UnwrapOutput {
Tuple(Unwrap::unwrap(self.0), Unwrap::unwrap(self.1))
}
fn has_value(&self) -> bool {
Unwrap::has_value(&self.0) && Unwrap::has_value(&self.1)
}
}
impl UnwrapOrDefault for Unit {
type UnwrapOutput = Unit;
fn unwrap_or_default(self) -> Self::UnwrapOutput {
Self
}
}
impl Unit {
/// Always be `Some(tuple!())`.
pub fn try_unwrap(self) -> Option<Self> {
Some(self)
}
}
impl<First, Other> UnwrapOrDefault for Tuple<First, Other>
where
Other: TupleLike + UnwrapOrDefault,
First: UnwrapOrDefault,
{
type UnwrapOutput = Tuple<First::UnwrapOutput, Other::UnwrapOutput>;
fn unwrap_or_default(self) -> Self::UnwrapOutput {
Tuple(
UnwrapOrDefault::unwrap_or_default(self.0),
UnwrapOrDefault::unwrap_or_default(self.1),
)
}
}