Compare commits
4 Commits
16d7190a1d
...
c3d76f109f
Author | SHA1 | Date |
---|---|---|
annieversary | c3d76f109f | |
annieversary | ca9d8de37f | |
annieversary | e6ac6d85fa | |
annieversary | fa60e84466 |
22
README.md
22
README.md
|
@ -1,13 +1,21 @@
|
||||||
# bad optics
|
# bad optics
|
||||||
|
|
||||||
ergonomic no-macro lenses for rust
|
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
|
## example
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
use bad_optics::{
|
use bad_optics::{
|
||||||
lenses::{_0, _1},
|
lenses::{over, set},
|
||||||
*,
|
prelude::*,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -41,6 +49,12 @@ fn main() {
|
||||||
|
|
||||||
// you can also call the lens as a function to modify the value
|
// you can also call the lens as a function to modify the value
|
||||||
let res = lens(a, |v| v + 1);
|
let res = lens(a, |v| v + 1);
|
||||||
assert_eq!(res, ((1, 3), 3));
|
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,4 +1,4 @@
|
||||||
use bad_optics::{lenses::*, prisms::*, traversals::*};
|
use bad_optics::prelude::*;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
struct MyStruct {
|
struct MyStruct {
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
use bad_optics::lenses::*;
|
use bad_optics::{
|
||||||
|
lenses::{over, set},
|
||||||
|
prelude::*,
|
||||||
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let a = ((1, 2), 3);
|
let a = ((1, 2), 3);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use bad_optics::lenses::*;
|
use bad_optics::prelude::*;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
struct MyStruct {
|
struct MyStruct {
|
||||||
|
|
|
@ -3,6 +3,7 @@ use crate::{
|
||||||
prisms::{Prism, PrismPreview},
|
prisms::{Prism, PrismPreview},
|
||||||
traversals::{Traversal, TraversalOver, TraversalTraverse},
|
traversals::{Traversal, TraversalOver, TraversalTraverse},
|
||||||
};
|
};
|
||||||
|
use std::ops::Add;
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct Combination<A, B>(A, B);
|
pub struct Combination<A, B>(A, B);
|
||||||
|
@ -10,7 +11,7 @@ pub struct Combination<A, B>(A, B);
|
||||||
// additions
|
// additions
|
||||||
|
|
||||||
// lens + lens
|
// lens + lens
|
||||||
impl<A, B> std::ops::Add<Lens<B>> for Lens<A> {
|
impl<A, B> const Add<Lens<B>> for Lens<A> {
|
||||||
type Output = Lens<Combination<Lens<A>, Lens<B>>>;
|
type Output = Lens<Combination<Lens<A>, Lens<B>>>;
|
||||||
|
|
||||||
fn add(self, rhs: Lens<B>) -> Self::Output {
|
fn add(self, rhs: Lens<B>) -> Self::Output {
|
||||||
|
@ -18,7 +19,7 @@ impl<A, B> std::ops::Add<Lens<B>> for Lens<A> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// prism + prism
|
// prism + prism
|
||||||
impl<A, B> std::ops::Add<Prism<B>> for Prism<A> {
|
impl<A, B> const Add<Prism<B>> for Prism<A> {
|
||||||
type Output = Prism<Combination<Prism<A>, Prism<B>>>;
|
type Output = Prism<Combination<Prism<A>, Prism<B>>>;
|
||||||
|
|
||||||
fn add(self, rhs: Prism<B>) -> Self::Output {
|
fn add(self, rhs: Prism<B>) -> Self::Output {
|
||||||
|
@ -26,7 +27,7 @@ impl<A, B> std::ops::Add<Prism<B>> for Prism<A> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// traversal + traversal
|
// traversal + traversal
|
||||||
impl<A, B> std::ops::Add<Traversal<B>> for Traversal<A> {
|
impl<A, B> const Add<Traversal<B>> for Traversal<A> {
|
||||||
type Output = Traversal<Combination<Traversal<A>, Traversal<B>>>;
|
type Output = Traversal<Combination<Traversal<A>, Traversal<B>>>;
|
||||||
|
|
||||||
fn add(self, rhs: Traversal<B>) -> Self::Output {
|
fn add(self, rhs: Traversal<B>) -> Self::Output {
|
||||||
|
@ -34,7 +35,7 @@ impl<A, B> std::ops::Add<Traversal<B>> for Traversal<A> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// traversal + lens
|
// traversal + lens
|
||||||
impl<A, B> std::ops::Add<Lens<B>> for Traversal<A> {
|
impl<A, B> const Add<Lens<B>> for Traversal<A> {
|
||||||
type Output = Traversal<Combination<Traversal<A>, Traversal<Lens<B>>>>;
|
type Output = Traversal<Combination<Traversal<A>, Traversal<Lens<B>>>>;
|
||||||
|
|
||||||
fn add(self, rhs: Lens<B>) -> Self::Output {
|
fn add(self, rhs: Lens<B>) -> Self::Output {
|
||||||
|
@ -42,7 +43,7 @@ impl<A, B> std::ops::Add<Lens<B>> for Traversal<A> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// lens + traversal
|
// lens + traversal
|
||||||
impl<A, B> std::ops::Add<Traversal<B>> for Lens<A> {
|
impl<A, B> const Add<Traversal<B>> for Lens<A> {
|
||||||
type Output = Traversal<Combination<Traversal<Lens<A>>, Traversal<B>>>;
|
type Output = Traversal<Combination<Traversal<Lens<A>>, Traversal<B>>>;
|
||||||
|
|
||||||
fn add(self, rhs: Traversal<B>) -> Self::Output {
|
fn add(self, rhs: Traversal<B>) -> Self::Output {
|
||||||
|
@ -50,7 +51,7 @@ impl<A, B> std::ops::Add<Traversal<B>> for Lens<A> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// traversal + prism
|
// traversal + prism
|
||||||
impl<A, B> std::ops::Add<Prism<B>> for Traversal<A> {
|
impl<A, B> const Add<Prism<B>> for Traversal<A> {
|
||||||
type Output = Traversal<Combination<Traversal<A>, Traversal<Prism<B>>>>;
|
type Output = Traversal<Combination<Traversal<A>, Traversal<Prism<B>>>>;
|
||||||
|
|
||||||
fn add(self, rhs: Prism<B>) -> Self::Output {
|
fn add(self, rhs: Prism<B>) -> Self::Output {
|
||||||
|
@ -58,7 +59,7 @@ impl<A, B> std::ops::Add<Prism<B>> for Traversal<A> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// prism + traversal
|
// prism + traversal
|
||||||
impl<A, B> std::ops::Add<Traversal<B>> for Prism<A> {
|
impl<A, B> const Add<Traversal<B>> for Prism<A> {
|
||||||
type Output = Traversal<Combination<Traversal<Prism<A>>, Traversal<B>>>;
|
type Output = Traversal<Combination<Traversal<Prism<A>>, Traversal<B>>>;
|
||||||
|
|
||||||
fn add(self, rhs: Traversal<B>) -> Self::Output {
|
fn add(self, rhs: Traversal<B>) -> Self::Output {
|
||||||
|
@ -66,7 +67,7 @@ impl<A, B> std::ops::Add<Traversal<B>> for Prism<A> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// lens + prism
|
// lens + prism
|
||||||
impl<A, B> std::ops::Add<Prism<B>> for Lens<A> {
|
impl<A, B> const Add<Prism<B>> for Lens<A> {
|
||||||
type Output = Traversal<Combination<Traversal<Lens<A>>, Traversal<Prism<B>>>>;
|
type Output = Traversal<Combination<Traversal<Lens<A>>, Traversal<Prism<B>>>>;
|
||||||
|
|
||||||
fn add(self, rhs: Prism<B>) -> Self::Output {
|
fn add(self, rhs: Prism<B>) -> Self::Output {
|
||||||
|
@ -74,7 +75,7 @@ impl<A, B> std::ops::Add<Prism<B>> for Lens<A> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// prism + traversal
|
// prism + traversal
|
||||||
impl<A, B> std::ops::Add<Lens<B>> for Prism<A> {
|
impl<A, B> const Add<Lens<B>> for Prism<A> {
|
||||||
type Output = Traversal<Combination<Traversal<Prism<A>>, Traversal<Lens<B>>>>;
|
type Output = Traversal<Combination<Traversal<Prism<A>>, Traversal<Lens<B>>>>;
|
||||||
|
|
||||||
fn add(self, rhs: Lens<B>) -> Self::Output {
|
fn add(self, rhs: Lens<B>) -> Self::Output {
|
||||||
|
@ -321,4 +322,17 @@ mod tests {
|
||||||
let res = t(thing, |v| v + 1);
|
let res = t(thing, |v| v + 1);
|
||||||
assert_eq!(res, (Some(2), 2));
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,108 @@
|
||||||
|
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]);
|
|
@ -0,0 +1,110 @@
|
||||||
|
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,16 +1,22 @@
|
||||||
mod fields;
|
pub mod fields;
|
||||||
|
|
||||||
mod identity;
|
pub mod identity;
|
||||||
pub use identity::id;
|
pub use identity::id;
|
||||||
|
|
||||||
mod first;
|
pub mod first;
|
||||||
pub use first::_0;
|
pub use first::_0;
|
||||||
mod second;
|
pub mod second;
|
||||||
pub use second::_1;
|
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;
|
||||||
|
|
||||||
mod to;
|
pub mod to;
|
||||||
pub use to::{to, to_from_boxed};
|
pub use to::{to, to_from_boxed};
|
||||||
mod lens;
|
pub mod lens;
|
||||||
pub use lens::{lens, lens_from_boxed};
|
pub use lens::{lens, lens_from_boxed};
|
||||||
|
|
||||||
/// Wrapper type
|
/// Wrapper type
|
||||||
|
|
|
@ -0,0 +1,99 @@
|
||||||
|
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]);
|
12
src/lib.rs
12
src/lib.rs
|
@ -1,7 +1,15 @@
|
||||||
#![feature(unboxed_closures, fn_traits)]
|
#![feature(unboxed_closures, fn_traits, const_trait_impl)]
|
||||||
|
|
||||||
mod combinations;
|
pub mod combinations;
|
||||||
mod fns;
|
mod fns;
|
||||||
pub mod lenses;
|
pub mod lenses;
|
||||||
pub mod prisms;
|
pub mod prisms;
|
||||||
pub mod traversals;
|
pub mod traversals;
|
||||||
|
|
||||||
|
pub mod prelude {
|
||||||
|
pub use crate::combinations::*;
|
||||||
|
|
||||||
|
pub use crate::lenses::*;
|
||||||
|
pub use crate::prisms::*;
|
||||||
|
pub use crate::traversals::*;
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
mod result;
|
pub mod result;
|
||||||
pub use result::{_Err, _Ok};
|
pub use result::{_Err, _Ok};
|
||||||
|
|
||||||
mod option;
|
pub mod option;
|
||||||
pub use option::{_None, _Some};
|
pub use option::{_None, _Some};
|
||||||
|
|
||||||
/// Wrapper type
|
/// Wrapper type
|
||||||
|
|
|
@ -0,0 +1,101 @@
|
||||||
|
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,9 +1,14 @@
|
||||||
mod both;
|
pub mod both;
|
||||||
pub use both::both;
|
pub use both::both;
|
||||||
|
|
||||||
mod each;
|
pub mod each;
|
||||||
pub use each::each;
|
pub use each::each;
|
||||||
|
|
||||||
|
pub mod head;
|
||||||
|
pub use head::_head;
|
||||||
|
pub mod tail;
|
||||||
|
pub use tail::_tail;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
lenses::{Lens, LensOver, LensView},
|
lenses::{Lens, LensOver, LensView},
|
||||||
prisms::{Prism, PrismPreview},
|
prisms::{Prism, PrismPreview},
|
||||||
|
@ -57,7 +62,7 @@ where
|
||||||
// all lenses are traversals, so we can freely transform them into a traversal
|
// all lenses are traversals, so we can freely transform them into a traversal
|
||||||
impl<L> Lens<L> {
|
impl<L> Lens<L> {
|
||||||
/// Returns this lens as a traversal
|
/// Returns this lens as a traversal
|
||||||
pub fn to_traversal(self) -> Traversal<Lens<L>> {
|
pub const fn to_traversal(self) -> Traversal<Lens<L>> {
|
||||||
Traversal(self)
|
Traversal(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -93,7 +98,7 @@ where
|
||||||
// all prisms are traversals, so we can freely transform them into a traversal
|
// all prisms are traversals, so we can freely transform them into a traversal
|
||||||
impl<L> Prism<L> {
|
impl<L> Prism<L> {
|
||||||
/// Returns this lens as a traversal
|
/// Returns this lens as a traversal
|
||||||
pub fn to_traversal(self) -> Traversal<Prism<L>> {
|
pub const fn to_traversal(self) -> Traversal<Prism<L>> {
|
||||||
Traversal(self)
|
Traversal(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -154,4 +159,26 @@ mod tests {
|
||||||
let res = each(array, |v| v + 1);
|
let res = each(array, |v| v + 1);
|
||||||
assert_eq!(res, [2, 3, 4, 5]);
|
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]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,98 @@
|
||||||
|
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