my_ecs/ds/borrow.rs
1use std::{
2 marker::PhantomData,
3 mem,
4 ops::{Deref, DerefMut},
5 ptr,
6};
7
8/// A [`Holder`] that lends its inner value itself by cloning.
9#[derive(Debug)]
10pub struct SimpleHolder<V>(Holder<V, V, V>);
11
12impl<V: Clone> SimpleHolder<V> {
13 pub fn new(value: V) -> Self {
14 let fn_imm = |value: &V| -> V { value.clone() };
15 let fn_mut = |value: &mut V| -> V { value.clone() };
16 // Safety: `fn_imm` and `fn_mut` clones the value so that they don't
17 // require borrow check.
18 let inner = unsafe { Holder::new(value, fn_imm, fn_mut) };
19 Self(inner)
20 }
21
22 pub fn into_value(self) -> V {
23 self.0.into_value()
24 }
25}
26
27impl<V> Deref for SimpleHolder<V> {
28 type Target = Holder<V, V, V>;
29
30 fn deref(&self) -> &Self::Target {
31 &self.0
32 }
33}
34
35impl<V> DerefMut for SimpleHolder<V> {
36 fn deref_mut(&mut self) -> &mut Self::Target {
37 &mut self.0
38 }
39}
40
41/// A type that holds a value and allows us borrow the value.
42///
43/// When you want to borrow inner value you can call [`Holder::borrow`] or
44/// [`Holder::borrow_mut`]. They return the inner value wrapped in [`Borrowed`]
45/// which tracks borrow status.
46///
47/// Multiple immutable borrowing is allowed, but mutable borrowing is exclusive.
48/// If this struct is dropped while any borrowed value is alive, it causes
49/// panic. You can check it out using [`Holder::borrow_count`] to see there's
50/// any borrowed value.
51///
52/// # Features
53///
54/// Borrow check is enabled if and only if `check` feature is enabled.
55/// Otherwise, this struct does nothing special.
56#[derive(Debug)]
57pub struct Holder<V, BI, BM> {
58 /// The inner value holder holds.
59 value: V,
60
61 /// Reference count to check borrow status at runtime.
62 #[cfg(feature = "check")]
63 cnt: std::sync::Arc<std::sync::atomic::AtomicI32>,
64
65 /// Function that borrows the inner value immutably.
66 fn_imm: fn(&V) -> BI,
67
68 /// Function that borrows the inner value mutably.
69 fn_mut: fn(&mut V) -> BM,
70
71 _marker: PhantomData<(BI, BM)>,
72}
73
74impl<V, BI, BM> Holder<V, BI, BM> {
75 /// Initial reference count.
76 #[cfg(feature = "check")]
77 const CNT_INIT: i32 = 0;
78
79 /// Reference count for mutable borrow.
80 #[cfg(feature = "check")]
81 const CNT_EXC: i32 = -1;
82
83 /// Maximum number of immutable borrow.
84 #[cfg(feature = "check")]
85 const CNT_MAX: i32 = 1024;
86
87 /// Creates a [`Holder`] with the given value.
88 ///
89 /// `Holder` checks borrow rule at runtime by enabled feature `check`. But
90 /// it requires additional operations, so that if you are confident, you can
91 /// use the `Holder` without the borrow check.
92 ///
93 /// * `fn_imm` - Function that borrows the value and returns borrowed
94 /// immutable value.
95 /// * `fn_mut` - Function that borrows the value and returns borrowed
96 /// mutable value.
97 ///
98 /// # Safety
99 ///
100 /// `Holder` disables Rust default borrow checker. Borrow rule is not
101 /// checked even if the `fn_imm` and `fn_mut` return references to the inner
102 /// value. However, `Holder` checks the borrow rule at runtime by enabled
103 /// feature `check`. If the feature is not enabled, this function is unsafe
104 /// due to the disabled runtime borrow check.
105 ///
106 /// If the `fn_imm` and `fn_mut` returns static type instead of reference,
107 /// it's safe regardless of enabling the feature because they don't need
108 /// borrow check.
109 ///
110 /// # Examples
111 ///
112 /// ```
113 /// use my_ecs::ds::Holder;
114 ///
115 /// let mut holder: Holder<i32, &i32, &mut i32> = unsafe {
116 /// Holder::new(0, |v| v, |v| v)
117 /// };
118 /// let a = holder.borrow_mut().unwrap();
119 /// holder.borrow_mut().unwrap(); // No panic without `check` feature
120 /// println!("{a:?}");
121 /// ```
122 //
123 // Lifetime `v` allows us to put something in like example above.
124 pub unsafe fn new<'v>(value: V, fn_imm: fn(&'v V) -> BI, fn_mut: fn(&'v mut V) -> BM) -> Self {
125 let (fn_imm, fn_mut) = unsafe {
126 (
127 mem::transmute::<fn(&'v V) -> BI, fn(&V) -> BI>(fn_imm),
128 mem::transmute::<fn(&'v mut V) -> BM, fn(&mut V) -> BM>(fn_mut),
129 )
130 };
131
132 Self {
133 value,
134 #[cfg(feature = "check")]
135 cnt: std::sync::Arc::new(std::sync::atomic::AtomicI32::new(Self::CNT_INIT)),
136 fn_imm,
137 fn_mut,
138 _marker: PhantomData,
139 }
140 }
141
142 /// Unwraps the holder and returns inner value.
143 ///
144 /// # Examples
145 ///
146 /// ```
147 /// use my_ecs::ds::Holder;
148 ///
149 /// let holder = unsafe { Holder::new(0, |v| v, |v| v) };
150 /// assert_eq!(holder.into_value(), 0);
151 /// ```
152 pub fn into_value(self) -> V {
153 // Due to the drop impl, we cannot take `value` out. So checking on drop
154 // occurs here instead.
155
156 #[cfg(feature = "check")]
157 assert_eq!(self.cnt.load(std::sync::atomic::Ordering::Relaxed), 0);
158
159 // Safety: Pointer to self.value is valid.
160 let value = unsafe { ptr::read(&self.value as *const _) };
161 mem::forget(self);
162 value
163 }
164
165 /// Returns immutable borrow function that you inserted at [`Holder::new`].
166 pub fn get_fn_imm(&self) -> fn(&V) -> BI {
167 self.fn_imm
168 }
169
170 /// Returns mutable borrow function that you inserted at [`Holder::new`].
171 pub fn get_fn_mut(&self) -> fn(&mut V) -> BM {
172 self.fn_mut
173 }
174
175 /// Borrows inner value.
176 ///
177 /// If `check` feature is enabled, runtime borrow checker works and blocks
178 /// try borrowing value after mutable borrow.
179 ///
180 /// # Examples
181 ///
182 /// ```
183 /// use my_ecs::ds::Holder;
184 ///
185 /// let holder = unsafe { Holder::new(0, |v| v, |v| v) };
186 /// assert_eq!(*holder.borrow().unwrap(), &0);
187 /// ```
188 pub fn borrow(&self) -> BorrowResult<BI> {
189 self.count_ref()?;
190 let value = (self.fn_imm)(&self.value);
191
192 #[cfg(feature = "check")]
193 {
194 let exclusive = false;
195 let cnt = std::sync::Arc::clone(&self.cnt);
196 Ok(Borrowed::new(value, exclusive, cnt))
197 }
198
199 #[cfg(not(feature = "check"))]
200 Ok(Borrowed::new(value))
201 }
202
203 /// Borrows inner value mutably.
204 ///
205 /// If `check` feature is enabled, runtime borrow checker works and blocks
206 /// try borrowing value after mutable or immutable borrow.
207 ///
208 /// # Examples
209 ///
210 /// ```
211 /// use my_ecs::ds::Holder;
212 ///
213 /// let mut holder = unsafe { Holder::new(0, |v| v, |v| v) };
214 /// **holder.borrow_mut().unwrap() = 1;
215 /// assert_eq!(*holder.borrow().unwrap(), &1);
216 /// ```
217 pub fn borrow_mut(&mut self) -> BorrowResult<BM> {
218 self.count_mut()?;
219 let value = (self.fn_mut)(&mut self.value);
220
221 #[cfg(feature = "check")]
222 {
223 let exclusive = true;
224 let cnt = std::sync::Arc::clone(&self.cnt);
225 Ok(Borrowed::new(value, exclusive, cnt))
226 }
227
228 #[cfg(not(feature = "check"))]
229 Ok(Borrowed::new(value))
230 }
231
232 /// Returns shared reference to the inner value without calling immutable
233 /// borrow function that you inserted at [`Holder::new`].
234 ///
235 /// If `check` feature is enabled, runtime borrow checker works and blocks
236 /// try borrowing value after mutable borrow.
237 ///
238 /// # Examples
239 ///
240 /// ```
241 /// use my_ecs::ds::Holder;
242 ///
243 /// let holder = unsafe { Holder::new(0, |v| *v + 1, |v| *v + 1) };
244 /// let value = holder.get().unwrap();
245 /// assert_eq!(*value, &0); // Due to bypassed borrow function.
246 /// ```
247 pub fn get(&self) -> BorrowResult<&V> {
248 self.count_ref()?;
249 let value = &self.value;
250
251 #[cfg(feature = "check")]
252 {
253 let exclusive = false;
254 let cnt = std::sync::Arc::clone(&self.cnt);
255 Ok(Borrowed::new(value, exclusive, cnt))
256 }
257
258 #[cfg(not(feature = "check"))]
259 Ok(Borrowed::new(value))
260 }
261
262 /// Returns mutable reference to the inner value without calling mutable
263 /// borrow function that you inserted at [`Holder::new`].
264 ///
265 /// If `check` feature is enabled, runtime borrow checker works and blocks
266 /// try borrowing value after mutable or immutable borrow.
267 ///
268 /// # Examples
269 ///
270 /// ```
271 /// use my_ecs::ds::Holder;
272 ///
273 /// let mut holder = unsafe { Holder::new(0, |v| *v + 1, |v| *v + 1) };
274 /// let value = holder.get_mut().unwrap();
275 /// assert_eq!(*value, &mut 0); // Due to bypassed borrow function.
276 /// ```
277 pub fn get_mut(&mut self) -> BorrowResult<&mut V> {
278 self.count_mut()?;
279 let value = &mut self.value;
280
281 #[cfg(feature = "check")]
282 {
283 let exclusive = true;
284 let cnt = std::sync::Arc::clone(&self.cnt);
285 Ok(Borrowed::new(value, exclusive, cnt))
286 }
287
288 #[cfg(not(feature = "check"))]
289 Ok(Borrowed::new(value))
290 }
291
292 /// Returns shared reference to inner value without borrow check.
293 ///
294 /// # Safety
295 ///
296 /// Undefined behavior if exclusive borrow happened before.
297 ///
298 /// # Examples
299 ///
300 /// ```
301 /// use my_ecs::ds::Holder;
302 ///
303 /// let holder = unsafe { Holder::new(0, |v| v, |v| v) };
304 /// let value = unsafe { holder.get_unchecked() };
305 /// assert_eq!(value, &0);
306 /// ```
307 pub unsafe fn get_unchecked(&self) -> &V {
308 &self.value
309 }
310
311 /// Returns mutable reference to inner value without borrow check.
312 ///
313 /// # Safety
314 ///
315 /// Undefined behavior if exclusive borrow happened before.
316 ///
317 /// # Examples
318 ///
319 /// ```
320 /// use my_ecs::ds::Holder;
321 ///
322 /// let mut holder = unsafe { Holder::new(0, |v| v, |v| v) };
323 /// let value = unsafe { holder.get_unchecked_mut() };
324 /// assert_eq!(value, &0);
325 /// ```
326 pub unsafe fn get_unchecked_mut(&mut self) -> &mut V {
327 &mut self.value
328 }
329
330 /// Returns current reference count.
331 ///
332 /// Returning reference count will be
333 /// - Greater than zero meaning there exist immutable borrow at the time.
334 /// - Lesser than zero meaning there exist mutable borrow at the time.
335 /// - Zero meaning no borrow at the time or `check` feature is disabled.
336 pub fn borrow_count(&self) -> i32 {
337 #[cfg(feature = "check")]
338 {
339 self.cnt.load(std::sync::atomic::Ordering::Relaxed)
340 }
341
342 #[cfg(not(feature = "check"))]
343 {
344 0
345 }
346 }
347
348 fn count_ref(&self) -> Result<(), BorrowError> {
349 #[cfg(feature = "check")]
350 {
351 use std::sync::atomic::Ordering;
352
353 let old = self.cnt.fetch_add(1, Ordering::Relaxed);
354 if old > Self::CNT_MAX {
355 self.cnt.fetch_sub(1, Ordering::Relaxed);
356 Err(BorrowError::TooManyBorrow)
357 } else if old == Self::CNT_EXC {
358 self.cnt.fetch_sub(1, Ordering::Relaxed);
359 Err(BorrowError::ExclusiveFailed)
360 } else {
361 Ok(())
362 }
363 }
364
365 #[cfg(not(feature = "check"))]
366 Ok(())
367 }
368
369 fn count_mut(&mut self) -> Result<(), BorrowError> {
370 #[cfg(feature = "check")]
371 {
372 use std::sync::atomic::Ordering;
373
374 self.cnt
375 .compare_exchange(
376 Self::CNT_INIT,
377 Self::CNT_EXC,
378 Ordering::Relaxed,
379 Ordering::Relaxed,
380 )
381 .map_err(|_| BorrowError::ExclusiveFailed)?;
382 Ok(())
383 }
384
385 #[cfg(not(feature = "check"))]
386 Ok(())
387 }
388}
389
390impl<V, BI, BM> Drop for Holder<V, BI, BM> {
391 fn drop(&mut self) {
392 #[cfg(feature = "check")]
393 {
394 let cnt = self.cnt.load(std::sync::atomic::Ordering::Relaxed);
395 if cnt != 0 {
396 // Holder may be dropped while some threads are using Borrowed.
397 // It's definitely unintended behavior.
398 if std::thread::panicking() {
399 std::process::abort();
400 } else {
401 panic!("Holder was dropped while someone is still using Borrowed");
402 }
403 }
404 }
405 }
406}
407
408/// A type generated by [`Holder`] that wraps a value in it shallowly.
409///
410/// This struct implements [`Deref`] and [`DerefMut`] for the inner value so
411/// that clients can use this struct like the inner value.
412///
413/// If `check` feature is enabled, this struct tracks borrow status at runtime,
414/// and will warn you if borrow rule was violated.
415#[derive(Debug)]
416pub struct Borrowed<B> {
417 value: B,
418 #[cfg(feature = "check")]
419 exclusive: bool,
420 #[cfg(feature = "check")]
421 cnt: std::sync::Arc<std::sync::atomic::AtomicI32>,
422}
423
424impl<B> Borrowed<B> {
425 const fn new(
426 value: B,
427 #[cfg(feature = "check")] exclusive: bool,
428 #[cfg(feature = "check")] cnt: std::sync::Arc<std::sync::atomic::AtomicI32>,
429 ) -> Self {
430 Self {
431 value,
432 #[cfg(feature = "check")]
433 exclusive,
434 #[cfg(feature = "check")]
435 cnt,
436 }
437 }
438
439 /// Converts inner value through the given function while maintaining borrow
440 /// state.
441 ///
442 /// # Examples
443 ///
444 /// ```
445 /// use my_ecs::ds::Holder;
446 ///
447 /// let holder = unsafe { Holder::new(0, |v| v, |v| v) };
448 /// let value = holder.borrow().unwrap();
449 /// let value = value.map(|v| v.to_string());
450 /// ```
451 pub fn map<T>(mut self, f: impl FnOnce(B) -> T) -> Borrowed<T> {
452 // Safety: self is not used again due to forget.
453 let res = unsafe { self.map_copy(f) };
454 mem::forget(self);
455 res
456 }
457
458 /// Turns inner value into another type, then returns converted value
459 /// wrapped in [`Borrowed`] while keeping borrow status.
460 ///
461 /// The operation looks like `move` with type-conversion. But `self` will
462 /// leave as it was, so caller must not use it any longer. That means caller
463 /// must not call even drop function on it. Consider using
464 /// [`forget`](mem::forget) or something like that to `self` after calling
465 /// this method.
466 ///
467 /// # Safety
468 ///
469 /// Undefined behavior if `self` is used again.
470 unsafe fn map_copy<T>(&mut self, f: impl FnOnce(B) -> T) -> Borrowed<T> {
471 let value: B = unsafe { ptr::read(&self.value as *const B) };
472
473 #[cfg(feature = "check")]
474 {
475 let cnt = unsafe { ptr::read(&self.cnt as *const _) };
476 Borrowed::new(f(value), self.exclusive, cnt)
477 }
478
479 #[cfg(not(feature = "check"))]
480 Borrowed::new(f(value))
481 }
482}
483
484impl<B> Deref for Borrowed<B> {
485 type Target = B;
486
487 fn deref(&self) -> &Self::Target {
488 &self.value
489 }
490}
491
492impl<B> DerefMut for Borrowed<B> {
493 fn deref_mut(&mut self) -> &mut Self::Target {
494 &mut self.value
495 }
496}
497
498impl<B> Drop for Borrowed<B> {
499 fn drop(&mut self) {
500 #[cfg(feature = "check")]
501 {
502 use std::sync::atomic::Ordering;
503
504 if self.exclusive {
505 self.cnt.fetch_add(1, Ordering::Relaxed);
506 } else {
507 self.cnt.fetch_sub(1, Ordering::Relaxed);
508 }
509 }
510 }
511}
512
513/// Result type for [`Borrowed`] with [`BorrowError`] for error propagation.
514pub type BorrowResult<B> = Result<Borrowed<B>, BorrowError>;
515
516/// An error type associated with borrow.
517///
518/// This error type will be commonly seen with [`Holder`], which can borrow
519/// its inner value to you.
520#[derive(Debug)]
521#[non_exhaustive]
522pub enum BorrowError {
523 /// Exclusive borrowing is only allowed when no one has borrowed it.
524 ExclusiveFailed,
525
526 /// For detecting anomaly, there exist the limit how many you can immutably
527 /// borrow.
528 TooManyBorrow,
529
530 /// Borrow failed because of index out of bounds.
531 OutOfBound,
532
533 /// Borrow failed because of not found key.
534 NotFound,
535}