local_async_utils 0.2.13

Utilities for single-threaded async programming
Documentation
use super::{Shared, UnsafeShared};
use std::fmt;

pub struct ProjectedShared<T, F> {
    pub(super) inner: T,
    pub(super) proj_fn: F,
}

impl<From, To, Inner, Proj> Shared for ProjectedShared<Inner, Proj>
where
    Inner: Shared<Target = From>,
    Proj: Fn(&mut From) -> &mut To + Clone,
{
    type Target = To;

    #[inline(always)]
    fn with<R, F>(&mut self, f: F) -> R
    where
        F: FnOnce(&mut Self::Target) -> R,
    {
        let proj_fn = &self.proj_fn;
        self.inner.with(|from| f(proj_fn(from)))
    }
}

impl<T, F> Clone for ProjectedShared<T, F>
where
    T: Clone,
    F: Clone,
{
    fn clone(&self) -> Self {
        Self {
            inner: self.inner.clone(),
            proj_fn: self.proj_fn.clone(),
        }
    }
}

impl<From, To, Inner, Proj> UnsafeShared for ProjectedShared<Inner, Proj>
where
    Inner: UnsafeShared<Target = From>,
    Proj: Fn(*mut From) -> *mut To + Clone,
{
    type Target = To;

    #[inline(always)]
    fn with<R, F>(&mut self, f: F) -> R
    where
        F: FnOnce(*mut Self::Target) -> R,
    {
        let proj_fn = &self.proj_fn;
        self.inner.with(|from| f(proj_fn(from)))
    }
}

impl<T, F> fmt::Debug for ProjectedShared<T, F> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("ProjectedShared").finish_non_exhaustive()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::shared::LocalShared;

    #[test]
    fn test_projected_shared() {
        let mut shared = LocalShared::new((1, 2));
        let mut projected = shared.project(|data| &mut data.0);

        projected.with(|data| {
            *data += 10;
        });

        let result = shared.with(|data| data.0);
        assert_eq!(result, 11);
    }
}