grist_lens 1.2.4

Unsafe Nightly Ergonomic Lens API
Documentation
use std::{
    cell::Cell,
    marker::PhantomData,
    ops::{Deref, DerefMut},
};

use crate::{Field, Usage};

/// Defines methods for getting `LensRef` and `LensMut`.
pub trait Lens<'a, T> {
    /// Get a `LensRef`
    fn get<'b, O: Field<Base = T>>(&'b self) -> LensRef<'b, O>;

    /// Get a `LensMut`
    fn get_mut<'b, O: Field<Base = T>>(&'b self) -> LensMut<'b, O>;
}

/// A wrapper type for a field borrow. See [`Optic::get`].
pub struct LensRef<'a, O: Field> {
    pub(crate) usage: &'a Cell<Usage>,
    pub(crate) field: &'a O::Type,

    pub(crate) phantom: PhantomData<&'a mut O::Base>,
}

impl<'a, O: Field> Deref for LensRef<'a, O> {
    type Target = O::Type;

    fn deref(&self) -> &Self::Target {
        self.field
    }
}

impl<'a, O: Field> Drop for LensRef<'a, O> {
    fn drop(&mut self) {
        self.usage.update(|x| match x {
            Usage::Ref(1) => Usage::None,
            Usage::Ref(x) => Usage::Ref(x - 1),
            _ => Usage::None,
        });
    }
}

/// A wrapper type for a field mutable borrow. See [`Optic::get_mut`].
pub struct LensMut<'a, O: Field> {
    pub(crate) usage: &'a Cell<Usage>,
    pub(crate) field: &'a mut O::Type,

    pub(crate) phantom: PhantomData<&'a O::Base>,
}

impl<'a, O: Field> Deref for LensMut<'a, O> {
    type Target = O::Type;

    fn deref(&self) -> &Self::Target {
        self.field
    }
}

impl<'a, O: Field> DerefMut for LensMut<'a, O> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        self.field
    }
}

impl<'a, O: Field> Drop for LensMut<'a, O> {
    fn drop(&mut self) {
        self.usage.set(Usage::None)
    }
}