add to, lens
parent
61484339f9
commit
2c0a770f9f
|
@ -0,0 +1,46 @@
|
||||||
|
use crate::{
|
||||||
|
lenses::{LensOver, LensView},
|
||||||
|
Optics, OpticsTrait,
|
||||||
|
};
|
||||||
|
|
||||||
|
type Getter<T, U> = dyn Fn(T) -> U;
|
||||||
|
type Setter<T, U> = dyn Fn(T, U) -> T;
|
||||||
|
|
||||||
|
pub struct LensInner<T, U>(pub(crate) Box<Getter<T, U>>, pub(crate) Box<Setter<T, U>>);
|
||||||
|
impl<T, U> OpticsTrait for LensInner<T, U> {}
|
||||||
|
|
||||||
|
impl<T, U> LensView<T> for LensInner<T, U> {
|
||||||
|
type Field = U;
|
||||||
|
|
||||||
|
fn view(&self, thing: T) -> Self::Field {
|
||||||
|
(self.0)(thing)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T: Clone, U> LensOver<T> for LensInner<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_boxed<T, U>(
|
||||||
|
getter: Box<Getter<T, U>>,
|
||||||
|
setter: Box<Setter<T, U>>,
|
||||||
|
) -> Optics<LensInner<T, U>> {
|
||||||
|
Optics(LensInner(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,
|
||||||
|
) -> Optics<LensInner<T, U>> {
|
||||||
|
Optics(LensInner(Box::new(getter), Box::new(setter)))
|
||||||
|
}
|
|
@ -7,6 +7,9 @@ mod second;
|
||||||
pub use second::_1;
|
pub use second::_1;
|
||||||
|
|
||||||
mod to;
|
mod to;
|
||||||
|
pub use to::{to, to_from_boxed};
|
||||||
|
mod lens;
|
||||||
|
pub use lens::{lens, lens_from_boxed};
|
||||||
|
|
||||||
use crate::{Optics, OpticsTrait};
|
use crate::{Optics, OpticsTrait};
|
||||||
|
|
||||||
|
@ -161,4 +164,53 @@ mod tests {
|
||||||
let res = lens(a, |v| v + 1);
|
let res = lens(a, |v| v + 1);
|
||||||
assert_eq!(res, ((1, 3), 3));
|
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_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 });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
use crate::{lenses::LensView, Optics, OpticsTrait};
|
||||||
|
|
||||||
|
use super::lens::LensInner;
|
||||||
|
|
||||||
|
pub struct ToInner<T, U>(Box<dyn Fn(T) -> U>);
|
||||||
|
impl<T, U> OpticsTrait for ToInner<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_boxed<T, U>(f: Box<dyn Fn(T) -> U>) -> Optics<ToInner<T, U>> {
|
||||||
|
Optics(ToInner(f))
|
||||||
|
}
|
||||||
|
/// Makes a lens that implements `LensView<T>` with the provided function
|
||||||
|
pub fn to<T, U>(f: impl Fn(T) -> U + 'static) -> Optics<ToInner<T, U>> {
|
||||||
|
Optics(ToInner(Box::new(f)))
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, U> Optics<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) -> Optics<LensInner<T, U>> {
|
||||||
|
Optics(LensInner((self.0).0, Box::new(setter)))
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue