defuse_near_utils/
lock.rs1use std::io;
2
3use defuse_borsh_utils::adapters::{AsWrap, BorshDeserializeAs, BorshSerializeAs};
4use near_sdk::{
5 borsh::{BorshDeserialize, BorshSerialize},
6 near,
7};
8
9#[derive(Debug, Default, PartialEq, Eq)]
13#[near(serializers = [borsh, json])]
14pub struct Lock<T> {
15 #[serde(
16 default,
17 skip_serializing_if = "::core::ops::Not::not"
19 )]
20 locked: bool,
21 #[serde(flatten)]
22 value: T,
23}
24
25impl<T> Lock<T> {
26 #[must_use]
27 #[inline]
28 pub const fn new(locked: bool, value: T) -> Self {
29 Self { locked, value }
30 }
31
32 #[must_use]
33 #[inline]
34 pub const fn unlocked(value: T) -> Self {
35 Self::new(false, value)
36 }
37
38 #[must_use]
39 #[inline]
40 pub const fn locked(value: T) -> Self {
41 Self::new(true, value)
42 }
43
44 #[inline]
45 pub const fn set_locked(&mut self, locked: bool) -> &mut Self {
46 self.locked = locked;
47 self
48 }
49
50 #[inline]
55 pub const fn as_inner_unchecked(&self) -> &T {
56 &self.value
57 }
58
59 #[inline]
63 pub const fn as_inner_unchecked_mut(&mut self) -> &mut T {
64 &mut self.value
65 }
66
67 #[inline]
68 pub fn into_inner_unchecked(self) -> T {
69 self.value
70 }
71
72 #[must_use]
73 #[inline]
74 pub const fn is_locked(&self) -> bool {
75 self.locked
76 }
77
78 #[must_use]
79 #[inline]
80 pub const fn as_locked(&self) -> Option<&T> {
81 if !self.is_locked() {
82 return None;
83 }
84 Some(self.as_inner_unchecked())
85 }
86
87 #[must_use]
88 #[inline]
89 pub const fn as_locked_mut(&mut self) -> Option<&mut T> {
90 if !self.is_locked() {
91 return None;
92 }
93 Some(self.as_inner_unchecked_mut())
94 }
95
96 #[must_use]
97 #[inline]
98 pub const fn as_locked_mut_maybe_forced(&mut self, force: bool) -> Option<&mut T> {
99 if force {
100 Some(self.as_inner_unchecked_mut())
101 } else {
102 self.as_locked_mut()
103 }
104 }
105
106 #[must_use]
107 #[inline]
108 pub fn into_locked(self) -> Option<T> {
109 if !self.is_locked() {
110 return None;
111 }
112 Some(self.value)
113 }
114
115 #[must_use]
116 #[inline]
117 pub const fn lock(&mut self) -> Option<&mut T> {
118 if self.is_locked() {
119 return None;
120 }
121 self.locked = true;
122 Some(self.as_inner_unchecked_mut())
123 }
124
125 #[inline]
126 pub const fn force_lock(&mut self) -> &mut T {
127 self.locked = true;
128 self.as_inner_unchecked_mut()
129 }
130
131 #[must_use]
132 #[inline]
133 pub const fn get(&self) -> Option<&T> {
134 if self.is_locked() {
135 return None;
136 }
137 Some(self.as_inner_unchecked())
138 }
139
140 #[must_use]
141 #[inline]
142 pub const fn get_mut(&mut self) -> Option<&mut T> {
143 if self.is_locked() {
144 return None;
145 }
146 Some(self.as_inner_unchecked_mut())
147 }
148
149 #[must_use]
150 #[inline]
151 pub const fn get_mut_maybe_forced(&mut self, force: bool) -> Option<&mut T> {
152 if force {
153 Some(self.as_inner_unchecked_mut())
154 } else {
155 self.get_mut()
156 }
157 }
158
159 #[must_use]
160 #[inline]
161 pub fn into_unlocked(self) -> Option<T> {
162 if self.is_locked() {
163 return None;
164 }
165 Some(self.value)
166 }
167
168 #[must_use]
169 #[inline]
170 pub const fn unlock(&mut self) -> Option<&mut T> {
171 if !self.is_locked() {
172 return None;
173 }
174 self.locked = false;
175 Some(self.as_inner_unchecked_mut())
176 }
177
178 #[inline]
179 pub const fn force_unlock(&mut self) -> &mut T {
180 self.locked = false;
181 self.as_inner_unchecked_mut()
182 }
183
184 #[inline]
185 pub const fn as_ref(&self) -> Lock<&T> {
186 Lock::new(self.is_locked(), self.as_inner_unchecked())
187 }
188
189 #[inline]
190 pub const fn as_mut(&mut self) -> Lock<&mut T> {
191 Lock::new(self.is_locked(), self.as_inner_unchecked_mut())
192 }
193
194 #[inline]
195 pub fn map_inner_unchecked<U, F>(self, f: F) -> Lock<U>
196 where
197 F: FnOnce(T) -> U,
198 {
199 Lock::new(self.is_locked(), f(self.into_inner_unchecked()))
200 }
201}
202
203impl<T> From<T> for Lock<T> {
204 #[inline]
205 fn from(value: T) -> Self {
206 Self::unlocked(value)
207 }
208}
209
210impl<T, As> BorshSerializeAs<Lock<T>> for Lock<As>
211where
212 As: BorshSerializeAs<T>,
213{
214 #[inline]
215 fn serialize_as<W>(source: &Lock<T>, writer: &mut W) -> io::Result<()>
216 where
217 W: io::Write,
218 {
219 Lock {
220 locked: source.locked,
221 value: AsWrap::<&T, &As>::new(&source.value),
222 }
223 .serialize(writer)
224 }
225}
226
227impl<T, As> BorshDeserializeAs<Lock<T>> for Lock<As>
228where
229 As: BorshDeserializeAs<T>,
230{
231 #[inline]
232 fn deserialize_as<R>(reader: &mut R) -> io::Result<Lock<T>>
233 where
234 R: io::Read,
235 {
236 Lock::<AsWrap<T, As>>::deserialize_reader(reader).map(|v| Lock {
237 locked: v.locked,
238 value: v.value.into_inner(),
239 })
240 }
241}
242
243#[cfg(test)]
244#[test]
245fn test() {
246 let mut a = Lock::new(false, 0);
247
248 assert!(!a.is_locked());
249 assert_eq!(a.unlock(), None);
250
251 assert_eq!(a.get().copied(), Some(0));
252 *a.get_mut().unwrap() += 1;
253 assert_eq!(*a.as_inner_unchecked(), 1);
254
255 assert_eq!(a.lock().copied(), Some(1));
256 assert!(a.is_locked());
257
258 assert_eq!(a.as_locked().copied(), Some(1));
259 *a.as_locked_mut().unwrap() += 1;
260 assert_eq!(*a.as_inner_unchecked(), 2);
261}