implement with_ref stuff, so you can use field lenses with a struct and a ref
parent
4a1f398fe3
commit
cc9c90202b
|
@ -55,9 +55,19 @@ fn expand_struct(data: DataStruct, name: &Ident, mod_name: &Ident) -> TokenStrea
|
||||||
let ty = &field.ty;
|
let ty = &field.ty;
|
||||||
quote! {
|
quote! {
|
||||||
pub fn #fname() ->
|
pub fn #fname() ->
|
||||||
bad_optics::lenses::Lens<bad_optics::lenses::lens::FuncLens<#name, #ty>>
|
bad_optics::lenses::Lens<
|
||||||
|
bad_optics::lenses::lens_with_ref::LensWithRef<
|
||||||
|
bad_optics::lenses::Lens<
|
||||||
|
bad_optics::lenses::lens::FuncLens<#name, #ty>
|
||||||
|
>,
|
||||||
|
bad_optics::lenses::Lens<
|
||||||
|
bad_optics::lenses::to::ToRefInner<#name, #ty>
|
||||||
|
>,
|
||||||
|
#name
|
||||||
|
>
|
||||||
|
>
|
||||||
{
|
{
|
||||||
bad_optics::field_lens!(#name, #fname)
|
bad_optics::field_lens_with_ref!(#name, #fname)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -71,7 +81,7 @@ fn expand_struct(data: DataStruct, name: &Ident, mod_name: &Ident) -> TokenStrea
|
||||||
.map(|field| {
|
.map(|field| {
|
||||||
let fname = field.ident.unwrap();
|
let fname = field.ident.unwrap();
|
||||||
quote! {
|
quote! {
|
||||||
bad_optics::field_lens!(#name, #fname),
|
bad_optics::field_lens_with_ref!(#name, #fname),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect::<TokenStream>();
|
.collect::<TokenStream>();
|
||||||
|
@ -79,7 +89,19 @@ fn expand_struct(data: DataStruct, name: &Ident, mod_name: &Ident) -> TokenStrea
|
||||||
quote! {
|
quote! {
|
||||||
impl Lenses<#ty> {
|
impl Lenses<#ty> {
|
||||||
pub fn get() ->
|
pub fn get() ->
|
||||||
Vec<bad_optics::lenses::Lens<bad_optics::lenses::lens::FuncLens<#name, #ty>>>
|
Vec<
|
||||||
|
bad_optics::lenses::Lens<
|
||||||
|
bad_optics::lenses::lens_with_ref::LensWithRef<
|
||||||
|
bad_optics::lenses::Lens<
|
||||||
|
bad_optics::lenses::lens::FuncLens<#name, #ty>
|
||||||
|
>,
|
||||||
|
bad_optics::lenses::Lens<
|
||||||
|
bad_optics::lenses::to::ToRefInner<#name, #ty>
|
||||||
|
>,
|
||||||
|
#name
|
||||||
|
>
|
||||||
|
>
|
||||||
|
>
|
||||||
{
|
{
|
||||||
vec![
|
vec![
|
||||||
#lenses
|
#lenses
|
||||||
|
|
|
@ -23,12 +23,15 @@ fn main() {
|
||||||
|
|
||||||
// we can manually get lenses for each field
|
// we can manually get lenses for each field
|
||||||
// note that it's a function that returns a lens
|
// note that it's a function that returns a lens
|
||||||
|
//
|
||||||
|
// these lenses work for `MyStruct` with `view` and `over`,
|
||||||
|
// and for `&MyStruct` with `view`
|
||||||
let field1 = mystruct::field1();
|
let field1 = mystruct::field1();
|
||||||
let field2 = mystruct::field2();
|
let field2 = mystruct::field2();
|
||||||
|
|
||||||
// the lenses work normally as any other lens :)
|
// the lenses work normally as any other lens :)
|
||||||
assert_eq!(field1(o.clone()), "first field");
|
assert_eq!(field1(&o), "first field");
|
||||||
assert_eq!(field2(o.clone()), "second field");
|
assert_eq!(field2(&o), "second field");
|
||||||
|
|
||||||
// we can get a vec with all the lenses that match a type
|
// we can get a vec with all the lenses that match a type
|
||||||
let string_lenses = mystruct::Lenses::<String>::get();
|
let string_lenses = mystruct::Lenses::<String>::get();
|
||||||
|
|
|
@ -10,3 +10,17 @@ macro_rules! field_lens {
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! field_lens_with_ref {
|
||||||
|
($type:ident, $field:ident) => {
|
||||||
|
$crate::lenses::lens_with_ref(
|
||||||
|
|v: $type| v.$field,
|
||||||
|
|mut u: $type, v| {
|
||||||
|
u.$field = v;
|
||||||
|
u
|
||||||
|
},
|
||||||
|
|v: &$type| v.$field.clone(),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ impl<T: Clone, U> LensOver<T> for FuncLens<T, U> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Makes a lens that implements `LensView<T>` and `LensOver<T>` with the provided functions
|
/// Makes a lens that implements `LensView<T>` and `LensOver<T>` with the provided functions
|
||||||
pub fn lens_from_boxed<T, U>(
|
pub fn lens_from_arc<T, U>(
|
||||||
getter: Arc<Getter<T, U>>,
|
getter: Arc<Getter<T, U>>,
|
||||||
setter: Arc<Setter<T, U>>,
|
setter: Arc<Setter<T, U>>,
|
||||||
) -> Lens<FuncLens<T, U>> {
|
) -> Lens<FuncLens<T, U>> {
|
||||||
|
|
|
@ -0,0 +1,83 @@
|
||||||
|
use crate::lenses::{
|
||||||
|
lens,
|
||||||
|
lens::FuncLens,
|
||||||
|
lens_from_arc,
|
||||||
|
to::{to_ref, to_ref_from_arc, ToRefInner},
|
||||||
|
Lens, LensOver, LensView,
|
||||||
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
/// Lens that works on both a T and &T
|
||||||
|
pub struct LensWithRef<A, B, T>(A, B, std::marker::PhantomData<T>);
|
||||||
|
|
||||||
|
impl<'a, A, B, T> LensView<T> for LensWithRef<Lens<A>, B, T>
|
||||||
|
where
|
||||||
|
T: Clone,
|
||||||
|
A: LensView<T>,
|
||||||
|
{
|
||||||
|
type Field = A::Field;
|
||||||
|
|
||||||
|
fn view(&self, thing: T) -> Self::Field {
|
||||||
|
A::view(&self.0 .0, thing)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'a, A, B, T> LensOver<T> for LensWithRef<Lens<A>, B, T>
|
||||||
|
where
|
||||||
|
T: Clone,
|
||||||
|
A: LensOver<T>,
|
||||||
|
{
|
||||||
|
fn over<F>(&self, thing: T, f: F) -> T
|
||||||
|
where
|
||||||
|
F: FnOnce(Self::Field) -> Self::Field,
|
||||||
|
{
|
||||||
|
A::over(&self.0 .0, thing, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, A, B, T> LensView<&'a T> for LensWithRef<A, Lens<B>, T>
|
||||||
|
where
|
||||||
|
T: Clone,
|
||||||
|
A: LensView<T>,
|
||||||
|
B: LensView<&'a T>,
|
||||||
|
{
|
||||||
|
type Field = B::Field;
|
||||||
|
|
||||||
|
fn view(&self, thing: &'a T) -> Self::Field {
|
||||||
|
B::view(&self.1 .0, thing)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Getter<T, U> = dyn Fn(T) -> U;
|
||||||
|
type Setter<T, U> = dyn Fn(T, U) -> T;
|
||||||
|
|
||||||
|
/// Makes a lens that implements `LensView<T>` and `LensOver<T>` with the provided functions
|
||||||
|
pub fn lens_with_ref_from_arc<T, U>(
|
||||||
|
getter: Arc<Getter<T, U>>,
|
||||||
|
setter: Arc<Setter<T, U>>,
|
||||||
|
getter_ref: Arc<dyn Fn(&T) -> U>,
|
||||||
|
) -> Lens<LensWithRef<Lens<FuncLens<T, U>>, Lens<ToRefInner<T, U>>, T>>
|
||||||
|
where
|
||||||
|
T: Clone,
|
||||||
|
{
|
||||||
|
Lens(LensWithRef(
|
||||||
|
lens_from_arc(getter, setter),
|
||||||
|
to_ref_from_arc(getter_ref),
|
||||||
|
Default::default(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
/// Makes a lens that implements `LensView<T>` and `LensOver<T>` with the provided functions
|
||||||
|
pub fn lens_with_ref<T, U>(
|
||||||
|
getter: impl Fn(T) -> U + 'static,
|
||||||
|
setter: impl Fn(T, U) -> T + 'static,
|
||||||
|
getter_ref: impl Fn(&T) -> U + 'static,
|
||||||
|
) -> Lens<LensWithRef<Lens<FuncLens<T, U>>, Lens<ToRefInner<T, U>>, T>>
|
||||||
|
where
|
||||||
|
T: Clone,
|
||||||
|
{
|
||||||
|
Lens(LensWithRef(
|
||||||
|
lens(getter, setter),
|
||||||
|
to_ref(getter_ref),
|
||||||
|
Default::default(),
|
||||||
|
))
|
||||||
|
}
|
|
@ -15,9 +15,11 @@ pub mod fifth;
|
||||||
pub use fifth::_4;
|
pub use fifth::_4;
|
||||||
|
|
||||||
pub mod to;
|
pub mod to;
|
||||||
pub use to::{to, to_from_boxed};
|
pub use to::{to, to_from_arc};
|
||||||
pub mod lens;
|
pub mod lens;
|
||||||
pub use lens::{lens, lens_from_boxed};
|
pub use lens::{lens, lens_from_arc};
|
||||||
|
pub mod lens_with_ref;
|
||||||
|
pub use lens_with_ref::{lens_with_ref, lens_with_ref_from_arc};
|
||||||
|
|
||||||
/// Wrapper type
|
/// Wrapper type
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
|
|
|
@ -16,7 +16,7 @@ impl<T, U> LensView<T> for ToInner<T, U> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Makes a lens that implements `LensView<T>` with the provided function
|
/// Makes a lens that implements `LensView<T>` with the provided function
|
||||||
pub fn to_from_boxed<T, U>(f: Arc<dyn Fn(T) -> U>) -> Lens<ToInner<T, U>> {
|
pub fn to_from_arc<T, U>(f: Arc<dyn Fn(T) -> U>) -> Lens<ToInner<T, U>> {
|
||||||
Lens(ToInner(f))
|
Lens(ToInner(f))
|
||||||
}
|
}
|
||||||
/// Makes a lens that implements `LensView<T>` with the provided function
|
/// Makes a lens that implements `LensView<T>` with the provided function
|
||||||
|
@ -30,3 +30,23 @@ impl<T, U> Lens<ToInner<T, U>> {
|
||||||
Lens(FuncLens((self.0).0, Arc::new(setter)))
|
Lens(FuncLens((self.0).0, Arc::new(setter)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct ToRefInner<T, U>(Arc<dyn Fn(&T) -> U>);
|
||||||
|
|
||||||
|
impl<T, U> LensView<&T> for ToRefInner<T, U> {
|
||||||
|
type Field = U;
|
||||||
|
|
||||||
|
fn view(&self, thing: &T) -> Self::Field {
|
||||||
|
(self.0)(thing)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Makes a lens that implements `LensView<T>` with the provided function
|
||||||
|
pub fn to_ref_from_arc<T, U>(f: Arc<dyn Fn(&T) -> U>) -> Lens<ToRefInner<T, U>> {
|
||||||
|
Lens(ToRefInner(f))
|
||||||
|
}
|
||||||
|
/// Makes a lens that implements `LensView<T>` with the provided function
|
||||||
|
pub fn to_ref<T, U>(f: impl Fn(&T) -> U + 'static) -> Lens<ToRefInner<T, U>> {
|
||||||
|
Lens(ToRefInner(Arc::new(f)))
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue