pub use grist_lens_macro::lens;
use std::{cell::Cell, marker::PhantomData};
use crate::{Field, Lens, LensMut, LensRef, Struct, Usage};
pub struct Optic<'a, T: Struct> {
value: *mut T,
usages: Box<[Cell<Usage>]>,
phantom: PhantomData<&'a mut T>,
}
impl<'a, T: Struct> Optic<'a, T> {
pub fn new(value: &'a mut T) -> Self {
Self {
value,
usages: vec![Cell::new(Usage::None); T::FIELD_COUNT].into(),
phantom: PhantomData,
}
}
pub fn usages(&self) -> Vec<Usage> {
unsafe { std::slice::from_raw_parts(self.usages.as_ptr().cast(), T::FIELD_COUNT) }.to_vec()
}
fn usage<O: Field>(&self) -> &Cell<Usage> {
&self.usages[O::INDEX]
}
}
impl<'a, T> Lens<'a, T> for Optic<'a, T>
where
T: Struct + 'a,
{
fn get<'b, O: Field<Base = T>>(&'b self) -> LensRef<'b, O> {
self.usage::<O>().update(|x| match x {
Usage::Mut => panic!("gulp"),
Usage::Ref(x @ 1..) => Usage::Ref(x + 1),
_ => Usage::Ref(1),
});
LensRef {
usage: self.usage::<O>(),
field: unsafe { &*(self.value.cast::<u8>().add(O::OFFSET).cast()) },
phantom: PhantomData,
}
}
fn get_mut<'b, O: Field<Base = T>>(&'b self) -> LensMut<'b, O> {
self.usage::<O>().update(|x| match x {
Usage::None => Usage::Mut,
_ => panic!("gulp"),
});
LensMut {
usage: self.usage::<O>(),
field: unsafe { &mut *(self.value.cast::<u8>().add(O::OFFSET).cast()) },
phantom: PhantomData,
}
}
}