@@ -554,10 +554,13 @@ public final class Property<Value>: PropertyProtocol {
554554 return observer. action ( event)
555555 }
556556
557- box. modify ( didSet: { _ in observer. action ( event) } ) { value in
558- if let newValue = event. value {
559- value = newValue
557+ box. begin { storage in
558+ storage. modify { value in
559+ if let newValue = event. value {
560+ value = newValue
561+ }
560562 }
563+ observer. action ( event)
561564 }
562565 }
563566 }
@@ -675,31 +678,28 @@ public final class MutableProperty<Value>: ComposableMutablePropertyProtocol {
675678 /// Atomically modifies the variable.
676679 ///
677680 /// - parameters:
678- /// - action: A closure that accepts old property value and returns a new
679- /// property value.
681+ /// - action: A closure that accepts an inout reference to the value.
680682 ///
681683 /// - returns: The result of the action.
682684 @discardableResult
683685 public func modify< Result> ( _ action: ( inout Value ) throws -> Result ) rethrows -> Result {
684- return try box. modify ( didSet: { self . observer. send ( value: $0) } ) { value in
685- return try action ( & value)
686+ return try box. begin { storage in
687+ defer { observer. send ( value: storage. value) }
688+ return try storage. modify ( action)
686689 }
687690 }
688691
689692 /// Atomically modifies the variable.
690693 ///
694+ /// - warning: The reference should not be escaped.
695+ ///
691696 /// - parameters:
692- /// - didSet: A closure that is invoked after `action` returns and the value is
693- /// committed to the storage, but before `modify` releases the lock.
694- /// - action: A closure that accepts old property value and returns a new
695- /// property value.
697+ /// - action: A closure that accepts a reference to the property storage.
696698 ///
697699 /// - returns: The result of the action.
698700 @discardableResult
699- internal func modify< Result> ( didSet: ( ) -> Void , _ action: ( inout Value ) throws -> Result ) rethrows -> Result {
700- return try box. modify ( didSet: { self . observer. send ( value: $0) ; didSet ( ) } ) { value in
701- return try action ( & value)
702- }
701+ internal func begin< Result> ( _ action: ( PropertyStorage < Value > ) throws -> Result ) rethrows -> Result {
702+ return try box. begin ( action)
703703 }
704704
705705 /// Atomically performs an arbitrary action using the current value of the
@@ -719,16 +719,40 @@ public final class MutableProperty<Value>: ComposableMutablePropertyProtocol {
719719 }
720720}
721721
722+ internal struct PropertyStorage < Value> {
723+ private unowned let box : PropertyBox < Value >
724+
725+ var value : Value {
726+ return box. _value
727+ }
728+
729+ func modify< Result> ( _ action: ( inout Value ) throws -> Result ) rethrows -> Result {
730+ guard !box. isModifying else { fatalError ( " Nested modifications violate exclusivity of access. " ) }
731+ box. isModifying = true
732+ defer { box. isModifying = false }
733+ return try action ( & box. _value)
734+ }
735+
736+ fileprivate init ( _ box: PropertyBox < Value > ) {
737+ self . box = box
738+ }
739+ }
740+
722741/// A reference counted box which holds a recursive lock and a value storage.
723742///
724743/// The requirement of a `Value?` storage from composed properties prevents further
725744/// implementation sharing with `MutableProperty`.
726745private final class PropertyBox < Value> {
746+
727747 private let lock : Lock . PthreadLock
728- private var _value : Value
729- private var isModifying = false
748+ fileprivate var _value : Value
749+ fileprivate var isModifying = false
730750
731- var value : Value { return modify { $0 } }
751+ internal var value : Value {
752+ lock. lock ( )
753+ defer { lock. unlock ( ) }
754+ return _value
755+ }
732756
733757 init ( _ value: Value ) {
734758 _value = value
@@ -741,11 +765,9 @@ private final class PropertyBox<Value> {
741765 return try action ( _value)
742766 }
743767
744- func modify < Result> ( didSet : ( Value ) -> Void = { _ in } , _ action: ( inout Value ) throws -> Result ) rethrows -> Result {
768+ func begin < Result> ( _ action: ( PropertyStorage < Value > ) throws -> Result ) rethrows -> Result {
745769 lock. lock ( )
746- guard !isModifying else { fatalError ( " Nested modifications violate exclusivity of access. " ) }
747- isModifying = true
748- defer { isModifying = false ; didSet ( _value) ; lock. unlock ( ) }
749- return try action ( & _value)
770+ defer { lock. unlock ( ) }
771+ return try action ( PropertyStorage ( self ) )
750772 }
751773}
0 commit comments