Skip to content

Commit 4ed9487

Browse files
committed
Introduce InArc lens adapter for efficient Arc handling
1 parent 6f7a9c1 commit 4ed9487

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

0 commit comments

Comments
 (0)