Skip to content

Commit affb5be

Browse files
committed
Introduce InArc lens adapter for efficient Arc handling
1 parent 1807ba9 commit affb5be

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

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

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

0 commit comments

Comments
 (0)