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}