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
//! System functions: non-negative integers
//!
//! At the start of a transaction, a storage location holds a non-negative-int
//! value if a previous transaction performed a "set" operation there, and the
//! most recent such operation placed a value of the non-negative-int storage
//! type. Otherwise, it does not contain a non-negative-int value.
//!
//! If the location does not contain a non-negative-int value, it may
//! nevertheless be set or incremented, after which it has a value in the
//! current transaction. An increment operation behaves as if there had been a
//! previous value of zero.
//!
//! If the location _does_ have a non-negative-int value, it may be set,
//! incremented, or retrieved (by `non_negative_int_get`).
//!
use cratennint_overflow;
use cratennint_internal as nnint;
use crateStorageKey;
const SHARED: bool = false;
const EXCLUSIVE: bool = true;
/// Get the current value.
///
/// Throws an exception if the location does not contain a non-negative-int value.
///
/// Get the current value, reporting failure as `Err` instead of aborting
/// (the `try_` law; see the [`exn`](mod@crate::exn) module docs).
///
/// The `Err` is exactly the exception [`non_negative_int_get`] would have
/// thrown. An empty location is a `LibraryExn::Syscall` for which
/// [`is_storage_missing`](crate::exn::LibraryExn::is_storage_missing) is
/// true — use [`none_if_missing`](crate::exn::NoneIfMissing::none_if_missing)
/// to treat just that case as an ordinary `None`. A value of the wrong
/// storage type or any other syscall failure is a `LibraryExn::Syscall` as
/// well; an overflowing `set + add` is `LibraryExn::NonNegativeIntOverflow`.
///
/// Set the value.
///
/// (This clears the effects of any previous "increment" operations.)
///
/// This call always succeeds, but it puts constraints on the transaction,
/// described below.
///
/// A negative value is allowed: it sets the commit-time floor to that value.
/// Subsequent increments may keep the value negative (down to the value set)
/// without an exception, but they cannot decrement below it — the storage layer
/// enforces `set + add >= min(set, 0)` at commit.
///
/// If a non-negative value is set, the floor is `0`: increments that would make
/// the committed value negative at the end of the transaction cause it to
/// revert.
///
/// A set of concurrent transactions with the same explicitly-set value may
/// included in the same block.
///
/// Set the value exclusively.
///
/// This behaves like [`non_negative_int_set`], with the additional constraint
/// that, if a concurrent exclusive-set operation is performed by another
/// contract invocation, only one such invocation can be included in the same
/// block. The set is followed by a request for an exclusive lock, which later
/// writes to the key in this transaction keep.
///
/// Increment the value.
///
/// Throws an exception if the increments accumulated from previous calls would overflow.
///
/// If a "set" operation has been used previously in this transaction and the
/// value resulting from adding the accumulated increments `amount` is
/// negative, this throws an exception.
///
/// Otherwise, if the resulting value (the value at the end of the last
/// transaction plus the accumulated increments) is negative, this function
/// will not immediately throw. But note the transaction constraints at
/// `non_negative_int_set`.
///
/// A set of concurrent transactions may be included in the same block if their
/// explicitly-set value is the same (see `non_negative_int_set`) and the sum
/// of that value and of all their increments is non-negative.
///
/// Increment the value.
///
/// This behaves similarly to `non_negative_int_inc`, except that it throws if
/// the sum of the explicitly-set value and the accumulated increments
/// would overflow, or if it is negative.
///
/// Increment the value, like [`non_negative_int_strict_inc`], but report
/// failure to the caller instead of throwing (the `try_` law; see the
/// [`exn`](mod@crate::exn) module docs), so a contract can raise a
/// domain-specific exception (e.g. an ERC20 "amount too large").
///
/// On `Err` the stored value is unmodified. The domain errors are
/// `LibraryExn::NonNegativeIntUnderflow` and
/// `LibraryExn::NonNegativeIntOverflow`; a wrong storage type at the key or
/// any other syscall failure surfaces as `LibraryExn::Syscall`. Uses a
/// single read-write pair, so checking before decrementing costs no extra
/// storage roundtrip over `non_negative_int_inc`.