      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

    use crate::sync::batch_semaphore::Semaphore;
    use std::fmt;
    use std::marker;
    use std::mem;
    use std::ops;

    /// RAII structure used to release the shared read access of a lock when
    /// dropped.
    ///
    /// This structure is created by the [`read`] method on
    /// [`RwLock`].
    ///
    /// [`read`]: method@crate::sync::RwLock::read
    /// [`RwLock`]: struct@crate::sync::RwLock
    pub struct RwLockReadGuard<'a, T: ?Sized> {
        pub(super) s: &'a Semaphore,
        pub(super) data: *const T,
        pub(super) marker: marker::PhantomData<&'a T>,
    }

    impl<'a, T> RwLockReadGuard<'a, T> {
        /// Make a new `RwLockReadGuard` for a component of the locked data.
        ///
        /// This operation cannot fail as the `RwLockReadGuard` passed in already
        /// locked the data.
        ///
        /// This is an associated function that needs to be
        /// used as `RwLockReadGuard::map(...)`. A method would interfere with
        /// methods of the same name on the contents of the locked data.
        ///
        /// This is an asynchronous version of [`RwLockReadGuard::map`] from the
        /// [`parking_lot` crate].
        ///
        /// [`RwLockReadGuard::map`]: https://docs.rs/lock_api/latest/lock_api/struct.RwLockReadGuard.html#method.map
        /// [`parking_lot` crate]: https://crates.io/crates/parking_lot
        ///
        /// # Examples
        ///
        /// ```
        /// use tokio::sync::{RwLock, RwLockReadGuard};
        ///
        /// #[derive(Debug, Clone, Copy, PartialEq, Eq)]
        /// struct Foo(u32);
        ///
        /// # #[tokio::main]
        /// # async fn main() {
        /// let lock = RwLock::new(Foo(1));
        ///
        /// let guard = lock.read().await;
        /// let guard = RwLockReadGuard::map(guard, |f| &f.0);
        ///
        /// assert_eq!(1, *guard);
        /// # }
        /// ```
        #[inline]
        pub fn map<F, U: ?Sized>(this: Self, f: F) -> RwLockReadGuard<'a, U>
        where
            F: FnOnce(&T) -> &U,
        {
            let data = f(&*this) as *const U;
            let s = this.s;
            // NB: Forget to avoid drop impl from being called.
            mem::forget(this);
            RwLockReadGuard {
                s,
                data,
                marker: marker::PhantomData,
            }
        }

        /// Attempts to make a new [`RwLockReadGuard`] for a component of the
        /// locked data. The original guard is returned if the closure returns
        /// `None`.
        ///
        /// This operation cannot fail as the `RwLockReadGuard` passed in already
        /// locked the data.
        ///
        /// This is an associated function that needs to be used as
        /// `RwLockReadGuard::try_map(..)`. A method would interfere with methods of the
        /// same name on the contents of the locked data.
        ///
        /// This is an asynchronous version of [`RwLockReadGuard::try_map`] from the
        /// [`parking_lot` crate].
        ///
        /// [`RwLockReadGuard::try_map`]: https://docs.rs/lock_api/latest/lock_api/struct.RwLockReadGuard.html#method.try_map
        /// [`parking_lot` crate]: https://crates.io/crates/parking_lot
        ///
        /// # Examples
        ///
        /// ```
        /// use tokio::sync::{RwLock, RwLockReadGuard};
        ///
        /// #[derive(Debug, Clone, Copy, PartialEq, Eq)]
        /// struct Foo(u32);
        ///
        /// # #[tokio::main]
        /// # async fn main() {
        /// let lock = RwLock::new(Foo(1));
        ///
        /// let guard = lock.read().await;
        /// let guard = RwLockReadGuard::try_map(guard, |f| Some(&f.0)).expect("should not fail");
        ///
        /// assert_eq!(1, *guard);
        /// # }
        /// ```
        #[inline]
        pub fn try_map<F, U: ?Sized>(this: Self, f: F) -> Result<RwLockReadGuard<'a, U>, Self>
        where
            F: FnOnce(&T) -> Option<&U>,
        {
            let data = match f(&*this) {
                Some(data) => data as *const U,
                None => return Err(this),
            };
            let s = this.s;
            // NB: Forget to avoid drop impl from being called.
            mem::forget(this);
            Ok(RwLockReadGuard {
                s,
                data,
                marker: marker::PhantomData,
            })
        }
    }

    impl<T: ?Sized> ops::Deref for RwLockReadGuard<'_, T> {
        type Target = T;

        fn deref(&self) -> &T {
            unsafe { &*self.data }
        }
    }

    impl<'a, T: ?Sized> fmt::Debug for RwLockReadGuard<'a, T>
    where
        T: fmt::Debug,
    {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            fmt::Debug::fmt(&**self, f)
        }
    }

    impl<'a, T: ?Sized> fmt::Display for RwLockReadGuard<'a, T>
    where
        T: fmt::Display,
    {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            fmt::Display::fmt(&**self, f)
        }
    }

    impl<'a, T: ?Sized> Drop for RwLockReadGuard<'a, T> {
        fn drop(&mut self) {
            self.s.release(1);
        }
    }