#![doc = include_str!("../README.md")]
#![no_std]
extern crate alloc;
extern crate self as lenz;
use alloc::vec::Vec;
use core::any::TypeId;
use core::marker::PhantomData;
pub use lenz_macros::Lenz;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct FieldId(TypeId);
impl FieldId {
pub(crate) fn of<P: FieldPath + ?Sized>() -> Self {
Self(TypeId::of::<P>())
}
}
pub trait FieldPath: 'static {
type Source: 'static;
type Target: 'static;
fn get(source: &Self::Source) -> Option<&Self::Target>;
fn get_mut(
source: &mut Self::Source,
) -> Option<&mut Self::Target>;
fn erase() -> Accessor<Self::Source, Self::Target> {
Accessor {
get: Self::get,
get_mut: Self::get_mut,
}
}
fn id() -> FieldId {
FieldId::of::<Self>()
}
fn hops(out: &mut Vec<FieldId>) {
out.push(Self::id());
}
}
pub struct Identity<S>(PhantomData<fn() -> S>);
impl<S: 'static> FieldPath for Identity<S> {
type Source = S;
type Target = S;
#[inline(always)]
fn get(source: &S) -> Option<&S> {
Some(source)
}
#[inline(always)]
fn get_mut(source: &mut S) -> Option<&mut S> {
Some(source)
}
fn hops(_out: &mut Vec<FieldId>) {}
}
pub struct Chain<A, B>(PhantomData<fn() -> (A, B)>);
impl<A, B> FieldPath for Chain<A, B>
where
A: FieldPath,
B: FieldPath<Source = A::Target>,
{
type Source = A::Source;
type Target = B::Target;
#[inline(always)]
fn get(source: &A::Source) -> Option<&B::Target> {
A::get(source).and_then(B::get)
}
#[inline(always)]
fn get_mut(source: &mut A::Source) -> Option<&mut B::Target> {
A::get_mut(source).and_then(B::get_mut)
}
fn hops(out: &mut Vec<FieldId>) {
A::hops(out);
B::hops(out);
}
}
pub trait Tagged: FieldPath {
type Tag;
}
impl<A, B> Tagged for Chain<A, B>
where
A: FieldPath,
B: FieldPath<Source = A::Target> + Tagged,
{
type Tag = B::Tag;
}
pub struct Cursor<P>(PhantomData<fn() -> P>);
impl<P> Cursor<P> {
pub const fn new() -> Self {
Self(PhantomData)
}
}
impl<P: FieldPath> Cursor<P> {
pub fn accessor(self) -> Accessor<P::Source, P::Target> {
P::erase()
}
pub fn key(self) -> FieldId {
P::id()
}
pub fn hops(self) -> Vec<FieldId> {
let mut out = Vec::new();
P::hops(&mut out);
out
}
}
impl<P> Default for Cursor<P> {
fn default() -> Self {
Self::new()
}
}
impl<P> Clone for Cursor<P> {
fn clone(&self) -> Self {
*self
}
}
impl<P> Copy for Cursor<P> {}
#[derive(Debug)]
pub struct Accessor<S, T> {
get: fn(&S) -> Option<&T>,
get_mut: fn(&mut S) -> Option<&mut T>,
}
impl<S, T> Accessor<S, T> {
pub fn get<'s>(&self, source: &'s S) -> Option<&'s T> {
(self.get)(source)
}
pub fn get_mut<'s>(
&self,
source: &'s mut S,
) -> Option<&'s mut T> {
(self.get_mut)(source)
}
}
impl<S, T> Clone for Accessor<S, T> {
fn clone(&self) -> Self {
*self
}
}
impl<S, T> Copy for Accessor<S, T> {}