Compare commits
No commits in common. "main" and "4a4751dcb2c0e5a55463e459a7c2a395bcb96a78" have entirely different histories.
main
...
4a4751dcb2
|
@ -1,3 +1,2 @@
|
|||
/target
|
||||
Cargo.lock
|
||||
.DS_Store
|
||||
|
|
|
@ -3,8 +3,6 @@ name = "bad-optics"
|
|||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[workspace]
|
||||
members = ["bad-optics-derive"]
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
bad-optics-derive = { path = "./bad-optics-derive" }
|
||||
|
|
60
README.md
60
README.md
|
@ -1,60 +0,0 @@
|
|||
# bad optics
|
||||
|
||||
ergonomic lenses in rust
|
||||
|
||||
`bad-optics` implements the haskell concept of lenses, prisms, and traversals in rust
|
||||
|
||||
it does *not* implement the operators, as it's not really a thing we can do in rust
|
||||
|
||||
you will need nightly for this library to work, as it uses a bunch of unstable features. they're technically not *critical*, but i think not having them reduces the ergonomics too much
|
||||
|
||||
does bringing lenses into rust actually make sense? probably not, but it was fun to implement so who can say
|
||||
|
||||
## example
|
||||
|
||||
```rust
|
||||
use bad_optics::{
|
||||
lenses::{over, set},
|
||||
prelude::*,
|
||||
};
|
||||
|
||||
fn main() {
|
||||
let a = ((1, 2), 3);
|
||||
|
||||
// use view to access inside the tuple
|
||||
let res = view(_0, a);
|
||||
assert_eq!(res, (1, 2));
|
||||
|
||||
let res = view(_1, a);
|
||||
assert_eq!(res, 3);
|
||||
|
||||
// you can combine lenses
|
||||
let lens = _0 + _1;
|
||||
|
||||
// use the view function to access
|
||||
let res = view(lens, a);
|
||||
assert_eq!(res, 2);
|
||||
|
||||
// you can also call the lens as a function
|
||||
let res = lens(a);
|
||||
assert_eq!(res, 2);
|
||||
|
||||
// call the over function to modify the value
|
||||
let a = over(lens, a, |v| v + 1);
|
||||
assert_eq!(a, ((1, 3), 3));
|
||||
|
||||
// call the set function to set the value
|
||||
let a = set(lens, a, 5);
|
||||
assert_eq!(a, ((1, 5), 3));
|
||||
|
||||
// you can also call the lens as a function to modify the value
|
||||
let res = lens(a, |v| v + 1);
|
||||
assert_eq!(res, ((1, 6), 3));
|
||||
}
|
||||
```
|
||||
|
||||
## how to use
|
||||
|
||||
bad-optics provides some of the lenses, prisms, and traversals defined in `lens`. i'm still trying to add more, so if there's one you need and it's missing from here, feel free to open a PR
|
||||
|
||||
if you don't know how lenses work, this is not really gonna be a tutorial, you should read [this](https://hackage.haskell.org/package/lens-tutorial-1.0.3/docs/Control-Lens-Tutorial.html) first instead. the general idea is that they are first-class getters and setters
|
|
@ -1,12 +0,0 @@
|
|||
[package]
|
||||
name = "bad-optics-derive"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
syn = {version = "1.0", features = ["extra-traits"]}
|
||||
quote = "1.0"
|
||||
proc-macro2 = "1.0"
|
|
@ -1,168 +0,0 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use quote::quote;
|
||||
use syn::{parse_macro_input, DataStruct, DeriveInput, Field, Ident, Lit, Meta, Type, Visibility};
|
||||
|
||||
// TODO add attributes to rename the lens/module/skip making lenses/idk
|
||||
|
||||
#[proc_macro_derive(Optics, attributes(mod_name))]
|
||||
pub fn derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
// Parse the input tokens into a syntax tree
|
||||
let input = parse_macro_input!(input as DeriveInput);
|
||||
|
||||
let name = &input.ident;
|
||||
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 {
|
||||
syn::Data::Struct(s) => expand_struct(s, name, &mod_name, &container_name),
|
||||
syn::Data::Enum(_) => todo!("not yet implemented for prisms"),
|
||||
syn::Data::Union(_) => panic!("this macro does not work on unions"),
|
||||
};
|
||||
|
||||
// Hand the output tokens back to the compiler
|
||||
proc_macro::TokenStream::from(expanded)
|
||||
}
|
||||
|
||||
fn get_mod_name(input: &DeriveInput) -> String {
|
||||
for i in &input.attrs {
|
||||
if let Ok(Meta::NameValue(meta)) = i.parse_meta() {
|
||||
if let Some(ident) = meta.path.get_ident() {
|
||||
if ident == "mod_name" {
|
||||
if let Lit::Str(a) = meta.lit {
|
||||
return a.value();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
input.ident.to_string().to_lowercase()
|
||||
}
|
||||
|
||||
fn get_container_name(input: &DeriveInput) -> String {
|
||||
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 {
|
||||
syn::Fields::Named(n) => n.named.iter(),
|
||||
syn::Fields::Unnamed(_) => todo!(),
|
||||
syn::Fields::Unit => todo!(),
|
||||
}
|
||||
.filter(|f| matches!(f.vis, Visibility::Public(_)));
|
||||
|
||||
let lens_funcs = fields
|
||||
.clone()
|
||||
.map(|field| {
|
||||
let fname = field.ident.as_ref().unwrap();
|
||||
let ty = &field.ty;
|
||||
quote! {
|
||||
pub fn #fname() ->
|
||||
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_with_ref!(#name, #fname)
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect::<TokenStream>();
|
||||
|
||||
let group_impls = group_by_type(fields)
|
||||
.into_iter()
|
||||
.map(|(ty, fields)| {
|
||||
let lenses = fields
|
||||
.into_iter()
|
||||
.map(|field| {
|
||||
let fname = field.ident.unwrap();
|
||||
quote! {
|
||||
bad_optics::field_lens_with_ref!(#name, #fname),
|
||||
}
|
||||
})
|
||||
.collect::<TokenStream>();
|
||||
|
||||
quote! {
|
||||
impl bad_optics::has_lens::HasLensOf<#ty> for #name {
|
||||
fn get() ->
|
||||
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![
|
||||
#lenses
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect::<TokenStream>();
|
||||
|
||||
quote! {
|
||||
mod #mod_name {
|
||||
use super::*;
|
||||
|
||||
pub struct #container_name;
|
||||
|
||||
impl HasLens for #name {
|
||||
type Lenses = #container_name;
|
||||
}
|
||||
|
||||
impl #container_name {
|
||||
#lens_funcs
|
||||
}
|
||||
|
||||
#group_impls
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn group_by_type<'a>(fields: impl Iterator<Item = &'a Field>) -> Vec<(Type, Vec<Field>)> {
|
||||
let mut map = HashMap::<Type, Vec<Field>>::new();
|
||||
|
||||
for field in fields {
|
||||
if let Some(f) = map.get_mut(&field.ty) {
|
||||
f.push(field.clone());
|
||||
} else {
|
||||
map.insert(field.ty.clone(), vec![field.clone()]);
|
||||
}
|
||||
}
|
||||
|
||||
map.into_iter().collect()
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
use bad_optics::prelude::*;
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
struct MyStruct {
|
||||
hey: (u8, (u8, [Option<i32>; 5])),
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// make a lens that accesses `hey` in `MyStruct`
|
||||
let hey = lens(
|
||||
|hello: MyStruct| hello.hey,
|
||||
|mut hello: MyStruct, v| {
|
||||
hello.hey = v;
|
||||
hello
|
||||
},
|
||||
);
|
||||
|
||||
// the thing we want to access
|
||||
let thing: (MyStruct, &'static str) = (
|
||||
MyStruct {
|
||||
hey: (1, (2, [None, Some(1), Some(2), None, Some(4)])),
|
||||
},
|
||||
"hello",
|
||||
);
|
||||
|
||||
let array_lens = _0 // access the first element in the tuple
|
||||
+ hey // access hey
|
||||
+ _1 // access the second element in the tuple
|
||||
+ _1; // access the second element in the tuple
|
||||
|
||||
assert_eq!(array_lens(thing.clone()).len(), 5);
|
||||
|
||||
let lens = array_lens
|
||||
+ each // access each element of the [Option<i32>; 5] array
|
||||
+ _Some; // access the ones that are Some;
|
||||
|
||||
assert_eq!(lens(thing.clone()), vec![1, 2, 4]);
|
||||
|
||||
assert_eq!(
|
||||
lens(thing, |v| v + 10),
|
||||
(
|
||||
MyStruct {
|
||||
hey: (1, (2, [None, Some(11), Some(12), None, Some(14)])),
|
||||
},
|
||||
"hello",
|
||||
)
|
||||
);
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
use bad_optics::prelude::*;
|
||||
|
||||
#[macro_use]
|
||||
extern crate bad_optics;
|
||||
|
||||
// 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
|
||||
// you can rename the generated module by adding `#[mod_name = "other_name"]` to the struct
|
||||
|
||||
#[derive(Optics, Clone, Debug)]
|
||||
pub struct MyStruct {
|
||||
pub field1: String,
|
||||
pub field2: String,
|
||||
|
||||
pub field3: u8,
|
||||
_field4: u8,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let o = MyStruct {
|
||||
field1: "first field".to_string(),
|
||||
field2: "second field".to_string(),
|
||||
field3: 12,
|
||||
_field4: 1,
|
||||
};
|
||||
|
||||
// we can manually get lenses for each field
|
||||
// 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 as HasLens>::Lenses::field1();
|
||||
// short macro for convenience, expands to the line above
|
||||
let field2 = lens!(MyStruct::field2);
|
||||
|
||||
// the lenses work normally as any other lens :)
|
||||
assert_eq!(field1(&o), "first field");
|
||||
assert_eq!(field2(&o), "second field");
|
||||
|
||||
// we can get a vec with all the lenses that match a type
|
||||
let string_lenses = <MyStruct as HasLensOf<String>>::get();
|
||||
assert_eq!(string_lenses.len(), 2);
|
||||
|
||||
// since _field4 is private, there's no lens for it
|
||||
let u8_lenses = <MyStruct as HasLensOf<u8>>::get();
|
||||
assert_eq!(u8_lenses.len(), 1);
|
||||
|
||||
// short macro for convenience, expands to the line above
|
||||
let _u8_lenses = lenses!(MyStruct::u8);
|
||||
|
||||
let mut o = o;
|
||||
for lens in string_lenses {
|
||||
o = lens(o, |s| s.to_ascii_uppercase());
|
||||
}
|
||||
dbg!(o);
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
use bad_optics::{
|
||||
lenses::{over, set},
|
||||
prelude::*,
|
||||
};
|
||||
|
||||
fn main() {
|
||||
let a = ((1, 2), 3);
|
||||
|
||||
// use view to access inside the tuple
|
||||
let res = view(_0, a);
|
||||
assert_eq!(res, (1, 2));
|
||||
|
||||
let res = view(_1, a);
|
||||
assert_eq!(res, 3);
|
||||
|
||||
// you can combine lenses
|
||||
let lens = _0 + _1;
|
||||
|
||||
// use the view function to access
|
||||
let res = view(lens, a);
|
||||
assert_eq!(res, 2);
|
||||
|
||||
// you can also call the lens as a function
|
||||
let res = lens(a);
|
||||
assert_eq!(res, 2);
|
||||
|
||||
// call the over function to modify the value
|
||||
let a = over(lens, a, |v| v + 1);
|
||||
assert_eq!(a, ((1, 3), 3));
|
||||
|
||||
// call the set function to set the value
|
||||
let a = set(lens, a, 5);
|
||||
assert_eq!(a, ((1, 5), 3));
|
||||
|
||||
// you can also call the lens as a function to modify the value
|
||||
let res = lens(a, |v| v + 1);
|
||||
assert_eq!(res, ((1, 6), 3));
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
use bad_optics::prelude::*;
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
struct MyStruct {
|
||||
hey: (u8, (u8, i32)),
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// make a lens for Hello
|
||||
let hey = lens(
|
||||
|hello: MyStruct| hello.hey,
|
||||
|mut hello: MyStruct, v| {
|
||||
hello.hey = v;
|
||||
hello
|
||||
},
|
||||
);
|
||||
|
||||
let my_struct = MyStruct { hey: (1, (2, -3)) };
|
||||
|
||||
// the thing we want to access
|
||||
let thing = (my_struct, "hello");
|
||||
|
||||
// a lens that targets the -3 inside my_struct
|
||||
let lens_that_targets_the_i32 = _0 + hey + _1 + _1;
|
||||
|
||||
assert_eq!(lens_that_targets_the_i32(thing), -3);
|
||||
}
|
|
@ -1,337 +1,41 @@
|
|||
use crate::{
|
||||
lenses::{Lens, LensOver, LensView},
|
||||
prisms::{Prism, PrismPreview},
|
||||
traversals::{Traversal, TraversalOver, TraversalTraverse},
|
||||
};
|
||||
use std::ops::Add;
|
||||
use crate::{Lens, LensOver, LensTrait, LensView};
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Combination<A, B>(A, B);
|
||||
impl<A, B> LensTrait for Combination<A, B> {}
|
||||
|
||||
// additions
|
||||
|
||||
// lens + lens
|
||||
impl<A, B> const Add<Lens<B>> for Lens<A> {
|
||||
impl<A, B> std::ops::Add<Lens<B>> for Lens<A>
|
||||
where
|
||||
A: LensTrait,
|
||||
B: LensTrait,
|
||||
{
|
||||
type Output = Lens<Combination<Lens<A>, Lens<B>>>;
|
||||
|
||||
fn add(self, rhs: Lens<B>) -> Self::Output {
|
||||
Lens(Combination(self, rhs))
|
||||
}
|
||||
}
|
||||
// prism + prism
|
||||
impl<A, B> const Add<Prism<B>> for Prism<A> {
|
||||
type Output = Prism<Combination<Prism<A>, Prism<B>>>;
|
||||
|
||||
fn add(self, rhs: Prism<B>) -> Self::Output {
|
||||
Prism(Combination(self, rhs))
|
||||
}
|
||||
}
|
||||
// traversal + traversal
|
||||
impl<A, B> const Add<Traversal<B>> for Traversal<A> {
|
||||
type Output = Traversal<Combination<Traversal<A>, Traversal<B>>>;
|
||||
|
||||
fn add(self, rhs: Traversal<B>) -> Self::Output {
|
||||
Traversal(Combination(self, rhs))
|
||||
}
|
||||
}
|
||||
// traversal + lens
|
||||
impl<A, B> const Add<Lens<B>> for Traversal<A> {
|
||||
type Output = Traversal<Combination<Traversal<A>, Traversal<Lens<B>>>>;
|
||||
|
||||
fn add(self, rhs: Lens<B>) -> Self::Output {
|
||||
Traversal(Combination(self, rhs.to_traversal()))
|
||||
}
|
||||
}
|
||||
// lens + traversal
|
||||
impl<A, B> const Add<Traversal<B>> for Lens<A> {
|
||||
type Output = Traversal<Combination<Traversal<Lens<A>>, Traversal<B>>>;
|
||||
|
||||
fn add(self, rhs: Traversal<B>) -> Self::Output {
|
||||
Traversal(Combination(self.to_traversal(), rhs))
|
||||
}
|
||||
}
|
||||
// traversal + prism
|
||||
impl<A, B> const Add<Prism<B>> for Traversal<A> {
|
||||
type Output = Traversal<Combination<Traversal<A>, Traversal<Prism<B>>>>;
|
||||
|
||||
fn add(self, rhs: Prism<B>) -> Self::Output {
|
||||
Traversal(Combination(self, rhs.to_traversal()))
|
||||
}
|
||||
}
|
||||
// prism + traversal
|
||||
impl<A, B> const Add<Traversal<B>> for Prism<A> {
|
||||
type Output = Traversal<Combination<Traversal<Prism<A>>, Traversal<B>>>;
|
||||
|
||||
fn add(self, rhs: Traversal<B>) -> Self::Output {
|
||||
Traversal(Combination(self.to_traversal(), rhs))
|
||||
}
|
||||
}
|
||||
// lens + prism
|
||||
impl<A, B> const Add<Prism<B>> for Lens<A> {
|
||||
type Output = Traversal<Combination<Traversal<Lens<A>>, Traversal<Prism<B>>>>;
|
||||
|
||||
fn add(self, rhs: Prism<B>) -> Self::Output {
|
||||
Traversal(Combination(self.to_traversal(), rhs.to_traversal()))
|
||||
}
|
||||
}
|
||||
// prism + traversal
|
||||
impl<A, B> const Add<Lens<B>> for Prism<A> {
|
||||
type Output = Traversal<Combination<Traversal<Prism<A>>, Traversal<Lens<B>>>>;
|
||||
|
||||
fn add(self, rhs: Lens<B>) -> Self::Output {
|
||||
Traversal(Combination(self.to_traversal(), rhs.to_traversal()))
|
||||
}
|
||||
}
|
||||
|
||||
// trait impls for Combination
|
||||
|
||||
// lens + lens
|
||||
impl<A, B, T> LensView<T> for Combination<Lens<A>, Lens<B>>
|
||||
impl<A, B, T> LensView<T> for Combination<A, B>
|
||||
where
|
||||
A: LensView<T>,
|
||||
B: LensView<A::Field>,
|
||||
{
|
||||
type Field = B::Field;
|
||||
|
||||
fn view(&self, thing: T) -> Self::Field {
|
||||
B::view(&self.1 .0, A::view(&self.0 .0, thing))
|
||||
fn view(thing: T) -> Self::Field {
|
||||
B::view(A::view(thing))
|
||||
}
|
||||
}
|
||||
impl<A, B, T> LensOver<T> for Combination<Lens<A>, Lens<B>>
|
||||
|
||||
impl<A, B, T> LensOver<T> for Combination<A, B>
|
||||
where
|
||||
A: LensOver<T>,
|
||||
B: LensOver<A::Field>,
|
||||
{
|
||||
fn over<F>(&self, thing: T, f: F) -> T
|
||||
fn over<F>(thing: T, f: F) -> T
|
||||
where
|
||||
F: FnOnce(Self::Field) -> Self::Field,
|
||||
{
|
||||
A::over(&self.0 .0, thing, |b| B::over(&self.1 .0, b, f))
|
||||
}
|
||||
}
|
||||
|
||||
// prism + prism
|
||||
impl<A, B, T> PrismPreview<T> for Combination<Prism<A>, Prism<B>>
|
||||
where
|
||||
A: PrismPreview<T>,
|
||||
B: PrismPreview<A::Field>,
|
||||
{
|
||||
type Field = B::Field;
|
||||
|
||||
fn preview(&self, thing: T) -> Option<Self::Field> {
|
||||
A::preview(&self.0 .0, thing).and_then(|a| B::preview(&self.1 .0, a))
|
||||
}
|
||||
|
||||
fn review(&self, thing: Self::Field) -> T {
|
||||
A::review(&self.0 .0, B::review(&self.1 .0, thing))
|
||||
}
|
||||
}
|
||||
|
||||
// traversal + traversal
|
||||
// lens + traversal
|
||||
// traversal + lens
|
||||
// prism + traversal
|
||||
// traversal + prism
|
||||
// prism + lens
|
||||
// lens + prism
|
||||
impl<A, B, T> TraversalTraverse<T> for Combination<Traversal<A>, Traversal<B>>
|
||||
where
|
||||
A: TraversalTraverse<T>,
|
||||
B: TraversalTraverse<A::Field>,
|
||||
{
|
||||
type Field = B::Field;
|
||||
|
||||
fn traverse(&self, thing: T) -> Vec<Self::Field> {
|
||||
let a = A::traverse(&self.0 .0, thing);
|
||||
a.into_iter()
|
||||
.flat_map(|v| B::traverse(&self.1 .0, v))
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
impl<A, B, T> TraversalOver<T> for Combination<Traversal<A>, Traversal<B>>
|
||||
where
|
||||
A: TraversalOver<T>,
|
||||
B: TraversalOver<A::Field>,
|
||||
{
|
||||
fn over<F>(&self, thing: T, mut f: F) -> T
|
||||
where
|
||||
F: FnMut(Self::Field) -> Self::Field,
|
||||
{
|
||||
A::over(&self.0 .0, thing, |b| B::over(&self.1 .0, b, &mut f))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{
|
||||
lenses::{_0, _1},
|
||||
prisms::_Some,
|
||||
traversals::each,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn can_view_lens_combination() {
|
||||
let a = ((1, 2), 3);
|
||||
|
||||
let lens = _0 + _1;
|
||||
let a = lens(a);
|
||||
assert_eq!(a, 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn can_over_lens_combination() {
|
||||
let a = ((1, 2), 3);
|
||||
|
||||
let lens = _0 + _1;
|
||||
let a = lens(a, |v| v + 1);
|
||||
assert_eq!(a, ((1, 3), 3));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn can_combine_prisms() {
|
||||
let thing = Some(Some(3));
|
||||
|
||||
// combine two traversals
|
||||
let res = (_Some + _Some)(thing, |v| v + 1);
|
||||
assert_eq!(res, Some(Some(4)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn can_combine_traversals() {
|
||||
let array = [vec![1, 2], vec![3, 4]];
|
||||
|
||||
// combine two traversals
|
||||
let res = (each + each)(array, |v| v + 1);
|
||||
assert_eq!(res, [vec![2, 3], vec![4, 5]]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn can_combine_traversal_with_lens() {
|
||||
let array = [(1, 2), (3, 4), (5, 6)];
|
||||
|
||||
// combine a traversal with a lens
|
||||
let t = each + _0;
|
||||
|
||||
// traverse
|
||||
let res = t(array);
|
||||
assert_eq!(res, vec![1, 3, 5]);
|
||||
|
||||
// over
|
||||
let res = t(array, |v| v + 1);
|
||||
assert_eq!(res, [(2, 2), (4, 4), (6, 6)]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn can_combine_lens_with_traversal() {
|
||||
let array = [(1, 2), (3, 4), (5, 6)];
|
||||
|
||||
// combine a traversal with a lens
|
||||
let t = _0 + each;
|
||||
|
||||
// traverse
|
||||
let res = t(array);
|
||||
assert_eq!(res, vec![1, 2]);
|
||||
|
||||
// over
|
||||
let res = t(array, |v| v + 1);
|
||||
assert_eq!(res, [(2, 3), (3, 4), (5, 6)]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn can_combine_prism_with_traversal() {
|
||||
let array = [Some(1), None, Some(3), None, Some(5)];
|
||||
|
||||
// combine a traversal with a lens
|
||||
let t = each + _Some;
|
||||
|
||||
// traverse
|
||||
let res = t(array);
|
||||
assert_eq!(res, vec![1, 3, 5]);
|
||||
|
||||
// over
|
||||
let res = t(array, |v| v + 1);
|
||||
assert_eq!(res, [Some(2), None, Some(4), None, Some(6)]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn can_combine_traversal_with_prism() {
|
||||
let array = Some([1, 2, 3]);
|
||||
|
||||
// combine a traversal with a lens
|
||||
let t = _Some + each;
|
||||
|
||||
// traverse
|
||||
let res = t(array);
|
||||
assert_eq!(res, vec![1, 2, 3]);
|
||||
|
||||
// over
|
||||
let res = t(array, |v| v + 1);
|
||||
assert_eq!(res, Some([2, 3, 4]));
|
||||
|
||||
let array: Option<[i32; 3]> = None;
|
||||
// traverse
|
||||
let res = t(array);
|
||||
assert_eq!(res, vec![]);
|
||||
|
||||
// over
|
||||
let res = t(array, |v| v + 1);
|
||||
assert_eq!(res, None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn can_combine_prism_with_lens() {
|
||||
let thing = Some((1, 2));
|
||||
|
||||
// combine a traversal with a lens
|
||||
let t = _Some + _0;
|
||||
|
||||
// NOTE: combination of a prism and a lens is a traversal
|
||||
//
|
||||
// > The optic kind resulting from a composition is the least upper bound (join)
|
||||
// > of the optic kinds being composed, if it exists.
|
||||
// > The Join type family computes the least upper bound given two optic kind tags.
|
||||
// > For example the Join of a Lens and a Prism is an AffineTraversal.
|
||||
//
|
||||
// from: https://hackage.haskell.org/package/optics-0.4/docs/Optics.html
|
||||
|
||||
// traversal
|
||||
let res = t(thing);
|
||||
assert_eq!(res, vec![1]);
|
||||
|
||||
// over
|
||||
let res = t(thing, |v| v + 1);
|
||||
assert_eq!(res, Some((2, 2)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn can_combine_lens_with_prism() {
|
||||
let thing = (Some(1), 2);
|
||||
|
||||
// combine a traversal with a lens
|
||||
let t = _0 + _Some;
|
||||
|
||||
// NOTE: combination of a lens and a prism is a traversal
|
||||
// see can_combine_prism_with_lens for more info
|
||||
|
||||
// traversal
|
||||
let res = t(thing);
|
||||
assert_eq!(res, vec![1]);
|
||||
|
||||
// over
|
||||
let res = t(thing, |v| v + 1);
|
||||
assert_eq!(res, (Some(2), 2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn can_combine_as_const() {
|
||||
use crate::lenses::first::_0Inner;
|
||||
use crate::lenses::Lens;
|
||||
const LENS: Lens<super::Combination<Lens<_0Inner>, Lens<_0Inner>>> = _0 + _0;
|
||||
|
||||
let thing: ((i32, i32), i32) = ((1, 2), 3);
|
||||
|
||||
let r: i32 = LENS(thing);
|
||||
|
||||
assert_eq!(r, 1);
|
||||
A::over(thing, |b| B::over(b, f))
|
||||
}
|
||||
}
|
||||
|
|
185
src/fns.rs
185
src/fns.rs
|
@ -1,185 +0,0 @@
|
|||
use crate::{
|
||||
lenses::{Lens, LensOver, LensView},
|
||||
prisms::{Prism, PrismPreview},
|
||||
traversals::{Traversal, TraversalOver, TraversalTraverse},
|
||||
};
|
||||
|
||||
// lens view
|
||||
impl<L, A> std::ops::FnOnce<(A,)> for Lens<L>
|
||||
where
|
||||
L: LensView<A>,
|
||||
{
|
||||
type Output = L::Field;
|
||||
|
||||
extern "rust-call" fn call_once(self, args: (A,)) -> Self::Output {
|
||||
L::view(&self.0, args.0)
|
||||
}
|
||||
}
|
||||
impl<L, A> std::ops::FnMut<(A,)> for Lens<L>
|
||||
where
|
||||
L: LensView<A>,
|
||||
{
|
||||
extern "rust-call" fn call_mut(&mut self, args: (A,)) -> Self::Output {
|
||||
L::view(&self.0, args.0)
|
||||
}
|
||||
}
|
||||
impl<L, A> std::ops::Fn<(A,)> for Lens<L>
|
||||
where
|
||||
L: LensView<A>,
|
||||
{
|
||||
extern "rust-call" fn call(&self, args: (A,)) -> Self::Output {
|
||||
L::view(&self.0, args.0)
|
||||
}
|
||||
}
|
||||
|
||||
// lens over
|
||||
impl<L, A, F> std::ops::FnOnce<(A, F)> for Lens<L>
|
||||
where
|
||||
L: LensOver<A>,
|
||||
F: FnOnce(L::Field) -> L::Field,
|
||||
{
|
||||
type Output = A;
|
||||
|
||||
extern "rust-call" fn call_once(self, args: (A, F)) -> Self::Output {
|
||||
L::over(&self.0, args.0, args.1)
|
||||
}
|
||||
}
|
||||
impl<L, A, F> std::ops::FnMut<(A, F)> for Lens<L>
|
||||
where
|
||||
L: LensOver<A>,
|
||||
F: FnOnce(L::Field) -> L::Field,
|
||||
{
|
||||
extern "rust-call" fn call_mut(&mut self, args: (A, F)) -> Self::Output {
|
||||
L::over(&self.0, args.0, args.1)
|
||||
}
|
||||
}
|
||||
impl<L, A, F> std::ops::Fn<(A, F)> for Lens<L>
|
||||
where
|
||||
L: LensOver<A>,
|
||||
F: FnOnce(L::Field) -> L::Field,
|
||||
{
|
||||
extern "rust-call" fn call(&self, args: (A, F)) -> Self::Output {
|
||||
L::over(&self.0, args.0, args.1)
|
||||
}
|
||||
}
|
||||
|
||||
// traversal traverse
|
||||
impl<L, A> std::ops::FnOnce<(A,)> for Traversal<L>
|
||||
where
|
||||
L: TraversalTraverse<A>,
|
||||
{
|
||||
type Output = Vec<L::Field>;
|
||||
|
||||
extern "rust-call" fn call_once(self, args: (A,)) -> Self::Output {
|
||||
L::traverse(&self.0, args.0)
|
||||
}
|
||||
}
|
||||
impl<L, A> std::ops::FnMut<(A,)> for Traversal<L>
|
||||
where
|
||||
L: TraversalTraverse<A>,
|
||||
{
|
||||
extern "rust-call" fn call_mut(&mut self, args: (A,)) -> Self::Output {
|
||||
L::traverse(&self.0, args.0)
|
||||
}
|
||||
}
|
||||
impl<L, A> std::ops::Fn<(A,)> for Traversal<L>
|
||||
where
|
||||
L: TraversalTraverse<A>,
|
||||
{
|
||||
extern "rust-call" fn call(&self, args: (A,)) -> Self::Output {
|
||||
L::traverse(&self.0, args.0)
|
||||
}
|
||||
}
|
||||
|
||||
// traversal over
|
||||
impl<L, A, F> std::ops::FnOnce<(A, F)> for Traversal<L>
|
||||
where
|
||||
L: TraversalOver<A>,
|
||||
F: FnMut(L::Field) -> L::Field,
|
||||
{
|
||||
type Output = A;
|
||||
|
||||
extern "rust-call" fn call_once(self, args: (A, F)) -> Self::Output {
|
||||
L::over(&self.0, args.0, args.1)
|
||||
}
|
||||
}
|
||||
impl<L, A, F> std::ops::FnMut<(A, F)> for Traversal<L>
|
||||
where
|
||||
L: TraversalOver<A>,
|
||||
F: FnMut(L::Field) -> L::Field,
|
||||
{
|
||||
extern "rust-call" fn call_mut(&mut self, args: (A, F)) -> Self::Output {
|
||||
L::over(&self.0, args.0, args.1)
|
||||
}
|
||||
}
|
||||
impl<L, A, F> std::ops::Fn<(A, F)> for Traversal<L>
|
||||
where
|
||||
L: TraversalOver<A>,
|
||||
F: FnMut(L::Field) -> L::Field,
|
||||
{
|
||||
extern "rust-call" fn call(&self, args: (A, F)) -> Self::Output {
|
||||
L::over(&self.0, args.0, args.1)
|
||||
}
|
||||
}
|
||||
|
||||
// prism preview
|
||||
impl<L, A> std::ops::FnOnce<(A,)> for Prism<L>
|
||||
where
|
||||
L: PrismPreview<A>,
|
||||
{
|
||||
type Output = Option<L::Field>;
|
||||
|
||||
extern "rust-call" fn call_once(self, args: (A,)) -> Self::Output {
|
||||
L::preview(&self.0, args.0)
|
||||
}
|
||||
}
|
||||
impl<L, A> std::ops::FnMut<(A,)> for Prism<L>
|
||||
where
|
||||
L: PrismPreview<A>,
|
||||
{
|
||||
extern "rust-call" fn call_mut(&mut self, args: (A,)) -> Self::Output {
|
||||
L::preview(&self.0, args.0)
|
||||
}
|
||||
}
|
||||
impl<L, A> std::ops::Fn<(A,)> for Prism<L>
|
||||
where
|
||||
L: PrismPreview<A>,
|
||||
{
|
||||
extern "rust-call" fn call(&self, args: (A,)) -> Self::Output {
|
||||
L::preview(&self.0, args.0)
|
||||
}
|
||||
}
|
||||
|
||||
// prism over
|
||||
impl<L, A, F> std::ops::FnOnce<(A, F)> for Prism<L>
|
||||
where
|
||||
A: Clone,
|
||||
L: PrismPreview<A>,
|
||||
F: FnMut(L::Field) -> L::Field,
|
||||
{
|
||||
type Output = A;
|
||||
|
||||
extern "rust-call" fn call_once(self, args: (A, F)) -> Self::Output {
|
||||
L::over(&self.0, args.0, args.1)
|
||||
}
|
||||
}
|
||||
impl<L, A, F> std::ops::FnMut<(A, F)> for Prism<L>
|
||||
where
|
||||
A: Clone,
|
||||
L: PrismPreview<A>,
|
||||
F: FnMut(L::Field) -> L::Field,
|
||||
{
|
||||
extern "rust-call" fn call_mut(&mut self, args: (A, F)) -> Self::Output {
|
||||
L::over(&self.0, args.0, args.1)
|
||||
}
|
||||
}
|
||||
impl<L, A, F> std::ops::Fn<(A, F)> for Prism<L>
|
||||
where
|
||||
A: Clone,
|
||||
L: PrismPreview<A>,
|
||||
F: FnMut(L::Field) -> L::Field,
|
||||
{
|
||||
extern "rust-call" fn call(&self, args: (A, F)) -> Self::Output {
|
||||
L::over(&self.0, args.0, args.1)
|
||||
}
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
#[macro_export]
|
||||
macro_rules! field_lens {
|
||||
($type:ident, $field:ident) => {
|
||||
$crate::lenses::lens(
|
||||
|v: $type| v.$field,
|
||||
|mut u: $type, v| {
|
||||
u.$field = v;
|
||||
u
|
||||
},
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
#[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(),
|
||||
)
|
||||
};
|
||||
}
|
|
@ -1,108 +0,0 @@
|
|||
use crate::lenses::{Lens, LensOver, LensView};
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct _4Inner;
|
||||
pub const _4: Lens<_4Inner> = Lens(_4Inner);
|
||||
|
||||
macro_rules! make_tuples {
|
||||
($f:ident, ( $( $v:ident ),* ), ( $( $t:ident ),* ) ) => {
|
||||
impl< $($t,)* > LensView<( $($t,)* )> for _4Inner {
|
||||
type Field = T;
|
||||
|
||||
fn view(&self, ( $($v,)* ): ($($t,)*)) -> Self::Field {
|
||||
$f
|
||||
}
|
||||
}
|
||||
impl< $($t,)* > LensOver<( $($t,)* )> for _4Inner {
|
||||
fn over<F>(
|
||||
&self,
|
||||
mut tup: ($($t,)*),
|
||||
f: F
|
||||
) -> ( $($t,)* )
|
||||
where
|
||||
F: FnOnce(Self::Field) -> Self::Field
|
||||
{
|
||||
tup.4 = f(tup.4);
|
||||
tup
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, $($t,)* > LensView<&'a ( $($t,)* )> for _4Inner {
|
||||
type Field = &'a T;
|
||||
|
||||
fn view(&self, ( $($v,)* ): &'a ($($t,)*)) -> Self::Field {
|
||||
$f
|
||||
}
|
||||
}
|
||||
impl<'a, $($t,)* > LensView<&'a mut ( $($t,)* )> for _4Inner {
|
||||
type Field = &'a mut T;
|
||||
|
||||
fn view(&self, ( $($v,)* ): &'a mut ($($t,)*)) -> Self::Field {
|
||||
$f
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
make_tuples!(t, (_u, _v, _w, _x, t), (U, V, W, X, T));
|
||||
make_tuples!(t, (_u, _v, _w, _x, t, _y), (U, V, W, X, T, Y));
|
||||
make_tuples!(t, (_u, _v, _w, _x, t, _y, _z), (U, V, W, X, T, Y, Z));
|
||||
make_tuples!(t, (_u, _v, _w, _x, t, _y, _z, _a), (U, V, W, X, T, Y, Z, A));
|
||||
make_tuples!(
|
||||
t,
|
||||
(_u, _v, _w, _x, t, _y, _z, _a, _b),
|
||||
(U, V, W, X, T, Y, Z, A, B)
|
||||
);
|
||||
make_tuples!(
|
||||
t,
|
||||
(_u, _v, _w, _x, t, _y, _z, _a, _b, _c),
|
||||
(U, V, W, X, T, Y, Z, A, B, C)
|
||||
);
|
||||
// not doing more cause i'm lazy, open a pr if you need more :)
|
||||
|
||||
macro_rules! make_arrays {
|
||||
($f:ident, $n:expr, [$( $v:ident ),*]) => {
|
||||
impl<T> LensView<[T; $n]> for _4Inner {
|
||||
type Field = T;
|
||||
|
||||
fn view(&self, [ $($v,)* ]: [T; $n]) -> Self::Field {
|
||||
$f
|
||||
}
|
||||
}
|
||||
impl<T> LensOver<[T; $n]> for _4Inner {
|
||||
fn over<F>(
|
||||
&self,
|
||||
tup: [T; $n],
|
||||
fun: F
|
||||
) -> [T; $n]
|
||||
where
|
||||
F: FnOnce(Self::Field) -> Self::Field
|
||||
{
|
||||
let [$($v,)*] = tup;
|
||||
let $f = fun( $f );
|
||||
[$($v,)*]
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> LensView<&'a [T; $n]> for _4Inner {
|
||||
type Field = &'a T;
|
||||
|
||||
fn view(&self, [ $($v,)* ]: &'a [T; $n]) -> Self::Field {
|
||||
$f
|
||||
}
|
||||
}
|
||||
impl<'a, T> LensView<&'a mut [T; $n]> for _4Inner {
|
||||
type Field = &'a mut T;
|
||||
|
||||
fn view(&self, [ $($v,)* ]: &'a mut [T; $n]) -> Self::Field {
|
||||
$f
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
make_arrays!(t, 5, [_a, _b, _c, _d, t]);
|
||||
make_arrays!(t, 6, [_a, _b, _c, _d, t, _e]);
|
||||
make_arrays!(t, 7, [_a, _b, _c, _d, t, _e, _g]);
|
||||
make_arrays!(t, 8, [_a, _b, _c, _d, t, _e, _g, _h]);
|
||||
make_arrays!(t, 9, [_a, _b, _c, _d, t, _e, _g, _h, _i]);
|
|
@ -1,21 +1,20 @@
|
|||
use crate::lenses::{Lens, LensOver, LensView};
|
||||
use crate::{Lens, LensOver, LensTrait, LensView};
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct _0Inner;
|
||||
pub const _0: Lens<_0Inner> = Lens(_0Inner);
|
||||
impl LensTrait for _0Inner {}
|
||||
|
||||
macro_rules! make_tuples {
|
||||
($f:ident, ( $( $v:ident ),* ), ( $( $t:ident ),* ) ) => {
|
||||
impl< $($t,)* > LensView<( $($t,)* )> for _0Inner {
|
||||
type Field = T;
|
||||
|
||||
fn view(&self, ( $($v,)* ): ($($t,)*)) -> Self::Field {
|
||||
fn view(( $($v,)* ): ($($t,)*)) -> Self::Field {
|
||||
$f
|
||||
}
|
||||
}
|
||||
impl< $($t,)* > LensOver<( $($t,)* )> for _0Inner {
|
||||
impl< $($t,)* > LensOver<( $($t,)* )> for _0Inner {
|
||||
fn over<F>(
|
||||
&self,
|
||||
mut tup: ($($t,)*),
|
||||
f: F
|
||||
) -> ( $($t,)* )
|
||||
|
@ -27,17 +26,17 @@ macro_rules! make_tuples {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, $($t,)* > LensView<&'a ( $($t,)* )> for _0Inner {
|
||||
impl<'a, $($t,)* > LensView<&'a ( $($t,)* )> for _0Inner {
|
||||
type Field = &'a T;
|
||||
|
||||
fn view(&self, ( $($v,)* ): &'a ($($t,)*)) -> Self::Field {
|
||||
fn view(( $($v,)* ): &'a ($($t,)*)) -> Self::Field {
|
||||
$f
|
||||
}
|
||||
}
|
||||
impl<'a, $($t,)* > LensView<&'a mut ( $($t,)* )> for _0Inner {
|
||||
impl<'a, $($t,)* > LensView<&'a mut ( $($t,)* )> for _0Inner {
|
||||
type Field = &'a mut T;
|
||||
|
||||
fn view(&self, ( $($v,)* ): &'a mut ($($t,)*)) -> Self::Field {
|
||||
fn view(( $($v,)* ): &'a mut ($($t,)*)) -> Self::Field {
|
||||
$f
|
||||
}
|
||||
}
|
||||
|
@ -57,13 +56,12 @@ macro_rules! make_arrays {
|
|||
impl<T> LensView<[T; $n]> for _0Inner {
|
||||
type Field = T;
|
||||
|
||||
fn view(&self, [ $($v,)* ]: [T; $n]) -> Self::Field {
|
||||
fn view([ $($v,)* ]: [T; $n]) -> Self::Field {
|
||||
$f
|
||||
}
|
||||
}
|
||||
impl<T> LensOver<[T; $n]> for _0Inner {
|
||||
fn over<F>(
|
||||
&self,
|
||||
tup: [T; $n],
|
||||
fun: F
|
||||
) -> [T; $n]
|
||||
|
@ -79,14 +77,14 @@ macro_rules! make_arrays {
|
|||
impl<'a, T> LensView<&'a [T; $n]> for _0Inner {
|
||||
type Field = &'a T;
|
||||
|
||||
fn view(&self, [ $($v,)* ]: &'a [T; $n]) -> Self::Field {
|
||||
fn view([ $($v,)* ]: &'a [T; $n]) -> Self::Field {
|
||||
$f
|
||||
}
|
||||
}
|
||||
impl<'a, T> LensView<&'a mut [T; $n]> for _0Inner {
|
||||
type Field = &'a mut T;
|
||||
|
||||
fn view(&self, [ $($v,)* ]: &'a mut [T; $n]) -> Self::Field {
|
||||
fn view([ $($v,)* ]: &'a mut [T; $n]) -> Self::Field {
|
||||
$f
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,110 +0,0 @@
|
|||
use crate::lenses::{Lens, LensOver, LensView};
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct _3Inner;
|
||||
pub const _3: Lens<_3Inner> = Lens(_3Inner);
|
||||
|
||||
macro_rules! make_tuples {
|
||||
($f:ident, ( $( $v:ident ),* ), ( $( $t:ident ),* ) ) => {
|
||||
impl< $($t,)* > LensView<( $($t,)* )> for _3Inner {
|
||||
type Field = T;
|
||||
|
||||
fn view(&self, ( $($v,)* ): ($($t,)*)) -> Self::Field {
|
||||
$f
|
||||
}
|
||||
}
|
||||
impl< $($t,)* > LensOver<( $($t,)* )> for _3Inner {
|
||||
fn over<F>(
|
||||
&self,
|
||||
mut tup: ($($t,)*),
|
||||
f: F
|
||||
) -> ( $($t,)* )
|
||||
where
|
||||
F: FnOnce(Self::Field) -> Self::Field
|
||||
{
|
||||
tup.3 = f(tup.3);
|
||||
tup
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, $($t,)* > LensView<&'a ( $($t,)* )> for _3Inner {
|
||||
type Field = &'a T;
|
||||
|
||||
fn view(&self, ( $($v,)* ): &'a ($($t,)*)) -> Self::Field {
|
||||
$f
|
||||
}
|
||||
}
|
||||
impl<'a, $($t,)* > LensView<&'a mut ( $($t,)* )> for _3Inner {
|
||||
type Field = &'a mut T;
|
||||
|
||||
fn view(&self, ( $($v,)* ): &'a mut ($($t,)*)) -> Self::Field {
|
||||
$f
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
make_tuples!(t, (_u, _v, _w, t), (U, V, W, T));
|
||||
make_tuples!(t, (_u, _v, _w, t, _x), (U, V, W, T, X));
|
||||
make_tuples!(t, (_u, _v, _w, t, _x, _y), (U, V, W, T, X, Y));
|
||||
make_tuples!(t, (_u, _v, _w, t, _x, _y, _z), (U, V, W, T, X, Y, Z));
|
||||
make_tuples!(t, (_u, _v, _w, t, _x, _y, _z, _a), (U, V, W, T, X, Y, Z, A));
|
||||
make_tuples!(
|
||||
t,
|
||||
(_u, _v, _w, t, _x, _y, _z, _a, _b),
|
||||
(U, V, W, T, X, Y, Z, A, B)
|
||||
);
|
||||
make_tuples!(
|
||||
t,
|
||||
(_u, _v, _w, t, _x, _y, _z, _a, _b, _c),
|
||||
(U, V, W, T, X, Y, Z, A, B, C)
|
||||
);
|
||||
// not doing more cause i'm lazy, open a pr if you need more :)
|
||||
|
||||
macro_rules! make_arrays {
|
||||
($f:ident, $n:expr, [$( $v:ident ),*]) => {
|
||||
impl<T> LensView<[T; $n]> for _3Inner {
|
||||
type Field = T;
|
||||
|
||||
fn view(&self, [ $($v,)* ]: [T; $n]) -> Self::Field {
|
||||
$f
|
||||
}
|
||||
}
|
||||
impl<T> LensOver<[T; $n]> for _3Inner {
|
||||
fn over<F>(
|
||||
&self,
|
||||
tup: [T; $n],
|
||||
fun: F
|
||||
) -> [T; $n]
|
||||
where
|
||||
F: FnOnce(Self::Field) -> Self::Field
|
||||
{
|
||||
let [$($v,)*] = tup;
|
||||
let $f = fun( $f );
|
||||
[$($v,)*]
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> LensView<&'a [T; $n]> for _3Inner {
|
||||
type Field = &'a T;
|
||||
|
||||
fn view(&self, [ $($v,)* ]: &'a [T; $n]) -> Self::Field {
|
||||
$f
|
||||
}
|
||||
}
|
||||
impl<'a, T> LensView<&'a mut [T; $n]> for _3Inner {
|
||||
type Field = &'a mut T;
|
||||
|
||||
fn view(&self, [ $($v,)* ]: &'a mut [T; $n]) -> Self::Field {
|
||||
$f
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
make_arrays!(t, 4, [_a, _b, _c, t]);
|
||||
make_arrays!(t, 5, [_a, _b, _c, t, _d]);
|
||||
make_arrays!(t, 6, [_a, _b, _c, t, _d, _e]);
|
||||
make_arrays!(t, 7, [_a, _b, _c, t, _d, _e, _g]);
|
||||
make_arrays!(t, 8, [_a, _b, _c, t, _d, _e, _g, _h]);
|
||||
make_arrays!(t, 9, [_a, _b, _c, t, _d, _e, _g, _h, _i]);
|
|
@ -1,19 +1,18 @@
|
|||
use crate::lenses::{Lens, LensOver, LensView};
|
||||
use crate::{LensOver, LensTrait, LensView};
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct IdInner;
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const id: Lens<IdInner> = Lens(IdInner);
|
||||
#[allow(non_camel_case_types)]
|
||||
pub struct id;
|
||||
|
||||
impl<T> LensView<T> for IdInner {
|
||||
impl LensTrait for id {}
|
||||
impl<T> LensView<T> for id {
|
||||
type Field = T;
|
||||
|
||||
fn view(&self, thing: T) -> Self::Field {
|
||||
fn view(thing: T) -> Self::Field {
|
||||
thing
|
||||
}
|
||||
}
|
||||
impl<T> LensOver<T> for IdInner {
|
||||
fn over<F>(&self, thing: T, f: F) -> T
|
||||
impl<T> LensOver<T> for id {
|
||||
fn over<F>(thing: T, f: F) -> T
|
||||
where
|
||||
F: FnOnce(Self::Field) -> Self::Field,
|
||||
{
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use crate::lenses::{Lens, LensOver, LensView};
|
||||
|
||||
type Getter<T, U> = dyn Fn(T) -> U;
|
||||
type Setter<T, U> = dyn Fn(T, U) -> T;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct FuncLens<T, U>(pub(crate) Arc<Getter<T, U>>, pub(crate) Arc<Setter<T, U>>);
|
||||
|
||||
impl<T, U> LensView<T> for FuncLens<T, U> {
|
||||
type Field = U;
|
||||
|
||||
fn view(&self, thing: T) -> Self::Field {
|
||||
(self.0)(thing)
|
||||
}
|
||||
}
|
||||
impl<T: Clone, U> LensOver<T> for FuncLens<T, U> {
|
||||
fn over<F>(&self, thing: T, f: F) -> T
|
||||
where
|
||||
F: FnOnce(Self::Field) -> Self::Field,
|
||||
{
|
||||
let v = f((self.0)(thing.clone()));
|
||||
(self.1)(thing, v)
|
||||
}
|
||||
|
||||
fn set(&self, thing: T, v: Self::Field) -> T {
|
||||
(self.1)(thing, v)
|
||||
}
|
||||
}
|
||||
|
||||
/// Makes a lens that implements `LensView<T>` and `LensOver<T>` with the provided functions
|
||||
pub fn lens_from_arc<T, U>(
|
||||
getter: Arc<Getter<T, U>>,
|
||||
setter: Arc<Setter<T, U>>,
|
||||
) -> Lens<FuncLens<T, U>> {
|
||||
Lens(FuncLens(getter, setter))
|
||||
}
|
||||
/// Makes a lens that implements `LensView<T>` and `LensOver<T>` with the provided functions
|
||||
pub fn lens<T, U>(
|
||||
getter: impl Fn(T) -> U + 'static,
|
||||
setter: impl Fn(T, U) -> T + 'static,
|
||||
) -> Lens<FuncLens<T, U>> {
|
||||
Lens(FuncLens(Arc::new(getter), Arc::new(setter)))
|
||||
}
|
|
@ -1,83 +0,0 @@
|
|||
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(),
|
||||
))
|
||||
}
|
|
@ -1,261 +1,7 @@
|
|||
pub mod fields;
|
||||
|
||||
pub mod identity;
|
||||
mod identity;
|
||||
pub use identity::id;
|
||||
|
||||
pub mod first;
|
||||
mod first;
|
||||
pub use first::_0;
|
||||
pub mod second;
|
||||
mod second;
|
||||
pub use second::_1;
|
||||
pub mod third;
|
||||
pub use third::_2;
|
||||
pub mod fourth;
|
||||
pub use fourth::_3;
|
||||
pub mod fifth;
|
||||
pub use fifth::_4;
|
||||
|
||||
pub mod to;
|
||||
pub use to::{to, to_from_arc};
|
||||
pub mod lens;
|
||||
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
|
||||
#[derive(Clone, Copy)]
|
||||
#[repr(transparent)]
|
||||
pub struct Lens<L>(pub(crate) L);
|
||||
|
||||
/// For lenses that allow viewing
|
||||
pub trait LensView<T> {
|
||||
type Field;
|
||||
|
||||
fn view(&self, thing: T) -> Self::Field;
|
||||
}
|
||||
|
||||
/// For lenses that allow setting
|
||||
pub trait LensOver<T>: LensView<T> {
|
||||
fn over<F>(&self, thing: T, f: F) -> T
|
||||
where
|
||||
F: FnOnce(Self::Field) -> Self::Field;
|
||||
|
||||
fn set(&self, thing: T, v: Self::Field) -> T {
|
||||
Self::over(self, thing, |_| v)
|
||||
}
|
||||
}
|
||||
|
||||
impl<L, T> LensView<T> for Lens<L>
|
||||
where
|
||||
L: LensView<T>,
|
||||
{
|
||||
type Field = L::Field;
|
||||
|
||||
fn view(&self, thing: T) -> Self::Field {
|
||||
L::view(&self.0, thing)
|
||||
}
|
||||
}
|
||||
impl<L, T> LensOver<T> for Lens<L>
|
||||
where
|
||||
L: LensOver<T>,
|
||||
{
|
||||
fn over<F>(&self, thing: T, f: F) -> T
|
||||
where
|
||||
F: FnOnce(Self::Field) -> Self::Field,
|
||||
{
|
||||
L::over(&self.0, thing, f)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn view<T, L: LensView<T>>(lens: L, thing: T) -> L::Field {
|
||||
L::view(&lens, thing)
|
||||
}
|
||||
pub fn set<T, L: LensOver<T>>(lens: L, thing: T, v: L::Field) -> T {
|
||||
L::set(&lens, thing, v)
|
||||
}
|
||||
pub fn over<T, L: LensOver<T>>(lens: L, thing: T, f: impl FnOnce(L::Field) -> L::Field) -> T {
|
||||
L::over(&lens, thing, f)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn view_first_from_tuple() {
|
||||
let a = (1, 2);
|
||||
assert_eq!(view(_0, a), 1);
|
||||
|
||||
let a = (1, 2);
|
||||
assert_eq!(view(_0, &a), &1);
|
||||
|
||||
let mut a = (1, 2);
|
||||
assert_eq!(view(_0, &mut a), &mut 1);
|
||||
|
||||
let a = (1, 2, 3);
|
||||
assert_eq!(view(_0, a), 1);
|
||||
|
||||
let a = (1, 2, 3);
|
||||
assert_eq!(view(_0, &a), &1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn view_first_from_tuple_mut_works() {
|
||||
let mut a = (1, 2);
|
||||
*view(_0, &mut a) += 1;
|
||||
|
||||
assert_eq!(a, (2, 2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_first_from_tuple() {
|
||||
let a = (1, 2);
|
||||
let a = set(_0, a, 3);
|
||||
assert_eq!(a, (3, 2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn over_first_from_tuple() {
|
||||
let a = (1, 2);
|
||||
let a = over(_0, a, |v| v + 1);
|
||||
assert_eq!(a, (2, 2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn over_first_from_array() {
|
||||
let a = [1, 2, 3, 4];
|
||||
|
||||
let a = over(_0, a, |v| v + 1);
|
||||
assert_eq!(a, [2, 2, 3, 4]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn second() {
|
||||
let a = (1, 2);
|
||||
let a = over(_1, a, |v| v + 1);
|
||||
assert_eq!(a, (1, 3));
|
||||
|
||||
let a = [1, 2, 3, 4];
|
||||
let a = over(_1, a, |v| v + 1);
|
||||
assert_eq!(a, [1, 3, 3, 4]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn call_as_funcs() {
|
||||
let a = (1, 2);
|
||||
assert_eq!(_0(a), 1);
|
||||
|
||||
let a = (1, 2);
|
||||
assert_eq!(_0(a, |v| v + 1), (2, 2));
|
||||
|
||||
let a = ((1, 2), 3);
|
||||
|
||||
let res = _0(a);
|
||||
assert_eq!(res, (1, 2));
|
||||
|
||||
let lens = _0 + _1;
|
||||
|
||||
let res = lens(a);
|
||||
assert_eq!(res, 2);
|
||||
let res = lens(a, |v| v + 1);
|
||||
assert_eq!(res, ((1, 3), 3));
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
struct Hello {
|
||||
hey: u8,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn can_use_to() {
|
||||
// making a getter
|
||||
let l = to(|hello: Hello| hello.hey);
|
||||
|
||||
let hello = Hello { hey: 8 };
|
||||
assert_eq!(l(hello), 8);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn can_make_lens_for_field() {
|
||||
// making a lens
|
||||
let l = crate::field_lens!(Hello, hey);
|
||||
|
||||
let hello = Hello { hey: 8 };
|
||||
assert_eq!(l(hello), 8);
|
||||
|
||||
let hello = Hello { hey: 8 };
|
||||
assert_eq!(l(hello, |v| v + 1), Hello { hey: 9 });
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn can_make_lens_with_ref_for_field() {
|
||||
// making a lens
|
||||
let l = crate::field_lens_with_ref!(Hello, hey);
|
||||
|
||||
let hello = Hello { hey: 8 };
|
||||
// as ref
|
||||
assert_eq!(l(&hello), 8);
|
||||
// as move
|
||||
assert_eq!(l(hello.clone()), 8);
|
||||
|
||||
assert_eq!(l(hello, |v| v + 1), Hello { hey: 9 });
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn can_make_lens_out_of_funcs() {
|
||||
// making a lens
|
||||
let l = lens(
|
||||
|hello: Hello| hello.hey,
|
||||
|mut hello: Hello, v: u8| {
|
||||
hello.hey = v;
|
||||
hello
|
||||
},
|
||||
);
|
||||
|
||||
let hello = Hello { hey: 8 };
|
||||
assert_eq!(l(hello), 8);
|
||||
|
||||
let hello = Hello { hey: 8 };
|
||||
assert_eq!(l(hello, |v| v + 1), Hello { hey: 9 });
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn can_make_lens_out_of_to() {
|
||||
// we first use to, and then use that to make a full lens
|
||||
|
||||
let l = to(|hello: Hello| hello.hey);
|
||||
let l = l.make_lens(|mut hello: Hello, v: u8| {
|
||||
hello.hey = v;
|
||||
hello
|
||||
});
|
||||
|
||||
let hello = Hello { hey: 8 };
|
||||
assert_eq!(l(hello), 8);
|
||||
|
||||
let hello = Hello { hey: 8 };
|
||||
assert_eq!(l(hello, |v| v + 1), Hello { hey: 9 });
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn convoluted_example() {
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
struct Hello2 {
|
||||
hey: (u8, (u8, i32)),
|
||||
}
|
||||
|
||||
// make a lens for Hello
|
||||
let l = lens(
|
||||
|hello: Hello2| hello.hey,
|
||||
|mut hello: Hello2, v| {
|
||||
hello.hey = v;
|
||||
hello
|
||||
},
|
||||
);
|
||||
|
||||
let thing = Hello2 { hey: (1, (2, -3)) };
|
||||
let thing = (thing, "hello");
|
||||
|
||||
let lens_that_targets_the_i32 = _0 + l + _1 + _1;
|
||||
|
||||
assert_eq!(lens_that_targets_the_i32(thing), -3);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,21 +1,20 @@
|
|||
use crate::lenses::{Lens, LensOver, LensView};
|
||||
use crate::{Lens, LensOver, LensTrait, LensView};
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct _1Inner;
|
||||
pub const _1: Lens<_1Inner> = Lens(_1Inner);
|
||||
impl LensTrait for _1Inner {}
|
||||
|
||||
macro_rules! make_tuples {
|
||||
($f:ident, ( $( $v:ident ),* ), ( $( $t:ident ),* ) ) => {
|
||||
impl< $($t,)* > LensView<( $($t,)* )> for _1Inner {
|
||||
impl< $($t,)* > LensView<( $($t,)* )> for _1Inner {
|
||||
type Field = T;
|
||||
|
||||
fn view(&self, ( $($v,)* ): ($($t,)*)) -> Self::Field {
|
||||
fn view(( $($v,)* ): ($($t,)*)) -> Self::Field {
|
||||
$f
|
||||
}
|
||||
}
|
||||
impl< $($t,)* > LensOver<( $($t,)* )> for _1Inner {
|
||||
impl< $($t,)* > LensOver<( $($t,)* )> for _1Inner {
|
||||
fn over<F>(
|
||||
&self,
|
||||
mut tup: ($($t,)*),
|
||||
f: F
|
||||
) -> ( $($t,)* )
|
||||
|
@ -27,17 +26,17 @@ macro_rules! make_tuples {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, $($t,)* > LensView<&'a ( $($t,)* )> for _1Inner {
|
||||
impl<'a, $($t,)* > LensView<&'a ( $($t,)* )> for _1Inner {
|
||||
type Field = &'a T;
|
||||
|
||||
fn view(&self, ( $($v,)* ): &'a ($($t,)*)) -> Self::Field {
|
||||
fn view(( $($v,)* ): &'a ($($t,)*)) -> Self::Field {
|
||||
$f
|
||||
}
|
||||
}
|
||||
impl<'a, $($t,)* > LensView<&'a mut ( $($t,)* )> for _1Inner {
|
||||
impl<'a, $($t,)* > LensView<&'a mut ( $($t,)* )> for _1Inner {
|
||||
type Field = &'a mut T;
|
||||
|
||||
fn view(&self, ( $($v,)* ): &'a mut ($($t,)*)) -> Self::Field {
|
||||
fn view(( $($v,)* ): &'a mut ($($t,)*)) -> Self::Field {
|
||||
$f
|
||||
}
|
||||
}
|
||||
|
@ -57,13 +56,12 @@ macro_rules! make_arrays {
|
|||
impl<T> LensView<[T; $n]> for _1Inner {
|
||||
type Field = T;
|
||||
|
||||
fn view(&self, [ $($v,)* ]: [T; $n]) -> Self::Field {
|
||||
fn view([ $($v,)* ]: [T; $n]) -> Self::Field {
|
||||
$f
|
||||
}
|
||||
}
|
||||
impl<T> LensOver<[T; $n]> for _1Inner {
|
||||
fn over<F>(
|
||||
&self,
|
||||
tup: [T; $n],
|
||||
fun: F
|
||||
) -> [T; $n]
|
||||
|
@ -79,14 +77,14 @@ macro_rules! make_arrays {
|
|||
impl<'a, T> LensView<&'a [T; $n]> for _1Inner {
|
||||
type Field = &'a T;
|
||||
|
||||
fn view(&self, [ $($v,)* ]: &'a [T; $n]) -> Self::Field {
|
||||
fn view([ $($v,)* ]: &'a [T; $n]) -> Self::Field {
|
||||
$f
|
||||
}
|
||||
}
|
||||
impl<'a, T> LensView<&'a mut [T; $n]> for _1Inner {
|
||||
type Field = &'a mut T;
|
||||
|
||||
fn view(&self, [ $($v,)* ]: &'a mut [T; $n]) -> Self::Field {
|
||||
fn view([ $($v,)* ]: &'a mut [T; $n]) -> Self::Field {
|
||||
$f
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,99 +0,0 @@
|
|||
use crate::lenses::{Lens, LensOver, LensView};
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct _2Inner;
|
||||
pub const _2: Lens<_2Inner> = Lens(_2Inner);
|
||||
|
||||
macro_rules! make_tuples {
|
||||
($f:ident, ( $( $v:ident ),* ), ( $( $t:ident ),* ) ) => {
|
||||
impl< $($t,)* > LensView<( $($t,)* )> for _2Inner {
|
||||
type Field = T;
|
||||
|
||||
fn view(&self, ( $($v,)* ): ($($t,)*)) -> Self::Field {
|
||||
$f
|
||||
}
|
||||
}
|
||||
impl< $($t,)* > LensOver<( $($t,)* )> for _2Inner {
|
||||
fn over<F>(
|
||||
&self,
|
||||
mut tup: ($($t,)*),
|
||||
f: F
|
||||
) -> ( $($t,)* )
|
||||
where
|
||||
F: FnOnce(Self::Field) -> Self::Field
|
||||
{
|
||||
tup.2 = f(tup.2);
|
||||
tup
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, $($t,)* > LensView<&'a ( $($t,)* )> for _2Inner {
|
||||
type Field = &'a T;
|
||||
|
||||
fn view(&self, ( $($v,)* ): &'a ($($t,)*)) -> Self::Field {
|
||||
$f
|
||||
}
|
||||
}
|
||||
impl<'a, $($t,)* > LensView<&'a mut ( $($t,)* )> for _2Inner {
|
||||
type Field = &'a mut T;
|
||||
|
||||
fn view(&self, ( $($v,)* ): &'a mut ($($t,)*)) -> Self::Field {
|
||||
$f
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
make_tuples!(t, (_u, _v, t), (U, V, T));
|
||||
make_tuples!(t, (_u, _v, t, _w), (U, V, T, W));
|
||||
make_tuples!(t, (_u, _v, t, _w, _x), (U, V, T, W, X));
|
||||
make_tuples!(t, (_u, _v, t, _w, _x, _y), (U, V, T, W, X, Y));
|
||||
make_tuples!(t, (_u, _v, t, _w, _x, _y, _z), (U, V, T, W, X, Y, Z));
|
||||
// not doing more cause i'm lazy, open a pr if you need more :)
|
||||
|
||||
macro_rules! make_arrays {
|
||||
($f:ident, $n:expr, [$( $v:ident ),*]) => {
|
||||
impl<T> LensView<[T; $n]> for _2Inner {
|
||||
type Field = T;
|
||||
|
||||
fn view(&self, [ $($v,)* ]: [T; $n]) -> Self::Field {
|
||||
$f
|
||||
}
|
||||
}
|
||||
impl<T> LensOver<[T; $n]> for _2Inner {
|
||||
fn over<F>(
|
||||
&self,
|
||||
tup: [T; $n],
|
||||
fun: F
|
||||
) -> [T; $n]
|
||||
where
|
||||
F: FnOnce(Self::Field) -> Self::Field
|
||||
{
|
||||
let [$($v,)*] = tup;
|
||||
let $f = fun( $f );
|
||||
[$($v,)*]
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> LensView<&'a [T; $n]> for _2Inner {
|
||||
type Field = &'a T;
|
||||
|
||||
fn view(&self, [ $($v,)* ]: &'a [T; $n]) -> Self::Field {
|
||||
$f
|
||||
}
|
||||
}
|
||||
impl<'a, T> LensView<&'a mut [T; $n]> for _2Inner {
|
||||
type Field = &'a mut T;
|
||||
|
||||
fn view(&self, [ $($v,)* ]: &'a mut [T; $n]) -> Self::Field {
|
||||
$f
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
make_arrays!(t, 3, [_a, _b, t]);
|
||||
make_arrays!(t, 4, [_a, _b, t, _c]);
|
||||
make_arrays!(t, 5, [_a, _b, t, _c, _d]);
|
||||
make_arrays!(t, 6, [_a, _b, t, _c, _d, _e]);
|
||||
make_arrays!(t, 7, [_a, _b, t, _c, _d, _e, _g]);
|
|
@ -1,52 +0,0 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use crate::lenses::{Lens, LensView};
|
||||
|
||||
use super::lens::FuncLens;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ToInner<T, U>(Arc<dyn Fn(T) -> U>);
|
||||
|
||||
impl<T, U> LensView<T> for ToInner<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_from_arc<T, U>(f: Arc<dyn Fn(T) -> U>) -> Lens<ToInner<T, U>> {
|
||||
Lens(ToInner(f))
|
||||
}
|
||||
/// Makes a lens that implements `LensView<T>` with the provided function
|
||||
pub fn to<T, U>(f: impl Fn(T) -> U + 'static) -> Lens<ToInner<T, U>> {
|
||||
Lens(ToInner(Arc::new(f)))
|
||||
}
|
||||
|
||||
impl<T, U> Lens<ToInner<T, U>> {
|
||||
/// Makes a full lens that implements `LensView<T>` and `LensOver<T>` with the provided functions
|
||||
pub fn make_lens(self, setter: impl Fn(T, U) -> T + 'static) -> Lens<FuncLens<T, U>> {
|
||||
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)))
|
||||
}
|
170
src/lib.rs
170
src/lib.rs
|
@ -1,47 +1,153 @@
|
|||
#![feature(unboxed_closures, fn_traits, const_trait_impl)]
|
||||
#![allow(clippy::type_complexity)]
|
||||
/// Base trait
|
||||
pub trait LensTrait {}
|
||||
|
||||
/// For lenses that allow viewing
|
||||
pub trait LensView<T>: LensTrait {
|
||||
type Field;
|
||||
|
||||
fn view(thing: T) -> Self::Field;
|
||||
}
|
||||
|
||||
/// For lenses that allow setting
|
||||
pub trait LensOver<T>: LensView<T> {
|
||||
fn over<F>(thing: T, f: F) -> T
|
||||
where
|
||||
F: FnOnce(Self::Field) -> Self::Field;
|
||||
|
||||
fn set(thing: T, v: Self::Field) -> T {
|
||||
Self::over(thing, |_| v)
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper type
|
||||
pub struct Lens<T: LensTrait>(T);
|
||||
|
||||
impl<L: LensTrait> LensTrait for Lens<L> {}
|
||||
impl<L, T> LensView<T> for Lens<L>
|
||||
where
|
||||
L: LensView<T>,
|
||||
{
|
||||
type Field = L::Field;
|
||||
|
||||
fn view(thing: T) -> Self::Field {
|
||||
L::view(thing)
|
||||
}
|
||||
}
|
||||
impl<L, T> LensOver<T> for Lens<L>
|
||||
where
|
||||
L: LensOver<T>,
|
||||
{
|
||||
fn over<F>(thing: T, f: F) -> T
|
||||
where
|
||||
F: FnOnce(Self::Field) -> Self::Field,
|
||||
{
|
||||
L::over(thing, f)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn view<T, L: LensView<T>>(_lens: L, thing: T) -> L::Field {
|
||||
L::view(thing)
|
||||
}
|
||||
pub fn set<T, L: LensOver<T>>(_lens: L, thing: T, v: L::Field) -> T {
|
||||
L::set(thing, v)
|
||||
}
|
||||
pub fn over<T, L: LensOver<T>>(_lens: L, thing: T, f: impl FnOnce(L::Field) -> L::Field) -> T {
|
||||
L::over(thing, f)
|
||||
}
|
||||
|
||||
mod combinations;
|
||||
|
||||
// TODO add fn impls
|
||||
|
||||
// TODO add third_from_tuple, etc
|
||||
|
||||
// TODO array traversals
|
||||
|
||||
// TODO make over work with changing types
|
||||
|
||||
pub mod combinations;
|
||||
mod fns;
|
||||
pub mod lenses;
|
||||
pub mod prisms;
|
||||
pub mod traversals;
|
||||
|
||||
pub mod prelude {
|
||||
pub use bad_optics_derive::Optics;
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{
|
||||
lenses::{_0, _1},
|
||||
*,
|
||||
};
|
||||
|
||||
pub use crate::combinations::*;
|
||||
#[test]
|
||||
fn view_first_from_tuple() {
|
||||
let a = (1, 2);
|
||||
assert_eq!(view(_0, a), 1);
|
||||
|
||||
pub use crate::lenses::*;
|
||||
pub use crate::prisms::*;
|
||||
pub use crate::traversals::*;
|
||||
let a = (1, 2);
|
||||
assert_eq!(view(_0, &a), &1);
|
||||
|
||||
pub use crate::has_lens::*;
|
||||
}
|
||||
let mut a = (1, 2);
|
||||
assert_eq!(view(_0, &mut a), &mut 1);
|
||||
|
||||
pub mod has_lens {
|
||||
use crate::prelude::{lens::FuncLens, lens_with_ref::LensWithRef, to::ToRefInner};
|
||||
let a = (1, 2, 3);
|
||||
assert_eq!(view(_0, a), 1);
|
||||
|
||||
use super::prelude::*;
|
||||
|
||||
pub trait HasLens {
|
||||
type Lenses;
|
||||
let a = (1, 2, 3);
|
||||
assert_eq!(view(_0, &a), &1);
|
||||
}
|
||||
|
||||
pub trait HasLensOf<T>: Sized {
|
||||
fn get() -> Vec<Lens<LensWithRef<Lens<FuncLens<Self, T>>, Lens<ToRefInner<Self, T>>, Self>>>;
|
||||
#[test]
|
||||
fn view_first_from_tuple_mut_works() {
|
||||
let mut a = (1, 2);
|
||||
*view(_0, &mut a) += 1;
|
||||
|
||||
assert_eq!(a, (2, 2));
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! lens {
|
||||
($name:ident :: $func:ident) => {
|
||||
<$name as HasLens>::Lenses::$func()
|
||||
};
|
||||
#[test]
|
||||
fn set_first_from_tuple() {
|
||||
let a = (1, 2);
|
||||
let a = set(_0, a, 3);
|
||||
assert_eq!(a, (3, 2));
|
||||
}
|
||||
#[macro_export]
|
||||
macro_rules! lenses {
|
||||
($name:ident :: $ty:ident) => {
|
||||
<$name as HasLensOf<$ty>>::get()
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn over_first_from_tuple() {
|
||||
let a = (1, 2);
|
||||
let a = over(_0, a, |v| v + 1);
|
||||
assert_eq!(a, (2, 2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn over_first_from_array() {
|
||||
let a = [1, 2, 3, 4];
|
||||
|
||||
let a = over(_0, a, |v| v + 1);
|
||||
assert_eq!(a, [2, 2, 3, 4]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn second() {
|
||||
let a = (1, 2);
|
||||
let a = over(_1, a, |v| v + 1);
|
||||
assert_eq!(a, (1, 3));
|
||||
|
||||
let a = [1, 2, 3, 4];
|
||||
let a = over(_1, a, |v| v + 1);
|
||||
assert_eq!(a, [1, 3, 3, 4]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn view_combination() {
|
||||
let a = ((1, 2), 3);
|
||||
|
||||
let lens = _0 + _1;
|
||||
let a = view(lens, a);
|
||||
assert_eq!(a, 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn over_combination() {
|
||||
let a = ((1, 2), 3);
|
||||
|
||||
let lens = _0 + _1;
|
||||
let a = over(lens, a, |v| v + 1);
|
||||
assert_eq!(a, ((1, 3), 3));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,117 +0,0 @@
|
|||
pub mod result;
|
||||
pub use result::{_Err, _Ok};
|
||||
|
||||
pub mod option;
|
||||
pub use option::{_None, _Some};
|
||||
|
||||
/// Wrapper type
|
||||
#[derive(Clone, Copy)]
|
||||
#[repr(transparent)]
|
||||
pub struct Prism<P>(pub(crate) P);
|
||||
|
||||
pub trait PrismPreview<T> {
|
||||
type Field;
|
||||
|
||||
fn preview(&self, thing: T) -> Option<Self::Field>;
|
||||
fn review(&self, thing: Self::Field) -> T;
|
||||
|
||||
// TODO id like for this to not need clone
|
||||
fn over<F>(&self, thing: T, f: F) -> T
|
||||
where
|
||||
F: FnOnce(Self::Field) -> Self::Field,
|
||||
T: Clone,
|
||||
{
|
||||
Self::preview(self, thing.clone()).map_or(thing, |a| Self::review(self, f(a)))
|
||||
}
|
||||
|
||||
fn set(&self, thing: T, v: Self::Field) -> T
|
||||
where
|
||||
T: Clone,
|
||||
Self::Field: Clone,
|
||||
{
|
||||
Self::over(self, thing, move |_| v)
|
||||
}
|
||||
}
|
||||
|
||||
impl<P, T> PrismPreview<T> for Prism<P>
|
||||
where
|
||||
P: PrismPreview<T>,
|
||||
{
|
||||
type Field = P::Field;
|
||||
|
||||
fn preview(&self, thing: T) -> Option<Self::Field> {
|
||||
P::preview(&self.0, thing)
|
||||
}
|
||||
|
||||
fn review(&self, thing: Self::Field) -> T {
|
||||
P::review(&self.0, thing)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn preview<T, P: PrismPreview<T>>(prism: P, thing: T) -> Option<P::Field> {
|
||||
P::preview(&prism, thing)
|
||||
}
|
||||
pub fn review<T, P: PrismPreview<T>>(prism: P, thing: P::Field) -> T {
|
||||
P::review(&prism, thing)
|
||||
}
|
||||
pub fn over<T: Clone, P: PrismPreview<T>>(
|
||||
prism: P,
|
||||
thing: T,
|
||||
f: impl FnOnce(P::Field) -> P::Field,
|
||||
) -> T {
|
||||
P::over(&prism, thing, f)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn preview_result() {
|
||||
let a: Result<i32, i32> = Ok(3);
|
||||
assert_eq!(_Ok(a), Some(3));
|
||||
|
||||
let a: Result<i32, i32> = Err(3);
|
||||
assert_eq!(preview(_Ok, a), None);
|
||||
|
||||
let a: Result<i32, i32> = Ok(3);
|
||||
assert_eq!(_Err(a), None);
|
||||
|
||||
let a: Result<i32, i32> = Err(3);
|
||||
assert_eq!(preview(_Err, a), Some(3));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn preview_option() {
|
||||
let a = Some(3);
|
||||
assert_eq!(_Some(a), Some(3));
|
||||
|
||||
let a = Some(3);
|
||||
assert_eq!(preview(_None, a), Some(()));
|
||||
|
||||
let a: Option<i32> = None;
|
||||
assert_eq!(preview(_Some, a), None);
|
||||
|
||||
let a: Option<i32> = None;
|
||||
assert_eq!(preview(_None, a), Some(()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn review_result() {
|
||||
assert_eq!(review(_Ok, 3), Ok::<i32, i32>(3));
|
||||
assert_eq!(review(_Err, 3), Err::<i32, i32>(3));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn review_option() {
|
||||
assert_eq!(review(_Some, 3), Some(3));
|
||||
assert_eq!(review(_None, ()), None::<()>);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn over_option() {
|
||||
assert_eq!(over(_Some, Some(3), |v| v + 1), Some(4));
|
||||
assert_eq!(_Some(Some(3), |v| v + 1), Some(4));
|
||||
assert_eq!(over(_None, None, |_v: ()| ()), None::<()>);
|
||||
}
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
use super::*;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct SomeInner;
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const _Some: Prism<SomeInner> = Prism(SomeInner);
|
||||
|
||||
impl<T> PrismPreview<Option<T>> for SomeInner {
|
||||
type Field = T;
|
||||
|
||||
fn preview(&self, thing: Option<T>) -> Option<Self::Field> {
|
||||
thing
|
||||
}
|
||||
|
||||
fn review(&self, thing: Self::Field) -> Option<T> {
|
||||
Some(thing)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct NoneInner;
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const _None: Prism<NoneInner> = Prism(NoneInner);
|
||||
impl<T> PrismPreview<Option<T>> for NoneInner {
|
||||
type Field = ();
|
||||
|
||||
fn preview(&self, _thing: Option<T>) -> Option<Self::Field> {
|
||||
Some(())
|
||||
}
|
||||
|
||||
fn review(&self, _thing: Self::Field) -> Option<T> {
|
||||
None
|
||||
}
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
use super::*;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct OkInner;
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const _Ok: Prism<OkInner> = Prism(OkInner);
|
||||
impl<T, E> PrismPreview<Result<T, E>> for OkInner {
|
||||
type Field = T;
|
||||
|
||||
fn preview(&self, thing: Result<T, E>) -> Option<Self::Field> {
|
||||
thing.ok()
|
||||
}
|
||||
fn review(&self, thing: Self::Field) -> Result<T, E> {
|
||||
Ok(thing)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct ErrInner;
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const _Err: Prism<ErrInner> = Prism(ErrInner);
|
||||
|
||||
impl<T, E> PrismPreview<Result<T, E>> for ErrInner {
|
||||
type Field = E;
|
||||
|
||||
fn preview(&self, thing: Result<T, E>) -> Option<Self::Field> {
|
||||
thing.err()
|
||||
}
|
||||
fn review(&self, thing: Self::Field) -> Result<T, E> {
|
||||
Err(thing)
|
||||
}
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
use crate::traversals::{Traversal, TraversalOver, TraversalTraverse};
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct BothInner;
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const both: Traversal<BothInner> = Traversal(BothInner);
|
||||
|
||||
impl<T> TraversalTraverse<(T, T)> for BothInner {
|
||||
type Field = T;
|
||||
|
||||
fn traverse(&self, (a, b): (T, T)) -> Vec<Self::Field> {
|
||||
vec![a, b]
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> TraversalOver<(T, T)> for BothInner {
|
||||
fn over<F>(&self, (a, b): (T, T), mut f: F) -> (T, T)
|
||||
where
|
||||
F: FnMut(Self::Field) -> Self::Field,
|
||||
{
|
||||
(f(a), f(b))
|
||||
}
|
||||
}
|
|
@ -1,146 +0,0 @@
|
|||
use crate::traversals::{Traversal, TraversalOver, TraversalTraverse};
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct EachInner;
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const each: Traversal<EachInner> = Traversal(EachInner);
|
||||
|
||||
impl<T> TraversalTraverse<Vec<T>> for EachInner {
|
||||
type Field = T;
|
||||
|
||||
fn traverse(&self, thing: Vec<T>) -> Vec<Self::Field> {
|
||||
thing
|
||||
}
|
||||
}
|
||||
impl<T> TraversalOver<Vec<T>> for EachInner {
|
||||
fn over<F>(&self, thing: Vec<T>, f: F) -> Vec<T>
|
||||
where
|
||||
F: FnMut(Self::Field) -> Self::Field,
|
||||
{
|
||||
thing.into_iter().map(f).collect()
|
||||
}
|
||||
}
|
||||
|
||||
// TODO i'd like to have this so we get it for free on any iterable
|
||||
// problem is, arrays/tuples don't implement FromIter
|
||||
// and having both the blanket implementation and the one below complains cause
|
||||
// other crates could add the trait in the future
|
||||
|
||||
// impl<I, T> TraversalTraverse<I> for EachInner
|
||||
// where
|
||||
// I: IntoIterator<Item = T>,
|
||||
// {
|
||||
// type Field = T;
|
||||
|
||||
// fn traverse(&self, thing: I) -> Vec<Self::Field> {
|
||||
// thing.into_iter().collect()
|
||||
// }
|
||||
// }
|
||||
|
||||
// impl<I, T> TraversalOver<I> for EachInner
|
||||
// where
|
||||
// I: IntoIterator<Item = T> + FromIterator<T>,
|
||||
// {
|
||||
// fn over<F>(&self, thing: I, f: F) -> I
|
||||
// where
|
||||
// F: FnMut(Self::Field) -> Self::Field,
|
||||
// {
|
||||
// thing.into_iter().map(f).collect()
|
||||
// }
|
||||
// }
|
||||
|
||||
macro_rules! make_tuples {
|
||||
($f:ident, ( $( $v:ident ),* ), ( $( $t:ident ),* ) ) => {
|
||||
impl<T> TraversalTraverse<( $($t,)* )> for EachInner {
|
||||
type Field = T;
|
||||
|
||||
fn traverse(&self, ( $($v,)* ): ($($t,)*)) -> Vec<Self::Field> {
|
||||
vec![ $($v,)* ]
|
||||
}
|
||||
}
|
||||
impl<T> TraversalOver<( $($t,)* )> for EachInner {
|
||||
fn over<F>(
|
||||
&self,
|
||||
($($v,)*): ($($t,)*),
|
||||
mut f: F
|
||||
) -> ( $($t,)* )
|
||||
where
|
||||
F: FnMut(Self::Field) -> Self::Field
|
||||
{
|
||||
|
||||
( $( f($v), )* )
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> TraversalTraverse<&'a ( $($t,)* )> for EachInner {
|
||||
type Field = &'a T;
|
||||
|
||||
fn traverse(&self, ( $($v,)* ): &'a ($($t,)*)) -> Vec<Self::Field> {
|
||||
vec![ $($v,)* ]
|
||||
}
|
||||
}
|
||||
impl<'a, T> TraversalTraverse<&'a mut ( $($t,)* )> for EachInner {
|
||||
type Field = &'a mut T;
|
||||
|
||||
fn traverse(&self, ( $($v,)* ): &'a mut ($($t,)*)) -> Vec<Self::Field> {
|
||||
vec![ $($v,)* ]
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
make_tuples!(t, (t), (T));
|
||||
make_tuples!(t, (t, u), (T, T));
|
||||
make_tuples!(t, (t, u, v), (T, T, T));
|
||||
make_tuples!(t, (t, u, v, w), (T, T, T, T));
|
||||
make_tuples!(t, (t, u, v, w, x), (T, T, T, T, T));
|
||||
make_tuples!(t, (t, u, v, w, x, y), (T, T, T, T, T, T));
|
||||
make_tuples!(t, (t, u, v, w, x, y, z), (T, T, T, T, T, T, T));
|
||||
// not doing more cause i'm lazy, open a pr if you need more :)
|
||||
|
||||
macro_rules! make_arrays {
|
||||
($f:ident, $n:expr, [$( $v:ident ),*]) => {
|
||||
impl<T> TraversalTraverse<[T; $n]> for EachInner {
|
||||
type Field = T;
|
||||
|
||||
fn traverse(&self, [ $($v,)* ]: [T; $n]) -> Vec<Self::Field> {
|
||||
vec![ $($v,)* ]
|
||||
}
|
||||
}
|
||||
impl<T> TraversalOver<[T; $n]> for EachInner {
|
||||
fn over<F>(
|
||||
&self,
|
||||
[ $($v,)* ]: [T; $n],
|
||||
mut fun: F
|
||||
) -> [T; $n]
|
||||
where
|
||||
F: FnMut(Self::Field) -> Self::Field
|
||||
{
|
||||
[$(fun($v),)*]
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> TraversalTraverse<&'a [T; $n]> for EachInner {
|
||||
type Field = &'a T;
|
||||
|
||||
fn traverse(&self, [ $($v,)* ]: &'a [T; $n]) -> Vec<Self::Field> {
|
||||
vec![ $($v,)* ]
|
||||
}
|
||||
}
|
||||
impl<'a, T> TraversalTraverse<&'a mut [T; $n]> for EachInner {
|
||||
type Field = &'a mut T;
|
||||
|
||||
fn traverse(&self, [ $($v,)* ]: &'a mut [T; $n]) -> Vec<Self::Field> {
|
||||
vec![ $($v,)* ]
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
make_arrays!(t, 1, [t]);
|
||||
make_arrays!(t, 2, [t, _a]);
|
||||
make_arrays!(t, 3, [t, _a, _b]);
|
||||
make_arrays!(t, 4, [t, _a, _b, _c]);
|
||||
make_arrays!(t, 5, [t, _a, _b, _c, _d]);
|
||||
make_arrays!(t, 6, [t, _a, _b, _c, _d, _e]);
|
||||
make_arrays!(t, 7, [t, _a, _b, _c, _d, _e, _g]);
|
|
@ -1,101 +0,0 @@
|
|||
use crate::traversals::{Traversal, TraversalOver, TraversalTraverse};
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct HeadInner;
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const _head: Traversal<HeadInner> = Traversal(HeadInner);
|
||||
|
||||
macro_rules! make_tuples {
|
||||
(( $( $v:ident ),* ), ( $( $t:ident ),* ) ) => {
|
||||
impl< $($t,)* > TraversalTraverse<( $($t,)* )> for HeadInner {
|
||||
type Field = T;
|
||||
|
||||
fn traverse(&self, ( head, $($v,)* ): ($($t,)*)) -> Vec<Self::Field> {
|
||||
vec![head]
|
||||
}
|
||||
}
|
||||
impl< $($t,)* > TraversalOver<( $($t,)* )> for HeadInner {
|
||||
fn over<F>(
|
||||
&self,
|
||||
(head, $($v,)*): ($($t,)*),
|
||||
mut f: F
|
||||
) -> ( $($t,)* )
|
||||
where
|
||||
F: FnMut(Self::Field) -> Self::Field
|
||||
{
|
||||
|
||||
( f(head), $($v,)* )
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, $($t,)* > TraversalTraverse<&'a ( $($t,)* )> for HeadInner {
|
||||
type Field = &'a T;
|
||||
|
||||
fn traverse(&self, (head, $($v,)* ): &'a ($($t,)*)) -> Vec<Self::Field> {
|
||||
vec![ head ]
|
||||
}
|
||||
}
|
||||
impl<'a, $($t,)* > TraversalTraverse<&'a mut ( $($t,)* )> for HeadInner {
|
||||
type Field = &'a mut T;
|
||||
|
||||
fn traverse(&self, (head, $($v,)* ): &'a mut ($($t,)*)) -> Vec<Self::Field> {
|
||||
vec![ head ]
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
make_tuples!((), (T));
|
||||
make_tuples!((_u), (T, U));
|
||||
make_tuples!((_u, _v), (T, U, V));
|
||||
make_tuples!((_u, _v, _w), (T, U, V, W));
|
||||
make_tuples!((_u, _v, _w, _x), (T, U, V, W, X));
|
||||
make_tuples!((_u, _v, _w, _x, _y), (T, U, V, W, X, Y));
|
||||
make_tuples!((_u, _v, _w, _x, _y, _z), (T, U, V, W, X, Y, Z));
|
||||
|
||||
macro_rules! make_arrays {
|
||||
($n:expr, [$( $v:ident ),*]) => {
|
||||
impl<T> TraversalTraverse<[T; $n]> for HeadInner {
|
||||
type Field = T;
|
||||
|
||||
fn traverse(&self, [ head, $($v,)* ]: [T; $n]) -> Vec<Self::Field> {
|
||||
vec![head]
|
||||
}
|
||||
}
|
||||
impl<T> TraversalOver<[T; $n]> for HeadInner {
|
||||
fn over<F>(
|
||||
&self,
|
||||
[ head, $($v,)* ]: [T; $n],
|
||||
mut fun: F
|
||||
) -> [T; $n]
|
||||
where
|
||||
F: FnMut(Self::Field) -> Self::Field
|
||||
{
|
||||
[fun(head), $(($v),)*]
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> TraversalTraverse<&'a [T; $n]> for HeadInner {
|
||||
type Field = &'a T;
|
||||
|
||||
fn traverse(&self, [head, $($v,)* ]: &'a [T; $n]) -> Vec<Self::Field> {
|
||||
vec![head]
|
||||
}
|
||||
}
|
||||
impl<'a, T> TraversalTraverse<&'a mut [T; $n]> for HeadInner {
|
||||
type Field = &'a mut T;
|
||||
|
||||
fn traverse(&self, [head, $($v,)* ]: &'a mut [T; $n]) -> Vec<Self::Field> {
|
||||
vec![head]
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
make_arrays!(1, []);
|
||||
make_arrays!(2, [_a]);
|
||||
make_arrays!(3, [_a, _b]);
|
||||
make_arrays!(4, [_a, _b, _c]);
|
||||
make_arrays!(5, [_a, _b, _c, _d]);
|
||||
make_arrays!(6, [_a, _b, _c, _d, _e]);
|
||||
make_arrays!(7, [_a, _b, _c, _d, _e, _g]);
|
|
@ -1,98 +0,0 @@
|
|||
use crate::traversals::{Traversal, TraversalOver, TraversalTraverse};
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct InitInner;
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const _init: Traversal<InitInner> = Traversal(InitInner);
|
||||
|
||||
macro_rules! make_tuples {
|
||||
(( $( $v:ident ),* ), ( $( $t:ident ),* ) ) => {
|
||||
impl<T> TraversalTraverse<( $($t,)* )> for InitInner {
|
||||
type Field = T;
|
||||
|
||||
fn traverse(&self, ( $($v,)* _last ): ($($t,)*)) -> Vec<Self::Field> {
|
||||
vec![ $($v,)* ]
|
||||
}
|
||||
}
|
||||
impl<T> TraversalOver<( $($t,)* )> for InitInner {
|
||||
fn over<F>(
|
||||
&self,
|
||||
($($v,)* last): ($($t,)*),
|
||||
mut f: F
|
||||
) -> ( $($t,)* )
|
||||
where
|
||||
F: FnMut(Self::Field) -> Self::Field
|
||||
{
|
||||
( $(f($v),)* last )
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> TraversalTraverse<&'a ( $($t,)* )> for InitInner {
|
||||
type Field = &'a T;
|
||||
|
||||
fn traverse(&self, ($($v,)* _last): &'a ($($t,)*)) -> Vec<Self::Field> {
|
||||
vec![ $($v,)* ]
|
||||
}
|
||||
}
|
||||
impl<'a, T> TraversalTraverse<&'a mut ( $($t,)* )> for InitInner {
|
||||
type Field = &'a mut T;
|
||||
|
||||
fn traverse(&self, ($($v,)* _last): &'a mut ($($t,)*)) -> Vec<Self::Field> {
|
||||
vec![ $($v,)* ]
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
make_tuples!((_u), (T, T));
|
||||
make_tuples!((_u, _v), (T, T, T));
|
||||
make_tuples!((_u, _v, _w), (T, T, T, T));
|
||||
make_tuples!((_u, _v, _w, _x), (T, T, T, T, T));
|
||||
make_tuples!((_u, _v, _w, _x, _y), (T, T, T, T, T, T));
|
||||
make_tuples!((_u, _v, _w, _x, _y, _z), (T, T, T, T, T, T, T));
|
||||
|
||||
macro_rules! make_arrays {
|
||||
($n:expr, [$( $v:ident ),*]) => {
|
||||
impl<T> TraversalTraverse<[T; $n]> for InitInner {
|
||||
type Field = T;
|
||||
|
||||
fn traverse(&self, [ $($v,)* _last]: [T; $n]) -> Vec<Self::Field> {
|
||||
vec![ $($v,)* ]
|
||||
}
|
||||
}
|
||||
impl<T> TraversalOver<[T; $n]> for InitInner {
|
||||
fn over<F>(
|
||||
&self,
|
||||
[ $($v,)* last]: [T; $n],
|
||||
mut fun: F
|
||||
) -> [T; $n]
|
||||
where
|
||||
F: FnMut(Self::Field) -> Self::Field
|
||||
{
|
||||
[$(fun($v),)* last]
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> TraversalTraverse<&'a [T; $n]> for InitInner {
|
||||
type Field = &'a T;
|
||||
|
||||
fn traverse(&self, [$($v,)* _last]: &'a [T; $n]) -> Vec<Self::Field> {
|
||||
vec![ $($v,)* ]
|
||||
}
|
||||
}
|
||||
impl<'a, T> TraversalTraverse<&'a mut [T; $n]> for InitInner {
|
||||
type Field = &'a mut T;
|
||||
|
||||
fn traverse(&self, [$($v,)* _last ]: &'a mut [T; $n]) -> Vec<Self::Field> {
|
||||
vec![ $($v,)* ]
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
make_arrays!(2, [_a]);
|
||||
make_arrays!(3, [_a, _b]);
|
||||
make_arrays!(4, [_a, _b, _c]);
|
||||
make_arrays!(5, [_a, _b, _c, _d]);
|
||||
make_arrays!(6, [_a, _b, _c, _d, _e]);
|
||||
make_arrays!(7, [_a, _b, _c, _d, _e, _g]);
|
|
@ -1,99 +0,0 @@
|
|||
use crate::traversals::{Traversal, TraversalOver, TraversalTraverse};
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct LastInner;
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const _last: Traversal<LastInner> = Traversal(LastInner);
|
||||
|
||||
macro_rules! make_tuples {
|
||||
(( $( $v:ident ),* ), ( $( $t:ident ),* ) ) => {
|
||||
impl<T> TraversalTraverse<( $($t,)* )> for LastInner {
|
||||
type Field = T;
|
||||
|
||||
fn traverse(&self, ( $($v,)* last ): ($($t,)*)) -> Vec<Self::Field> {
|
||||
vec![ last ]
|
||||
}
|
||||
}
|
||||
impl<T> TraversalOver<( $($t,)* )> for LastInner {
|
||||
fn over<F>(
|
||||
&self,
|
||||
($($v,)* last): ($($t,)*),
|
||||
mut f: F
|
||||
) -> ( $($t,)* )
|
||||
where
|
||||
F: FnMut(Self::Field) -> Self::Field
|
||||
{
|
||||
( $($v,)* f(last), )
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> TraversalTraverse<&'a ( $($t,)* )> for LastInner {
|
||||
type Field = &'a T;
|
||||
|
||||
fn traverse(&self, ($($v,)* last): &'a ($($t,)*)) -> Vec<Self::Field> {
|
||||
vec![ last ]
|
||||
}
|
||||
}
|
||||
impl<'a, T> TraversalTraverse<&'a mut ( $($t,)* )> for LastInner {
|
||||
type Field = &'a mut T;
|
||||
|
||||
fn traverse(&self, ($($v,)* last): &'a mut ($($t,)*)) -> Vec<Self::Field> {
|
||||
vec![ last ]
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
make_tuples!((_u), (T, T));
|
||||
make_tuples!((_u, _v), (T, T, T));
|
||||
make_tuples!((_u, _v, _w), (T, T, T, T));
|
||||
make_tuples!((_u, _v, _w, _x), (T, T, T, T, T));
|
||||
make_tuples!((_u, _v, _w, _x, _y), (T, T, T, T, T, T));
|
||||
make_tuples!((_u, _v, _w, _x, _y, _z), (T, T, T, T, T, T, T));
|
||||
|
||||
macro_rules! make_arrays {
|
||||
($n:expr, [$( $v:ident ),*]) => {
|
||||
impl<T> TraversalTraverse<[T; $n]> for LastInner {
|
||||
type Field = T;
|
||||
|
||||
fn traverse(&self, [ $($v,)* last]: [T; $n]) -> Vec<Self::Field> {
|
||||
vec![ last ]
|
||||
}
|
||||
}
|
||||
impl<T> TraversalOver<[T; $n]> for LastInner {
|
||||
fn over<F>(
|
||||
&self,
|
||||
[ $($v,)* last]: [T; $n],
|
||||
mut fun: F
|
||||
) -> [T; $n]
|
||||
where
|
||||
F: FnMut(Self::Field) -> Self::Field
|
||||
{
|
||||
[$(($v),)* fun(last)]
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> TraversalTraverse<&'a [T; $n]> for LastInner {
|
||||
type Field = &'a T;
|
||||
|
||||
fn traverse(&self, [$($v,)* last]: &'a [T; $n]) -> Vec<Self::Field> {
|
||||
vec![ last ]
|
||||
}
|
||||
}
|
||||
impl<'a, T> TraversalTraverse<&'a mut [T; $n]> for LastInner {
|
||||
type Field = &'a mut T;
|
||||
|
||||
fn traverse(&self, [ $($v,)* last ]: &'a mut [T; $n]) -> Vec<Self::Field> {
|
||||
vec![ last ]
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
make_arrays!(1, []);
|
||||
make_arrays!(2, [_a]);
|
||||
make_arrays!(3, [_a, _b]);
|
||||
make_arrays!(4, [_a, _b, _c]);
|
||||
make_arrays!(5, [_a, _b, _c, _d]);
|
||||
make_arrays!(6, [_a, _b, _c, _d, _e]);
|
||||
make_arrays!(7, [_a, _b, _c, _d, _e, _g]);
|
|
@ -1,211 +0,0 @@
|
|||
pub mod both;
|
||||
pub use both::both;
|
||||
|
||||
pub mod each;
|
||||
pub use each::each;
|
||||
|
||||
pub mod head;
|
||||
pub use head::_head;
|
||||
pub mod tail;
|
||||
pub use tail::_tail;
|
||||
|
||||
pub mod init;
|
||||
pub use init::_init;
|
||||
pub mod last;
|
||||
pub use last::_last;
|
||||
|
||||
use crate::{
|
||||
lenses::{Lens, LensOver, LensView},
|
||||
prisms::{Prism, PrismPreview},
|
||||
};
|
||||
|
||||
/// Wrapper type
|
||||
#[derive(Clone, Copy)]
|
||||
#[repr(transparent)]
|
||||
pub struct Traversal<T>(pub(crate) T);
|
||||
|
||||
pub trait TraversalTraverse<T> {
|
||||
type Field;
|
||||
|
||||
fn traverse(&self, thing: T) -> Vec<Self::Field>;
|
||||
}
|
||||
pub trait TraversalOver<T>: TraversalTraverse<T> {
|
||||
fn over<F>(&self, thing: T, f: F) -> T
|
||||
where
|
||||
F: FnMut(Self::Field) -> Self::Field;
|
||||
|
||||
fn set(&self, thing: T, v: Self::Field) -> T
|
||||
where
|
||||
Self::Field: Clone,
|
||||
{
|
||||
Self::over(self, thing, move |_| v.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl<L, T> TraversalTraverse<T> for Traversal<L>
|
||||
where
|
||||
L: TraversalTraverse<T>,
|
||||
{
|
||||
type Field = L::Field;
|
||||
|
||||
fn traverse(&self, thing: T) -> Vec<Self::Field> {
|
||||
L::traverse(&self.0, thing)
|
||||
}
|
||||
}
|
||||
impl<L, T> TraversalOver<T> for Traversal<L>
|
||||
where
|
||||
L: TraversalOver<T>,
|
||||
{
|
||||
fn over<F>(&self, thing: T, f: F) -> T
|
||||
where
|
||||
F: FnMut(Self::Field) -> Self::Field,
|
||||
{
|
||||
L::over(&self.0, thing, f)
|
||||
}
|
||||
}
|
||||
|
||||
// all lenses are traversals, so we can freely transform them into a traversal
|
||||
impl<L> Lens<L> {
|
||||
/// Returns this lens as a traversal
|
||||
pub const fn to_traversal(self) -> Traversal<Lens<L>> {
|
||||
Traversal(self)
|
||||
}
|
||||
}
|
||||
// we can go back to a lens from a "traversal-ed" lens
|
||||
impl<L> Traversal<Lens<L>> {
|
||||
/// Returns the wrapped lens
|
||||
pub fn to_lens(self) -> Lens<L> {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
impl<L, T> TraversalTraverse<T> for Lens<L>
|
||||
where
|
||||
L: LensView<T>,
|
||||
{
|
||||
type Field = L::Field;
|
||||
|
||||
fn traverse(&self, thing: T) -> Vec<Self::Field> {
|
||||
vec![L::view(&self.0, thing)]
|
||||
}
|
||||
}
|
||||
impl<L, T> TraversalOver<T> for Lens<L>
|
||||
where
|
||||
L: LensView<T> + LensOver<T>,
|
||||
{
|
||||
fn over<F>(&self, thing: T, f: F) -> T
|
||||
where
|
||||
F: FnMut(Self::Field) -> Self::Field,
|
||||
{
|
||||
L::over(&self.0, thing, f)
|
||||
}
|
||||
}
|
||||
|
||||
// all prisms are traversals, so we can freely transform them into a traversal
|
||||
impl<L> Prism<L> {
|
||||
/// Returns this lens as a traversal
|
||||
pub const fn to_traversal(self) -> Traversal<Prism<L>> {
|
||||
Traversal(self)
|
||||
}
|
||||
}
|
||||
// we can go back to a lens from a "traversal-ed" lens
|
||||
impl<L> Traversal<Prism<L>> {
|
||||
/// Returns the wrapped lens
|
||||
pub fn to_prism(self) -> Prism<L> {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
impl<L, T> TraversalTraverse<T> for Prism<L>
|
||||
where
|
||||
L: PrismPreview<T>,
|
||||
{
|
||||
type Field = L::Field;
|
||||
|
||||
fn traverse(&self, thing: T) -> Vec<Self::Field> {
|
||||
L::preview(&self.0, thing).into_iter().collect()
|
||||
}
|
||||
}
|
||||
impl<L, T> TraversalOver<T> for Prism<L>
|
||||
where
|
||||
T: Clone,
|
||||
L: PrismPreview<T>,
|
||||
{
|
||||
fn over<F>(&self, thing: T, f: F) -> T
|
||||
where
|
||||
F: FnMut(Self::Field) -> Self::Field,
|
||||
{
|
||||
L::over(&self.0, thing, f)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn traverse<T, L: TraversalTraverse<T>>(lens: L, thing: T) -> Vec<L::Field> {
|
||||
L::traverse(&lens, thing)
|
||||
}
|
||||
pub fn set<T, L: TraversalOver<T>>(lens: L, thing: T, v: L::Field) -> T
|
||||
where
|
||||
<L as TraversalTraverse<T>>::Field: Clone,
|
||||
{
|
||||
L::set(&lens, thing, v)
|
||||
}
|
||||
pub fn over<T, L: TraversalOver<T>>(lens: L, thing: T, f: impl FnMut(L::Field) -> L::Field) -> T {
|
||||
L::over(&lens, thing, f)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn traverse_each_works_on_arrays() {
|
||||
let array = [1, 2, 3, 4];
|
||||
|
||||
let res = each(array);
|
||||
assert_eq!(res, vec![1, 2, 3, 4,]);
|
||||
|
||||
let res = each(array, |v| v + 1);
|
||||
assert_eq!(res, [2, 3, 4, 5]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn traverse_head_works_on_arrays() {
|
||||
let array = [1, 2, 3, 4];
|
||||
|
||||
let res = _head(array);
|
||||
assert_eq!(res, vec![1,]);
|
||||
|
||||
let res = _head(array, |v| v + 1);
|
||||
assert_eq!(res, [2, 2, 3, 4,]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn traverse_tail_works_on_arrays() {
|
||||
let array = [1, 2, 3, 4];
|
||||
|
||||
let res = _tail(array);
|
||||
assert_eq!(res, vec![2, 3, 4]);
|
||||
|
||||
let res = _tail(array, |v| v + 1);
|
||||
assert_eq!(res, [1, 3, 4, 5]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn traverse_init_works_on_arrays() {
|
||||
let array = [1, 2, 3, 4];
|
||||
|
||||
let res = _init(array);
|
||||
assert_eq!(res, vec![1, 2, 3]);
|
||||
|
||||
let res = _init(array, |v| v + 1);
|
||||
assert_eq!(res, [2, 3, 4, 4,]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn traverse_last_works_on_arrays() {
|
||||
let array = [1, 2, 3, 4];
|
||||
|
||||
let res = _last(array);
|
||||
assert_eq!(res, vec![4]);
|
||||
|
||||
let res = _last(array, |v| v + 1);
|
||||
assert_eq!(res, [1, 2, 3, 5]);
|
||||
}
|
||||
}
|
|
@ -1,98 +0,0 @@
|
|||
use crate::traversals::{Traversal, TraversalOver, TraversalTraverse};
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct TailInner;
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const _tail: Traversal<TailInner> = Traversal(TailInner);
|
||||
|
||||
macro_rules! make_tuples {
|
||||
(( $( $v:ident ),* ), ( $( $t:ident ),* ) ) => {
|
||||
impl<T> TraversalTraverse<( $($t,)* )> for TailInner {
|
||||
type Field = T;
|
||||
|
||||
fn traverse(&self, ( _, $($v,)* ): ($($t,)*)) -> Vec<Self::Field> {
|
||||
vec![$($v,)*]
|
||||
}
|
||||
}
|
||||
impl<T> TraversalOver<( $($t,)* )> for TailInner {
|
||||
fn over<F>(
|
||||
&self,
|
||||
(head, $($v,)*): ($($t,)*),
|
||||
mut fun: F
|
||||
) -> ( $($t,)* )
|
||||
where
|
||||
F: FnMut(Self::Field) -> Self::Field
|
||||
{
|
||||
(head, $( fun($v) ,)*)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> TraversalTraverse<&'a ( $($t,)* )> for TailInner {
|
||||
type Field = &'a T;
|
||||
|
||||
fn traverse(&self, (_, $($v,)* ): &'a ($($t,)*)) -> Vec<Self::Field> {
|
||||
vec![ $($v,)* ]
|
||||
}
|
||||
}
|
||||
impl<'a, T> TraversalTraverse<&'a mut ( $($t,)* )> for TailInner {
|
||||
type Field = &'a mut T;
|
||||
|
||||
fn traverse(&self, (_, $($v,)* ): &'a mut ($($t,)*)) -> Vec<Self::Field> {
|
||||
vec![ $($v,)* ]
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
make_tuples!((_u), (T, T));
|
||||
make_tuples!((_u, _v), (T, T, T));
|
||||
make_tuples!((_u, _v, _w), (T, T, T, T));
|
||||
make_tuples!((_u, _v, _w, _x), (T, T, T, T, T));
|
||||
make_tuples!((_u, _v, _w, _x, _y), (T, T, T, T, T, T));
|
||||
make_tuples!((_u, _v, _w, _x, _y, _z), (T, T, T, T, T, T, T));
|
||||
|
||||
macro_rules! make_arrays {
|
||||
($n:expr, [$( $v:ident ),*]) => {
|
||||
impl<T> TraversalTraverse<[T; $n]> for TailInner {
|
||||
type Field = T;
|
||||
|
||||
fn traverse(&self, [ _, $($v,)* ]: [T; $n]) -> Vec<Self::Field> {
|
||||
vec![$($v,)*]
|
||||
}
|
||||
}
|
||||
impl<T> TraversalOver<[T; $n]> for TailInner {
|
||||
fn over<F>(
|
||||
&self,
|
||||
[ head, $($v,)* ]: [T; $n],
|
||||
mut fun: F
|
||||
) -> [T; $n]
|
||||
where
|
||||
F: FnMut(Self::Field) -> Self::Field
|
||||
{
|
||||
[head, $(fun($v),)*]
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> TraversalTraverse<&'a [T; $n]> for TailInner {
|
||||
type Field = &'a T;
|
||||
|
||||
fn traverse(&self, [_, $($v,)* ]: &'a [T; $n]) -> Vec<Self::Field> {
|
||||
vec![$($v,)*]
|
||||
}
|
||||
}
|
||||
impl<'a, T> TraversalTraverse<&'a mut [T; $n]> for TailInner {
|
||||
type Field = &'a mut T;
|
||||
|
||||
fn traverse(&self, [_, $($v,)* ]: &'a mut [T; $n]) -> Vec<Self::Field> {
|
||||
vec![$($v,)*]
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
make_arrays!(2, [_a]);
|
||||
make_arrays!(3, [_a, _b]);
|
||||
make_arrays!(4, [_a, _b, _c]);
|
||||
make_arrays!(5, [_a, _b, _c, _d]);
|
||||
make_arrays!(6, [_a, _b, _c, _d, _e]);
|
||||
make_arrays!(7, [_a, _b, _c, _d, _e, _g]);
|
Loading…
Reference in New Issue