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
//! # DoublySure
//!
//! > Using types to make sure that you're sure, sure, and doubly sure
//!
//! Users get prompted to make sure they want to perform a destructive action,
//! why shouldn't developers?
//!
//! This crate is composed of only the `AreYouSure` enum, and the `make_sure`
//! macro. Check their individual documentation for more info.
//!
//! ## Usage
//!
//! The core usage is simple, when you encounter an `AreYouSure` type you must
//! answer the question:
//!
//! - Call `.yes_i_am_sure()` to run deferred functions and runwrap the value.
//! - Or call `.no_i_am_not_sure()` to discard, doing nothing.
//!
//! The `make_sure` macro exists to wrap existing values, functions, and code
//! blocks in the `AreYouSure` type.
//!
//! ### Library Usage
//!
//! DoublySure really shines when you use it within the public API of your own
//! libraries as the return type of dangerous functions.
//!
//! ```ignore
//! pub fn dangerous(num: usize) -> AreYouSure<Result<()>> {
//!     // Set things up...
//!
//!     return make_sure!({
//!        // dangerous operation that will not be run
//!        // until the user calls .yes_i_am_sure()
//!     });
//! }
//! ```

mod tests;

/// A type that asks the user the all important question:
/// Are you sure you want to do this?
///
/// The functions on this type are intentionally verbose so that users
/// understand that they are confirming a potentially destructive action.
pub enum AreYouSure<T> {
    /// A value that will be returned when `yes_i_am_sure()` is called.
    Value(T),
    /// A function that was deferred and will be run later when
    /// `yes_i_am_sure()` is called.
    DeferredFunction(Box<dyn Fn() -> T>),
}

impl<T> AreYouSure<T> {
    /// Creates a new `AreYouSure` wrapping around a value.
    /// This is the same as `AreYouSure::Value()`.
    ///
    /// The `make_sure` macro is the preferred way of creating an `AreYouSure`.
    pub fn new(val: T) -> Self {
        Self::Value(val)
    }

    /// You are, in fact, sure that you want to do this.
    ///
    /// Returns the inner value, or runs the deferred function and returns
    /// whatever it does.
    pub fn yes_i_am_sure(self) -> T {
        match self {
            Self::Value(x) => x,
            Self::DeferredFunction(f) => f(),
        }
    }

    /// You're not actually sure you want to do this.
    ///
    /// This will discard the `AreYouSure` dropping it's value and will not run
    /// deferred functions.
    pub fn no_i_am_not_sure(self) {
        // Does nothing, but took ownership of `self`
    }
}

/// Macro to wrap values in an `AreYouSure`. Or in other words, it makes sure of
/// something.
///
/// Creates an `AreYouSure`, possibly deferring execution of a function or block
/// of code.
///
/// ## Variants
/// This macro has three variants, each with their own use cases.
///
/// You can wrap a value or expression directly.
///
/// ```
/// # #[macro_use] extern crate doublysure;
/// # fn main() {
///
/// let sure = make_sure!(4 + 1);
/// let x = sure.yes_i_am_sure();
/// assert_eq!(x, 5);
///
/// # }
/// ```
///
/// You can defer a function. While it looks like `min()` is called here,
/// it will actually be called later when `yes_i_am_sure()` is called.
/// This means that functions with destructive side effects cannot happen until
/// you have confirmed you are sure.
///
/// ```
/// # #[macro_use] extern crate doublysure;
/// # fn main() {
///
/// let sure = make_sure!(std::cmp::min(4, 5));
/// let x = sure.yes_i_am_sure();
/// assert_eq!(x, 4);
///
/// # }
/// ```
///
/// Finally you can defer a block of code for later execution. Keep in mind you
/// still need the parentheses around the block.
/// This form requires the most care to use. Keep in mind as well that the
/// return value of the block is the last expression without a `;` and **not**
/// the `return`.
///
/// ```
/// # #[macro_use] extern crate doublysure;
/// # fn main() {
///
/// let sure = make_sure!({
///   let x = 4;
///   let y = 5;
///   std::cmp::min(x, y)
/// });
/// let x = sure.yes_i_am_sure();
/// assert_eq!(x, 4);
///
/// # }
/// ```
#[macro_export]
macro_rules! make_sure {
    ($name:ident($($arg:expr),*)) => {
        $crate::AreYouSure::DeferredFunction(Box::new(|| $name($($arg),*)))
    };
    ($code:block) => {
        $crate::AreYouSure::DeferredFunction(Box::new(|| { $code }))
    };
    ($value:expr) => {
        $crate::AreYouSure::Value($value)
    };
}