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