Skip to content

Commit 6d9f725

Browse files
committed
Introduce InArc lens adapter for efficient Arc handling
1 parent 41611ba commit 6d9f725

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

@@ -143,6 +144,28 @@ pub trait LensExt<A: ?Sized, B: ?Sized>: Lens<A, B> {
143144
{
144145
self.then(Index::new(index))
145146
}
147+
148+
/// Adapt to operate on the contents of an `Arc` with efficient copy-on-write semantics
149+
///
150+
/// ```
151+
/// # use druid::*; use std::sync::Arc;
152+
/// let lens = lens::Id.index(2).in_arc();
153+
/// let mut x = Arc::new(vec![0, 1, 2, 3]);
154+
/// let original = x.clone();
155+
/// assert_eq!(lens.get(&x), 2);
156+
/// lens.put(&mut x, 2);
157+
/// assert!(Arc::ptr_eq(&original, &x), "no-op writes don't cause a deep copy");
158+
/// lens.put(&mut x, 42);
159+
/// assert_eq!(&*x, &[0, 1, 42, 3]);
160+
/// ```
161+
fn in_arc(self) -> InArc<Self>
162+
where
163+
A: Clone,
164+
B: Data,
165+
Self: Sized,
166+
{
167+
InArc::new(self)
168+
}
146169
}
147170

148171
impl<A: ?Sized, B: ?Sized, T: Lens<A, B>> LensExt<A, B> for T {}
@@ -441,3 +464,45 @@ impl<A: ?Sized> Lens<A, A> for Id {
441464
f(data)
442465
}
443466
}
467+
468+
/// A `Lens` that exposes data within an `Arc` with copy-on-write semantics
469+
///
470+
/// A copy is only made in the event that a different value is written.
471+
#[derive(Debug, Copy, Clone)]
472+
pub struct InArc<L> {
473+
inner: L,
474+
}
475+
476+
impl<L> InArc<L> {
477+
/// Adapt a lens to operate on an `Arc`
478+
///
479+
/// See also `LensExt::in_arc`
480+
pub fn new<A, B>(inner: L) -> Self
481+
where
482+
A: Clone,
483+
B: Data,
484+
L: Lens<A, B>,
485+
{
486+
Self { inner }
487+
}
488+
}
489+
490+
impl<A, B, L> Lens<Arc<A>, B> for InArc<L>
491+
where
492+
A: Clone,
493+
B: Data,
494+
L: Lens<A, B>,
495+
{
496+
fn with<V, F: FnOnce(&B) -> V>(&self, data: &Arc<A>, f: F) -> V {
497+
self.inner.with(data, f)
498+
}
499+
500+
fn with_mut<V, F: FnOnce(&mut B) -> V>(&self, data: &mut Arc<A>, f: F) -> V {
501+
let mut temp = self.inner.with(data, |x| x.clone());
502+
let v = f(&mut temp);
503+
if self.inner.with(data, |x| !x.same(&temp)) {
504+
self.inner.with_mut(Arc::make_mut(data), |x| *x = temp);
505+
}
506+
v
507+
}
508+
}

0 commit comments

Comments
 (0)