Compare commits
No commits in common. "b12bcfc92ac53d44cac7c860830b06e7dedfbe5c" and "3d8b58202d031d5995d6f323c146be417e996ae4" have entirely different histories.
b12bcfc92a
...
3d8b58202d
|
@ -13,10 +13,9 @@ pub fn derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||||
|
|
||||||
let name = &input.ident;
|
let name = &input.ident;
|
||||||
let mod_name = Ident::new(&get_mod_name(&input), Span::call_site());
|
let mod_name = Ident::new(&get_mod_name(&input), Span::call_site());
|
||||||
let container_name = Ident::new(&get_container_name(&input), Span::call_site());
|
|
||||||
|
|
||||||
let expanded = match input.data {
|
let expanded = match input.data {
|
||||||
syn::Data::Struct(s) => expand_struct(s, name, &mod_name, &container_name),
|
syn::Data::Struct(s) => expand_struct(s, name, &mod_name),
|
||||||
syn::Data::Enum(_) => todo!("not yet implemented for prisms"),
|
syn::Data::Enum(_) => todo!("not yet implemented for prisms"),
|
||||||
syn::Data::Union(_) => panic!("this macro does not work on unions"),
|
syn::Data::Union(_) => panic!("this macro does not work on unions"),
|
||||||
};
|
};
|
||||||
|
@ -41,28 +40,7 @@ fn get_mod_name(input: &DeriveInput) -> String {
|
||||||
input.ident.to_string().to_lowercase()
|
input.ident.to_string().to_lowercase()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_container_name(input: &DeriveInput) -> String {
|
fn expand_struct(data: DataStruct, name: &Ident, mod_name: &Ident) -> TokenStream {
|
||||||
for i in &input.attrs {
|
|
||||||
if let Ok(Meta::NameValue(meta)) = i.parse_meta() {
|
|
||||||
if let Some(ident) = meta.path.get_ident() {
|
|
||||||
if ident == "container_name" {
|
|
||||||
if let Lit::Str(a) = meta.lit {
|
|
||||||
return a.value();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
format!("{}LensContainer", input.ident.to_string())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn expand_struct(
|
|
||||||
data: DataStruct,
|
|
||||||
name: &Ident,
|
|
||||||
mod_name: &Ident,
|
|
||||||
container_name: &Ident,
|
|
||||||
) -> TokenStream {
|
|
||||||
let fields = match &data.fields {
|
let fields = match &data.fields {
|
||||||
syn::Fields::Named(n) => n.named.iter(),
|
syn::Fields::Named(n) => n.named.iter(),
|
||||||
syn::Fields::Unnamed(_) => todo!(),
|
syn::Fields::Unnamed(_) => todo!(),
|
||||||
|
@ -109,8 +87,8 @@ fn expand_struct(
|
||||||
.collect::<TokenStream>();
|
.collect::<TokenStream>();
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
impl bad_optics::has_lens::HasLensOf<#ty> for #name {
|
impl Lenses<#ty> {
|
||||||
fn get() ->
|
pub fn get() ->
|
||||||
Vec<
|
Vec<
|
||||||
bad_optics::lenses::Lens<
|
bad_optics::lenses::Lens<
|
||||||
bad_optics::lenses::lens_with_ref::LensWithRef<
|
bad_optics::lenses::lens_with_ref::LensWithRef<
|
||||||
|
@ -135,19 +113,12 @@ fn expand_struct(
|
||||||
.collect::<TokenStream>();
|
.collect::<TokenStream>();
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
mod #mod_name {
|
pub mod #mod_name {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
pub struct #container_name;
|
|
||||||
|
|
||||||
impl HasLens for #name {
|
|
||||||
type Lenses = #container_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl #container_name {
|
|
||||||
#lens_funcs
|
#lens_funcs
|
||||||
}
|
|
||||||
|
|
||||||
|
pub struct Lenses<T>(std::marker::PhantomData<T>);
|
||||||
#group_impls
|
#group_impls
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
use bad_optics::prelude::*;
|
use bad_optics::prelude::Optics;
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
extern crate bad_optics;
|
|
||||||
|
|
||||||
// the Optics derive macro will implement lenses for every public field in the struct
|
// the Optics derive macro will implement lenses for every public field in the struct
|
||||||
// it makes a module named whatever the struct is called, but in lower case
|
// it makes a module named whatever the struct is called, but in lower case
|
||||||
|
@ -29,24 +26,20 @@ fn main() {
|
||||||
//
|
//
|
||||||
// these lenses work for `MyStruct` with `view` and `over`,
|
// these lenses work for `MyStruct` with `view` and `over`,
|
||||||
// and for `&MyStruct` with `view`
|
// and for `&MyStruct` with `view`
|
||||||
let field1 = <MyStruct as HasLens>::Lenses::field1();
|
let field1 = mystruct::field1();
|
||||||
// short macro for convenience, expands to the line above
|
let field2 = mystruct::field2();
|
||||||
let field2 = lens!(MyStruct::field2);
|
|
||||||
|
|
||||||
// the lenses work normally as any other lens :)
|
// the lenses work normally as any other lens :)
|
||||||
assert_eq!(field1(&o), "first field");
|
assert_eq!(field1(&o), "first field");
|
||||||
assert_eq!(field2(&o), "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 as HasLensOf<String>>::get();
|
let string_lenses = mystruct::Lenses::<String>::get();
|
||||||
assert_eq!(string_lenses.len(), 2);
|
assert_eq!(string_lenses.len(), 2);
|
||||||
|
|
||||||
// since _field4 is private, there's no lens for it
|
// since _field4 is private, there's no lens for it
|
||||||
let u8_lenses = <MyStruct as HasLensOf<u8>>::get();
|
let vec_string_lenses = mystruct::Lenses::<u8>::get();
|
||||||
assert_eq!(u8_lenses.len(), 1);
|
assert_eq!(vec_string_lenses.len(), 1);
|
||||||
|
|
||||||
// short macro for convenience, expands to the line above
|
|
||||||
let _u8_lenses = lenses!(MyStruct::u8);
|
|
||||||
|
|
||||||
let mut o = o;
|
let mut o = o;
|
||||||
for lens in string_lenses {
|
for lens in string_lenses {
|
||||||
|
|
|
@ -144,7 +144,8 @@ where
|
||||||
fn traverse(&self, thing: T) -> Vec<Self::Field> {
|
fn traverse(&self, thing: T) -> Vec<Self::Field> {
|
||||||
let a = A::traverse(&self.0 .0, thing);
|
let a = A::traverse(&self.0 .0, thing);
|
||||||
a.into_iter()
|
a.into_iter()
|
||||||
.flat_map(|v| B::traverse(&self.1 .0, v))
|
.map(|v| B::traverse(&self.1 .0, v))
|
||||||
|
.flatten()
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
30
src/lib.rs
30
src/lib.rs
|
@ -1,5 +1,4 @@
|
||||||
#![feature(unboxed_closures, fn_traits, const_trait_impl)]
|
#![feature(unboxed_closures, fn_traits, const_trait_impl)]
|
||||||
#![allow(clippy::type_complexity)]
|
|
||||||
|
|
||||||
pub mod combinations;
|
pub mod combinations;
|
||||||
mod fns;
|
mod fns;
|
||||||
|
@ -15,33 +14,4 @@ pub mod prelude {
|
||||||
pub use crate::lenses::*;
|
pub use crate::lenses::*;
|
||||||
pub use crate::prisms::*;
|
pub use crate::prisms::*;
|
||||||
pub use crate::traversals::*;
|
pub use crate::traversals::*;
|
||||||
|
|
||||||
pub use crate::has_lens::*;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub mod has_lens {
|
|
||||||
use crate::prelude::{lens::FuncLens, lens_with_ref::LensWithRef, to::ToRefInner};
|
|
||||||
|
|
||||||
use super::prelude::*;
|
|
||||||
|
|
||||||
pub trait HasLens {
|
|
||||||
type Lenses;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait HasLensOf<T>: Sized {
|
|
||||||
fn get() -> Vec<Lens<LensWithRef<Lens<FuncLens<Self, T>>, Lens<ToRefInner<Self, T>>, Self>>>;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! lens {
|
|
||||||
($name:ident :: $func:ident) => {
|
|
||||||
<$name as HasLens>::Lenses::$func()
|
|
||||||
};
|
|
||||||
}
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! lenses {
|
|
||||||
($name:ident :: $ty:ident) => {
|
|
||||||
<$name as HasLensOf<$ty>>::get()
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,11 @@ pub trait PrismPreview<T> {
|
||||||
F: FnOnce(Self::Field) -> Self::Field,
|
F: FnOnce(Self::Field) -> Self::Field,
|
||||||
T: Clone,
|
T: Clone,
|
||||||
{
|
{
|
||||||
Self::preview(self, thing.clone()).map_or(thing, |a| Self::review(self, f(a)))
|
if let Some(a) = Self::preview(&self, thing.clone()) {
|
||||||
|
Self::review(&self, f(a))
|
||||||
|
} else {
|
||||||
|
thing
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set(&self, thing: T, v: Self::Field) -> T
|
fn set(&self, thing: T, v: Self::Field) -> T
|
||||||
|
@ -29,7 +33,7 @@ pub trait PrismPreview<T> {
|
||||||
T: Clone,
|
T: Clone,
|
||||||
Self::Field: Clone,
|
Self::Field: Clone,
|
||||||
{
|
{
|
||||||
Self::over(self, thing, move |_| v)
|
Self::over(self, thing, move |_| v.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue