use std::{
cell::Cell,
marker::PhantomData,
ops::{Deref, DerefMut},
};
use crate::{Field, Usage};
pub trait Lens<'a, T> {
fn get<'b, O: Field<Base = T>>(&'b self) -> LensRef<'b, O>;
fn get_mut<'b, O: Field<Base = T>>(&'b self) -> LensMut<'b, O>;
}
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,
});
}
}
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)
}
}