Skip to content

Commit e5bd269

Browse files
committed
Deref and Index lenses
1 parent f0b3278 commit e5bd269

File tree

2 files changed

+114
-1
lines changed

2 files changed

+114
-1
lines changed

druid/src/lens.rs

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
//! Support for lenses, a way of focusing on subfields of data.
1616
1717
use std::marker::PhantomData;
18+
use std::ops;
1819

1920
pub use druid_derive::Lens;
2021

@@ -252,3 +253,82 @@ impl<T: Clone, U: Clone, B> Clone for Then<T, U, B> {
252253
}
253254
}
254255
}
256+
257+
#[derive(Debug, Copy, Clone)]
258+
pub struct Deref;
259+
260+
impl<T: ?Sized> Lens<T, T::Target> for Deref
261+
where T: ops::Deref + ops::DerefMut,
262+
{
263+
fn with<V, F: FnOnce(&T::Target) -> V>(&self, data: &T, f: F) -> V {
264+
f(data.deref())
265+
}
266+
fn with_mut<V, F: FnOnce(&mut T::Target) -> V>(&self, data: &mut T, f: F) -> V {
267+
f(data.deref_mut())
268+
}
269+
}
270+
271+
/// `Lens` for indexing containers
272+
#[derive(Debug, Copy, Clone)]
273+
pub struct Index<I> {
274+
index: I,
275+
}
276+
277+
impl<I> Index<I> {
278+
/// Construct a lens that accesses a particular index
279+
///
280+
/// See also `LensExt::index`.
281+
pub fn new(index: I) -> Self {
282+
Self { index }
283+
}
284+
}
285+
286+
impl<T, I> Lens<T, T::Output> for Index<I>
287+
where
288+
T: ?Sized + ops::Index<I> + ops::IndexMut<I>,
289+
I: Clone,
290+
{
291+
fn with<V, F: FnOnce(&T::Output) -> V>(&self, data: &T, f: F) -> V {
292+
f(&data[self.index.clone()])
293+
}
294+
fn with_mut<V, F: FnOnce(&mut T::Output) -> V>(&self, data: &mut T, f: F) -> V {
295+
f(&mut data[self.index.clone()])
296+
}
297+
}
298+
299+
pub trait Iso<A, B> {
300+
fn forward_ref(&self, a: &A) -> B;
301+
fn reverse_ref(&self, b: &B) -> A;
302+
303+
fn forward(&self, a: A) -> B {
304+
self.forward_ref(&a)
305+
}
306+
307+
fn reverse(&self, b: B) -> A {
308+
self.reverse_ref(&b)
309+
}
310+
311+
fn into_lens(self) -> IsoLens<Self>
312+
where Self: Sized
313+
{
314+
IsoLens { iso: self }
315+
}
316+
}
317+
318+
#[derive(Debug, Copy, Clone)]
319+
pub struct IsoLens<I> {
320+
iso: I,
321+
}
322+
323+
impl<A, B, I: Iso<A, B>> Lens<A, B> for IsoLens<I> {
324+
fn with<T, F: FnOnce(&B) -> T>(&self, data: &A, f: F) -> T {
325+
f(&self.iso.forward_ref(data))
326+
}
327+
328+
fn with_mut<T, F: FnOnce(&mut B) -> T>(&self, data: &mut A, f: F) -> T {
329+
let mut x = self.iso.forward_ref(data);
330+
let v = f(&mut x);
331+
*data = self.iso.reverse(x);
332+
v
333+
}
334+
}

druid/src/lens_ext.rs

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
use crate::lens::Then;
1+
use std::ops;
2+
3+
use crate::lens::{Index, Then, Deref};
24
use crate::Lens;
35

46
/// Helpers for manipulating `Lens`es
@@ -35,6 +37,37 @@ pub trait LensExt<A: ?Sized, B: ?Sized>: Lens<A, B> {
3537
{
3638
Then::new(self, other)
3739
}
40+
41+
/// Invoke a type's `Deref` impl
42+
///
43+
/// ```
44+
/// # use druid::*;
45+
/// let lens = lens!((bool, Box<u32>), 1).deref();
46+
/// assert_eq!(lens.get(&(false, Box::new(42))), 42);
47+
/// ```
48+
fn deref(self) -> Then<Self, Deref, B>
49+
where
50+
B: ops::Deref + ops::DerefMut,
51+
Self: Sized,
52+
{
53+
self.then(Deref)
54+
}
55+
56+
/// Access an index in a container
57+
///
58+
/// ```
59+
/// # use druid::*;
60+
/// let lens = lens!((bool, Vec<u8>), 1).deref().index(2);
61+
/// assert_eq!(lens.get(&(false, vec![0, 1, 2, 3])), 2);
62+
/// ```
63+
fn index<I>(self, index: I) -> Then<Self, Index<I>, B>
64+
where
65+
I: Clone,
66+
B: ops::Index<I> + ops::IndexMut<I>,
67+
Self: Sized,
68+
{
69+
self.then(Index::new(index))
70+
}
3871
}
3972

4073
impl<A: ?Sized, B: ?Sized, T: Lens<A, B>> LensExt<A, B> for T {}

0 commit comments

Comments
 (0)