Skip to content

Commit

Permalink
Finally works!
Browse files Browse the repository at this point in the history
YAY!!!!!
  • Loading branch information
pthariensflame committed Dec 17, 2016
1 parent 07f555f commit 0210e04
Show file tree
Hide file tree
Showing 4 changed files with 135 additions and 13 deletions.
32 changes: 31 additions & 1 deletion src/conv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

use std::fmt::{self, Debug, Formatter};
use std::marker::PhantomData;
use super::{Iso, Lens, Lenticuloid, PartialLens, Prism};
use super::{Injector, Iso, Lens, Lenticuloid, PartialLens, Prism, util};

/// An isomorphism family that handles lossless conversions by owned value.
pub struct Conv<S, A = S, T = S, B = A> {
Expand Down Expand Up @@ -121,6 +121,16 @@ impl<S, A, T, B> PartialLens for Conv<S, A, T, B>
Ok(v.into())
}

#[inline]
fn try_get_inject(&self,
v: Self::InitialSource)
-> Result<(Self::InitialTarget,
Injector<Self::FinalTarget, Self::FinalSource>),
Self::FinalSource> {
Ok((v.into(),
util::once_to_mut(move |x: Self::FinalTarget| -> Self::FinalSource { x.into() })))
}

#[inline]
fn set(&self, _v: Self::InitialSource, x: Self::FinalTarget) -> Self::FinalSource {
x.into()
Expand Down Expand Up @@ -298,6 +308,16 @@ impl<'a, S: ?Sized, A: ?Sized, T: ?Sized, B: ?Sized> PartialLens for ConvRef<'a,
Ok(v.as_ref())
}

#[inline]
fn try_get_inject(&self,
v: Self::InitialSource)
-> Result<(Self::InitialTarget,
Injector<Self::FinalTarget, Self::FinalSource>),
Self::FinalSource> {
Ok((v.as_ref(),
util::once_to_mut(move |x: Self::FinalTarget| -> Self::FinalSource { x.as_ref() })))
}

#[inline]
fn set(&self, _v: Self::InitialSource, x: Self::FinalTarget) -> Self::FinalSource {
x.as_ref()
Expand Down Expand Up @@ -475,6 +495,16 @@ impl<'a, S: ?Sized, A: ?Sized, T: ?Sized, B: ?Sized> PartialLens for ConvMut<'a,
Ok(v.as_mut())
}

#[inline]
fn try_get_inject(&self,
v: Self::InitialSource)
-> Result<(Self::InitialTarget,
Injector<Self::FinalTarget, Self::FinalSource>),
Self::FinalSource> {
Ok((v.as_mut(),
util::once_to_mut(move |x: Self::FinalTarget| -> Self::FinalSource { x.as_mut() })))
}

#[inline]
fn set(&self, _v: Self::InitialSource, x: Self::FinalTarget) -> Self::FinalSource {
x.as_mut()
Expand Down
19 changes: 19 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,29 @@
//! - `const fn` support

#![cfg_attr(feature = "nightly", feature(never_type, const_fn))]
#![cfg_attr(feature = "cargo-clippy", allow(expl_impl_clone_on_copy, type_complexity))]

use std::fmt;
use std::marker::PhantomData;

/// Some utility functions used inside this crate, but possibly useful for
/// others as well.
pub mod util {
pub fn once_to_mut<'a, X, Y, F>(f_once: F) -> Box<FnMut(X) -> Option<Y> + 'a>
where F: FnOnce(X) -> Y + 'a
{
let mut f_opt: Option<F> = Some(f_once);
Box::new(move |x| f_opt.take().map(move |f| f(x)))
}

pub fn once_to_mut_flatten<'a, X, Y, F>(f_once: F) -> Box<FnMut(X) -> Option<Y> + 'a>
where F: FnOnce(X) -> Option<Y> + 'a
{
let mut f_opt: Option<F> = Some(f_once);
Box::new(move |x| f_opt.take().and_then(move |f| f(x)))
}
}

/// The supertype of all lenticuloids.
pub trait Lenticuloid {
type InitialSource;
Expand Down
64 changes: 58 additions & 6 deletions src/partial_lens.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,25 @@
use super::{Compose, Identity, Invert, Iso, Lens, Lenticuloid, Prism};
use super::{Compose, Identity, Invert, Iso, Lenticuloid, util};

pub type Injector<'l, X, Y> = Box<FnMut(X) -> Option<Y> + 'l>;

/// The supertype of all partial lens families.
pub trait PartialLens: Lenticuloid
where Self::AtInitial: PartialLens,
Self::AtFinal: PartialLens
{
fn try_get(&self, v: Self::InitialSource) -> Result<Self::InitialTarget, Self::FinalSource>;
fn try_get(&self, v: Self::InitialSource) -> Result<Self::InitialTarget, Self::FinalSource> {
self.try_get_inject(v).map(|(x, _)| x)
}

/// This signature is somewhat hacky; it awaits resolution of the `FnBox`
/// issue for better design. Notably, the injection function returned by
/// this method will (if law-abiding) only return `Some` exactly once;
/// every time afterwards, it will return `None`.
fn try_get_inject(&self,
v: Self::InitialSource)
-> Result<(Self::InitialTarget,
Injector<Self::FinalTarget, Self::FinalSource>),
Self::FinalSource>;

fn set(&self, v: Self::InitialSource, x: Self::FinalTarget) -> Self::FinalSource {
self.modify(v, |_| x)
Expand Down Expand Up @@ -35,6 +49,11 @@ impl<S, T> PartialLens for Identity<S, T> {
Ok(v)
}

#[inline]
fn try_get_inject(&self, v: S) -> Result<(S, Injector<T, T>), T> {
Ok((v, util::once_to_mut(|x| x)))
}

#[inline]
fn set(&self, _v: S, x: T) -> T {
x
Expand Down Expand Up @@ -66,7 +85,31 @@ impl<LF: PartialLens, LS: ?Sized> PartialLens for Compose<LF, LS>
{
fn try_get(&self, v: Self::InitialSource) -> Result<Self::InitialTarget, Self::FinalSource> {
let Compose { first: ref lf, second: ref ls } = *self;
()
ls.try_get_inject(v).and_then(move |(q, mut inj)| {
lf.try_get(q).map_err(move |x| inj(x).unwrap_or_else(|| unreachable!()))
})
}

fn try_get_inject(&self,
v: Self::InitialSource)
-> Result<(Self::InitialTarget,
Injector<Self::FinalTarget, Self::FinalSource>),
Self::FinalSource> {
let Compose { first: ref lf, second: ref ls } = *self;
ls.try_get_inject(v).and_then(move |(q, mut inj_q)| {
let res = lf.try_get_inject(q).map(|(x, mut inj_x)| {
(x, move |y| inj_x(y).unwrap_or_else(|| unreachable!()))
});
match res {
Ok((x, mut inj_x)) => {
Ok((x,
util::once_to_mut(move |y| {
inj_q(inj_x(y)).unwrap_or_else(|| unreachable!())
})))
}
Err(q) => Err(inj_q(q).unwrap_or_else(|| unreachable!())),
}
})
}

fn set(&self, v: Self::InitialSource, x: Self::FinalTarget) -> Self::FinalSource {
Expand Down Expand Up @@ -107,6 +150,15 @@ impl<L: Iso> PartialLens for Invert<L>
Ok(self.deinvert.inject(v))
}

#[inline]
fn try_get_inject(&self,
v: Self::InitialSource)
-> Result<(Self::InitialTarget,
Injector<Self::FinalTarget, Self::FinalSource>),
Self::FinalSource> {
Ok((self.deinvert.inject(v), util::once_to_mut(move |x| self.deinvert.get(x))))
}

#[inline]
fn set(&self, _v: Self::InitialSource, x: Self::FinalTarget) -> Self::FinalSource {
self.deinvert.get(x)
Expand All @@ -117,23 +169,23 @@ impl<L: Iso> PartialLens for Invert<L>
v: Self::InitialSource,
x: Self::FinalTarget)
-> (Option<Self::InitialTarget>, Self::FinalSource) {
let ref l = self.deinvert;
let l = &self.deinvert;
(Some(l.inject(v)), l.get(x))
}

#[inline]
fn modify<F>(&self, v: Self::InitialSource, f: F) -> Self::FinalSource
where F: FnOnce(Self::InitialTarget) -> Self::FinalTarget
{
let ref l = self.deinvert;
let l = &self.deinvert;
l.get(f(l.inject(v)))
}

#[inline]
fn modify_with<F, X>(&self, v: Self::InitialSource, f: F) -> (Self::FinalSource, Option<X>)
where F: FnOnce(Self::InitialTarget) -> (Self::FinalTarget, X)
{
let ref l = self.deinvert;
let l = &self.deinvert;
let (x, ret) = f(l.inject(v));
(l.get(x), Some(ret))
}
Expand Down
33 changes: 27 additions & 6 deletions src/terminal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

use std::fmt::{self, Debug, Formatter};
use std::marker::PhantomData;
use super::{Lens, Lenticuloid, PartialLens, Prism};
use super::{Injector, Lens, Lenticuloid, PartialLens, Prism, util};

#[cfg(feature = "nightly")]
/// A `Lens` to "extract" anything from `!`.
Expand Down Expand Up @@ -76,11 +76,16 @@ impl<A, B> Lenticuloid for FromNever<A, B> {
}

#[cfg(feature = "nightly")]
#[cfg_attr(feature = "cargo-clippy", allow(unreachable_code))]
impl<A, B> PartialLens for FromNever<A, B> {
fn try_get(&self, v: !) -> Result<A, !> {
v
}

fn try_get_inject(&self, v: !) -> Result<(A, Injector<B, !>), !> {
v
}

fn set(&self, v: !, _x: B) -> ! {
v
}
Expand All @@ -93,14 +98,15 @@ impl<A, B> PartialLens for FromNever<A, B> {
v
}

fn modify_with<F, X>(&self, v: !, f: F) -> (!, Option<X>)
fn modify_with<F, X>(&self, v: !, _f: F) -> (!, Option<X>)
where F: FnOnce(A) -> (B, X)
{
v
}
}

#[cfg(feature = "nightly")]
#[cfg_attr(feature = "cargo-clippy", allow(unreachable_code))]
impl<A, B> Lens for FromNever<A, B> {
fn get(&self, v: !) -> A {
v
Expand Down Expand Up @@ -177,11 +183,16 @@ impl<S> Lenticuloid for ToNever<S> {
}

#[cfg(feature = "nightly")]
#[cfg_attr(feature = "cargo-clippy", allow(unreachable_code))]
impl<S> PartialLens for ToNever<S> {
fn try_get(&self, v: S) -> Result<!, S> {
Err(v)
}

fn try_get_inject(&self, v: S) -> Result<(!, Injector<!, S>), S> {
Err(v)
}

fn set(&self, _v: S, x: !) -> S {
x
}
Expand All @@ -196,14 +207,15 @@ impl<S> PartialLens for ToNever<S> {
v
}

fn modify_with<F, X>(&self, v: S, f: F) -> (S, Option<X>)
fn modify_with<F, X>(&self, v: S, _f: F) -> (S, Option<X>)
where F: FnOnce(!) -> (!, X)
{
(v, None)
}
}

#[cfg(feature = "nightly")]
#[cfg_attr(feature = "cargo-clippy", allow(unreachable_code))]
impl<S> Prism for ToNever<S> {
fn inject(&self, v: !) -> S {
v
Expand Down Expand Up @@ -284,11 +296,15 @@ impl<A, B> PartialLens for FromUnit<A, B> {
Err(v)
}

fn try_get_inject(&self, v: ()) -> Result<(A, Injector<B, ()>), ()> {
Err(v)
}

fn set(&self, v: (), _x: B) -> () {
v
}

fn exchange(&self, v: (), x: B) -> (Option<A>, ()) {
fn exchange(&self, _v: (), _x: B) -> (Option<A>, ()) {
(None, ())
}

Expand All @@ -298,7 +314,7 @@ impl<A, B> PartialLens for FromUnit<A, B> {
v
}

fn modify_with<F, X>(&self, v: (), f: F) -> ((), Option<X>)
fn modify_with<F, X>(&self, _v: (), _f: F) -> ((), Option<X>)
where F: FnOnce(A) -> (B, X)
{
((), None)
Expand Down Expand Up @@ -385,6 +401,10 @@ impl<S> PartialLens for ToUnit<S> {
Ok(())
}

fn try_get_inject(&self, v: S) -> Result<((), Injector<(), S>), S> {
Ok(((), util::once_to_mut(|_| v)))
}

fn set(&self, v: S, _x: ()) -> S {
v
}
Expand All @@ -393,7 +413,8 @@ impl<S> PartialLens for ToUnit<S> {
(Some(()), v)
}

fn modify<F: FnOnce(()) -> ()>(&self, v: S, _f: F) -> S {
fn modify<F: FnOnce(()) -> ()>(&self, v: S, f: F) -> S {
f(());
v
}

Expand Down

0 comments on commit 0210e04

Please sign in to comment.