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),
        )
    }
}