|
16 | 16 |
|
17 | 17 | use std::marker::PhantomData;
|
18 | 18 | use std::ops;
|
| 19 | +use std::sync::Arc; |
19 | 20 |
|
20 | 21 | pub use druid_derive::Lens;
|
21 | 22 |
|
@@ -123,6 +124,33 @@ pub trait LensExt<A: ?Sized, B: ?Sized>: Lens<A, B> {
|
123 | 124 | {
|
124 | 125 | self.then(Index::new(index))
|
125 | 126 | }
|
| 127 | + |
| 128 | + /// Access data in an `Arc` with copy-on-write semantics |
| 129 | + /// |
| 130 | + /// The inner `lens` allows the scope that has to be checked for changes after a mutable access |
| 131 | + /// to be reduced. |
| 132 | + /// |
| 133 | + /// ``` |
| 134 | + /// # use druid::*; use std::sync::Arc; |
| 135 | + /// let lens = lens::Id.make_mut(lens::Id.index(2)); |
| 136 | + /// let mut x = Arc::new(vec![0, 1, 2, 3]); |
| 137 | + /// let original = x.clone(); |
| 138 | + /// assert_eq!(lens.get(&x), 2); |
| 139 | + /// lens.put(&mut x, 2); |
| 140 | + /// assert!(Arc::ptr_eq(&original, &x), "no-op writes don't cause a deep copy"); |
| 141 | + /// lens.put(&mut x, 42); |
| 142 | + /// assert_eq!(&*x, &[0, 1, 42, 3]); |
| 143 | + /// ``` |
| 144 | + fn make_mut<L, C, D>(self, lens: L) -> MakeMut<Self, L, C> |
| 145 | + where |
| 146 | + Self: Sized + Lens<A, Arc<C>>, |
| 147 | + B: Sized, |
| 148 | + C: Clone, |
| 149 | + D: Data, |
| 150 | + L: Lens<C, D>, |
| 151 | + { |
| 152 | + MakeMut::new(self, lens) |
| 153 | + } |
126 | 154 | }
|
127 | 155 |
|
128 | 156 | impl<A: ?Sized, B: ?Sized, T: Lens<A, B>> LensExt<A, B> for T {}
|
@@ -381,3 +409,57 @@ impl<A: ?Sized> Lens<A, A> for Id {
|
381 | 409 | f(data)
|
382 | 410 | }
|
383 | 411 | }
|
| 412 | + |
| 413 | +/// A `Lens` that exposes data within an `Arc` with copy-on-write semantics |
| 414 | +/// |
| 415 | +/// A copy is only made in the event that a different value is written. |
| 416 | +#[derive(Debug, Copy, Clone)] |
| 417 | +pub struct MakeMut<L, M, B> { |
| 418 | + arc: L, |
| 419 | + inner: M, |
| 420 | + _marker: PhantomData<B>, |
| 421 | +} |
| 422 | + |
| 423 | +impl<L, M, B> MakeMut<L, M, B> { |
| 424 | + /// Construct a lens manipulating the `inner` part of `arc` |
| 425 | + /// |
| 426 | + /// See also `LensExt::make_mut` |
| 427 | + pub fn new<A, C>(arc: L, inner: M) -> Self |
| 428 | + where |
| 429 | + A: ?Sized, |
| 430 | + B: Clone, |
| 431 | + C: Data, |
| 432 | + L: Lens<A, Arc<B>>, |
| 433 | + M: Lens<B, C>, |
| 434 | + { |
| 435 | + Self { |
| 436 | + arc, |
| 437 | + inner, |
| 438 | + _marker: PhantomData, |
| 439 | + } |
| 440 | + } |
| 441 | +} |
| 442 | + |
| 443 | +impl<A, B, C, L, M> Lens<A, C> for MakeMut<L, M, B> |
| 444 | +where |
| 445 | + A: ?Sized, |
| 446 | + B: Clone, |
| 447 | + C: Data, |
| 448 | + L: Lens<A, Arc<B>>, |
| 449 | + M: Lens<B, C>, |
| 450 | +{ |
| 451 | + fn with<V, F: FnOnce(&C) -> V>(&self, data: &A, f: F) -> V { |
| 452 | + self.arc.with(data, |arc| self.inner.with(arc, f)) |
| 453 | + } |
| 454 | + |
| 455 | + fn with_mut<V, F: FnOnce(&mut C) -> V>(&self, data: &mut A, f: F) -> V { |
| 456 | + self.arc.with_mut(data, |arc| { |
| 457 | + let mut temp = self.inner.with(arc, |x| x.clone()); |
| 458 | + let v = f(&mut temp); |
| 459 | + if self.inner.with(arc, |x| !x.same(&temp)) { |
| 460 | + self.inner.with_mut(Arc::make_mut(arc), |x| *x = temp); |
| 461 | + } |
| 462 | + v |
| 463 | + }) |
| 464 | + } |
| 465 | +} |
0 commit comments