Skip to content

Commit 5830a34

Browse files
committed
Introduce InArc lens adapter for efficient Arc handling
1 parent f1baaf6 commit 5830a34

File tree

1 file changed

+65
-0
lines changed

1 file changed

+65
-0
lines changed

druid/src/lens.rs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
1717
use std::marker::PhantomData;
1818
use std::ops;
19+
use std::sync::Arc;
1920

2021
pub use druid_derive::Lens;
2122

@@ -121,6 +122,28 @@ pub trait LensExt<A: ?Sized, B: ?Sized>: Lens<A, B> {
121122
{
122123
self.then(Index::new(index))
123124
}
125+
126+
/// Adapt to operate on the contents of an `Arc` with efficient copy-on-write semantics
127+
///
128+
/// ```
129+
/// # use druid::*; use std::sync::Arc;
130+
/// let lens = lens::Id.index(2).in_arc();
131+
/// let mut x = Arc::new(vec![0, 1, 2, 3]);
132+
/// let original = x.clone();
133+
/// assert_eq!(lens.get(&x), 2);
134+
/// lens.put(&mut x, 2);
135+
/// assert!(Arc::ptr_eq(&original, &x), "no-op writes don't cause a deep copy");
136+
/// lens.put(&mut x, 42);
137+
/// assert_eq!(&*x, &[0, 1, 42, 3]);
138+
/// ```
139+
fn in_arc(self) -> InArc<Self>
140+
where
141+
A: Clone,
142+
B: Data,
143+
Self: Sized,
144+
{
145+
InArc::new(self)
146+
}
124147
}
125148

126149
impl<A: ?Sized, B: ?Sized, T: Lens<A, B>> LensExt<A, B> for T {}
@@ -382,3 +405,45 @@ impl<A: ?Sized> Lens<A, A> for Id {
382405
f(data)
383406
}
384407
}
408+
409+
/// A `Lens` that exposes data within an `Arc` with copy-on-write semantics
410+
///
411+
/// A copy is only made in the event that a different value is written.
412+
#[derive(Debug, Copy, Clone)]
413+
pub struct InArc<L> {
414+
inner: L,
415+
}
416+
417+
impl<L> InArc<L> {
418+
/// Adapt a lens to operate on an `Arc`
419+
///
420+
/// See also `LensExt::in_arc`
421+
pub fn new<A, B>(inner: L) -> Self
422+
where
423+
A: Clone,
424+
B: Data,
425+
L: Lens<A, B>,
426+
{
427+
Self { inner }
428+
}
429+
}
430+
431+
impl<A, B, L> Lens<Arc<A>, B> for InArc<L>
432+
where
433+
A: Clone,
434+
B: Data,
435+
L: Lens<A, B>,
436+
{
437+
fn with<V, F: FnOnce(&B) -> V>(&self, data: &Arc<A>, f: F) -> V {
438+
self.inner.with(data, f)
439+
}
440+
441+
fn with_mut<V, F: FnOnce(&mut B) -> V>(&self, data: &mut Arc<A>, f: F) -> V {
442+
let mut temp = self.inner.with(data, |x| x.clone());
443+
let v = f(&mut temp);
444+
if self.inner.with(data, |x| !x.same(&temp)) {
445+
self.inner.with_mut(Arc::make_mut(data), |x| *x = temp);
446+
}
447+
v
448+
}
449+
}

0 commit comments

Comments
 (0)