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
//! Structured, understandable runtime contracts.
//!
//! While many languages have contract libraries, many opt to compile them only in debug and test builds. The reasoning behind
//! this choice seems to be that they don't wish to incur a performance penalty in production.
//! A notable exception is [Racket's contracts module](https://docs.racket-lang.org/reference/contracts.html), itself a [work of art](https://docs.racket-lang.org/guide/contracts.html).
//! In this library, we eschew this concern in the name of both runtime safety and program correctness.
//!
//! This crate wishes to make it easier for practitioners building software to use and understand Programming-by-Contract.
//! The philosophy is directly inspired by the [Design-by-Contract](https://en.wikipedia.org/wiki/Design_by_contract) (DbC)
//! concept expressed by noted Computer Scientist, [Dr. Betrand Meyer](https://en.wikipedia.org/wiki/Bertrand_Meyer) when
//! designing the [Eiffel programming language](https://en.wikipedia.org/wiki/Eiffel_(programming_language)) in 1986.
//!
//! Additionally, much thanks goes to the [`contracts`](https://crates.io/crates/contracts) crate which implements contacts
//! as procedural macros. Definitely check it out!
//!
//! # Examples
//!
//! Though this example uses the crate's own error type, you can substitute whatever you wish so long as it works.
//!
//! ```
//! use runtime_contracts::{check, ensures, requires, error::RuntimeContractError, Result};
//!
//! # struct Account {
//! #   pub balance: usize,
//! # }
//! # impl Account {
//! #   pub fn add_to_balance(&self, amount: usize) -> Result<usize> {
//! #     Ok(self.balance + amount)
//! #   }
//! # }
//! # fn load_account(i: &str) -> Account {
//! #   Account { balance: 613 }
//! # }
//!
//! fn refund_loyalty_points(account_id: &str, point_amount: usize) -> Result<usize> {
//!   requires(|| account_id.len() == 32, "malformed account ID")?;
//!   requires(|| point_amount % 2 == 0, "attempting to refund an odd number of points")?;
//!
//!   let account = load_account(account_id);
//!   let starting_balance = account.balance;
//!   let closing_balance = account.add_to_balance(point_amount)?;
//!
//!   ensures(closing_balance, |balance| balance - point_amount == starting_balance, "points were not added to account")
//! }
//! ```

pub mod error;

pub type Result<T, E = error::RuntimeContractError> = core::result::Result<T, E>;

pub type RuntimeContractFunction<T> = dyn Fn(T) -> Result<T>;

/// Checks an arbitrary condition expressed by the given predicate. This is most useful for validating arguments at the _start_
/// of a function. You must provide an error message, so it often makes sense to call `requires` once for each argument. This allows
/// for passing more specific error messages back to the caller.
///
/// # Examples
///
/// Though these example use the crate's own error type, you can substitute whatever you wish so long as it works.
///
/// ```
/// use runtime_contracts::{requires, error::RuntimeContractError};
///
/// fn add_two(i: i32, j: i32) -> Result<i32, RuntimeContractError> {
///   requires(|| i > 0, "i must be greater than 0")?;
///   requires(|| j > 0, "j must be greater than 0")?;
///
///   Ok(i + j)
/// }
///
/// assert!(add_two(2, 3).is_ok());
/// ```
///
/// The above example seem a bit silly since the usage of `i32` could just as easily be changed to `u32` to prevent passing
/// in a negative number literal. For example, the following fails to compile:
///
/// ```compile_fail
/// use runtime_contracts::{requires, error::RuntimeContractError};
///
/// fn add_two(i: u32, j: u32) -> Result<u32, RuntimeContractError> {
///   requires(|| i > 0, "i must be greater than 0")?;
///   requires(|| j > 0, "j must be greater than 0")?;
///
///   Ok(i + j)
/// }
///
/// assert!(add_two(-2, 3).is_ok());
/// ```
///
/// However, what if the number in question is obtained from an external source? In this case, the external source may provide
/// malformed input! For this reason, it is especially useful to use `requires` to validate input. You can even use the provided
/// combinator on Rust's Result type to chain contracts into a single statement:
///
/// ```
/// use runtime_contracts::{requires, error::RuntimeContractError};
///
/// fn add_two(i: i32, j: i32) -> Result<i32, RuntimeContractError> {
///   requires(|| i > 0, "i must be greater than 0")
///     .and_then(|_| requires(|| j > 0, "j must be greater than 0"))?;
///
///   Ok(i + j)
/// }
///
/// assert!(add_two(2, 3).is_ok());
/// ```
pub fn requires<F, M>(pred: F, message: M) -> Result<()>
where
  F: Fn() -> bool,
  M: std::fmt::Display,
{
  if pred() {
    Ok(())
  } else {
    let err = error::RuntimeContractError::RequiresFailure(message.to_string());

    Err(err)
  }
}

/// Checks an arbitrary condition expressed in a predicate run against a given value. If the condition is satisfied(read: if the
/// predicate evaluates to true) this function yields the value passed to it. Ergo, it is most useful for checking return values
/// at the _end_ of a function. You must provide an error message in case of failure.
///
/// # Examples
///
/// Though these example use the crate's own error type, you can substitute whatever you wish so long as it works.
///
/// ```
/// use runtime_contracts::{ensures, error::RuntimeContractError};
///
/// fn add_two(i: i32, j: i32) -> Result<i32, RuntimeContractError> {
///   ensures(i + j, |sum| *sum > 0, "the sum of i and j must be greater than 0")
/// }
///
/// let eleven_result = add_two(5, 6);
/// assert!(eleven_result.is_ok());
/// assert_eq!(eleven_result.unwrap(), 11);
///
/// let five_result = add_two(10, -5);
/// assert!(five_result.is_ok());
/// assert_eq!(five_result.unwrap(), 5);
///
/// // In the below, the output value doesn't satisfy the contract since `5 + - 5 = 5 - 5` is not greater than 0.
/// assert!(add_two(5, -5).is_err());
/// ```
///
pub fn ensures<T, F, M>(value: T, predicate: F, message: M) -> Result<T>
where
  T: Clone,
  F: FnOnce(&T) -> bool,
  M: std::fmt::Display,
{
  if predicate(&value) {
    Ok(value)
  } else {
    let err = error::RuntimeContractError::EnsuresFailure(message.to_string());

    Err(err)
  }
}

/// Verifies than an arbitrary condition is met, intended to verify preservation of an invariant at runtime.
/// Think of this as a `requires` designed to be used anywhere in control flow.

pub fn check<F, M>(pred: F, message: M) -> Result<()>
where
  F: FnOnce() -> bool,
  M: std::fmt::Display,
{
  if pred() {
    Ok(())
  } else {
    let err_msg = format!("invariant violated: {message}",);
    let err = error::RuntimeContractError::CheckFailure(err_msg);

    Err(err)
  }
}