Skip to content

Deref, Index, and InArc lenses #367

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Dec 3, 2019
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
157 changes: 157 additions & 0 deletions druid/src/lens.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
//! Support for lenses, a way of focusing on subfields of data.

use std::marker::PhantomData;
use std::ops;
use std::sync::Arc;

pub use druid_derive::Lens;

Expand Down Expand Up @@ -113,6 +115,57 @@ pub trait LensExt<A: ?Sized, B: ?Sized>: Lens<A, B> {
{
self.then(Map::new(get, put))
}

/// Invoke a type's `Deref` impl
///
/// ```
/// # use druid::*;
/// assert_eq!(lens::Id.deref().get(&Box::new(42)), 42);
/// ```
fn deref(self) -> Then<Self, Deref, B>
where
B: ops::Deref + ops::DerefMut,
Self: Sized,
{
self.then(Deref)
}

/// Access an index in a container
///
/// ```
/// # use druid::*;
/// assert_eq!(lens::Id.index(2).get(&vec![0u32, 1, 2, 3]), 2);
/// ```
fn index<I>(self, index: I) -> Then<Self, Index<I>, B>
where
I: Clone,
B: ops::Index<I> + ops::IndexMut<I>,
Self: Sized,
{
self.then(Index::new(index))
}

/// Adapt to operate on the contents of an `Arc` with efficient copy-on-write semantics
///
/// ```
/// # use druid::*; use std::sync::Arc;
/// let lens = lens::Id.index(2).in_arc();
/// let mut x = Arc::new(vec![0, 1, 2, 3]);
/// let original = x.clone();
/// assert_eq!(lens.get(&x), 2);
/// lens.put(&mut x, 2);
/// assert!(Arc::ptr_eq(&original, &x), "no-op writes don't cause a deep copy");
/// lens.put(&mut x, 42);
/// assert_eq!(&*x, &[0, 1, 42, 3]);
/// ```
fn in_arc(self) -> InArc<Self>
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bikeshedding still welcome, though I think this is probably adequate.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't think of anything better? maybe just arc, but either or.

where
A: Clone,
B: Data,
Self: Sized,
{
InArc::new(self)
}
}

impl<A: ?Sized, B: ?Sized, T: Lens<A, B>> LensExt<A, B> for T {}
Expand Down Expand Up @@ -349,3 +402,107 @@ where
x
}
}

/// `Lens` for invoking `Deref` and `DerefMut` on a type
///
/// See also `LensExt::deref`.
#[derive(Debug, Copy, Clone)]
pub struct Deref;

impl<T: ?Sized> Lens<T, T::Target> for Deref
where
T: ops::Deref + ops::DerefMut,
{
fn with<V, F: FnOnce(&T::Target) -> V>(&self, data: &T, f: F) -> V {
f(data.deref())
}
fn with_mut<V, F: FnOnce(&mut T::Target) -> V>(&self, data: &mut T, f: F) -> V {
f(data.deref_mut())
}
}

/// `Lens` for indexing containers
#[derive(Debug, Copy, Clone)]
pub struct Index<I> {
index: I,
}

impl<I> Index<I> {
/// Construct a lens that accesses a particular index
///
/// See also `LensExt::index`.
pub fn new(index: I) -> Self {
Self { index }
}
}

impl<T, I> Lens<T, T::Output> for Index<I>
where
T: ?Sized + ops::Index<I> + ops::IndexMut<I>,
I: Clone,
{
fn with<V, F: FnOnce(&T::Output) -> V>(&self, data: &T, f: F) -> V {
f(&data[self.index.clone()])
}
fn with_mut<V, F: FnOnce(&mut T::Output) -> V>(&self, data: &mut T, f: F) -> V {
f(&mut data[self.index.clone()])
}
}

/// The identity lens: the lens which does nothing, i.e. exposes exactly the original value.
///
/// Useful for starting a lens combinator chain, or passing to lens-based interfaces.
#[derive(Debug, Copy, Clone)]
pub struct Id;

impl<A: ?Sized> Lens<A, A> for Id {
fn with<V, F: FnOnce(&A) -> V>(&self, data: &A, f: F) -> V {
f(data)
}

fn with_mut<V, F: FnOnce(&mut A) -> V>(&self, data: &mut A, f: F) -> V {
f(data)
}
}

/// A `Lens` that exposes data within an `Arc` with copy-on-write semantics
///
/// A copy is only made in the event that a different value is written.
#[derive(Debug, Copy, Clone)]
pub struct InArc<L> {
inner: L,
}

impl<L> InArc<L> {
/// Adapt a lens to operate on an `Arc`
///
/// See also `LensExt::in_arc`
pub fn new<A, B>(inner: L) -> Self
where
A: Clone,
B: Data,
L: Lens<A, B>,
{
Self { inner }
}
}

impl<A, B, L> Lens<Arc<A>, B> for InArc<L>
where
A: Clone,
B: Data,
L: Lens<A, B>,
{
fn with<V, F: FnOnce(&B) -> V>(&self, data: &Arc<A>, f: F) -> V {
self.inner.with(data, f)
}

fn with_mut<V, F: FnOnce(&mut B) -> V>(&self, data: &mut Arc<A>, f: F) -> V {
let mut temp = self.inner.with(data, |x| x.clone());
let v = f(&mut temp);
if self.inner.with(data, |x| !x.same(&temp)) {
self.inner.with_mut(Arc::make_mut(data), |x| *x = temp);
}
v
}
}