@@ -51,38 +51,76 @@ public typealias EnvironmentMutation = (DecisionEnvironment) -> Void
5151 }
5252
5353 func make( decision: Decision ) {
54- /**
55- 1. Create a temporary environment, something to enable transactions
56- 2. Perform that mutation
57- 3. Execute effects
58- */
5954 decision. mutate ( self )
55+ observers. forEach { $0. send ( ) }
56+ performEffects ( )
57+ observers = [ ]
6058 }
6159
62- func perform( effect: Effect ) {
63-
60+ func performEffects( ) {
61+
62+ }
63+
64+ private var observers : Set < Observer > = [ ]
65+
66+ func getValue< Root: StateRoot , Value> ( _ path: KeyPath < Root , ValueStorage < Value > > ) -> Value {
67+ let root = environment. get ( Root . self)
68+ let observableValue = root [ keyPath: path]
69+ return observableValue. value
70+ }
71+
72+ func set< Root: StateRoot , Value> ( value newValue: Value , path: KeyPath < Root , ValueStorage < Value > > ) {
73+ let root = environment. get ( Root . self)
74+ let observableValue = root [ keyPath: path]
75+ // We pop all observers of the observable values mutated by the decision.
76+ // it also will prevent their observers to be notified
77+ // until decision application is complete.
78+ let valueObservers = observableValue. observation. popObservers ( )
79+ // then we add them into set of all the observers that we will notify
80+ // when all states affected by decision are mutated.
81+ // this way we squash all the updates to:
82+ // Each observer notified **once**,
83+ // regardless how many values were updated.
84+ // E.g. some object observes `A.a` `A.b` and `B.a` where A and B are roots.
85+ // and .a .b are values.
86+ // Decision updates all of them, but since it's a single observer (Observer.id),
87+ // it will only get one update.
88+ observers. formUnion ( valueObservers)
89+ observableValue. value = newValue
6490 }
6591
6692 /**
6793 Subscript to direct read/write access to any atomic state.
6894 */
69- public subscript< Root: StateRoot , Value> ( _ path: KeyPath < Root , ObservableValue < Value > > ) -> Value {
70- get {
71- let root = environment. get ( Root . self)
72- let observableValue = root [ keyPath: path]
73- return observableValue. wrappedValue
74- }
75- set {
76- let root = environment. get ( Root . self)
77- let observableValue = root [ keyPath: path]
78- observableValue. set ( value: newValue)
79- }
95+ public subscript<
96+ Root: StateRoot ,
97+ Value
98+ > (
99+ _ path: KeyPath < Root , ObservableValue < Value > >
100+ ) -> Value {
101+ get { getValue ( path. appending ( path: \. storage) ) }
102+ set { set ( value: newValue, path: path. appending ( path: \. storage) ) }
103+ }
104+
105+ public subscript<
106+ Root: StateRoot ,
107+ Wrapper: ObservableValueStorageWrapper ,
108+ Value
109+ > (
110+ path: KeyPath < Root , Wrapper >
111+ ) -> Value where Wrapper. Value == Value {
112+ get { getValue ( path. appending ( path: \. storage) ) }
113+ set { set ( value: newValue, path: path. appending ( path: \. storage) ) }
80114 }
81115
82116 /**
83117 Subscript to direct read/write access to any identified state.
84118 */
85- public subscript< Identifier: Hashable , Root: IdentifiedStateRoot , Value> (
119+ public subscript<
120+ Identifier: Hashable ,
121+ Root: IdentifiedStateRoot ,
122+ Value
123+ > (
86124 _ path: KeyPath < Root , ObservableValue < Value > > ,
87125 at id: Identifier
88126 ) -> Value where Root. Identifier == Identifier {
@@ -93,7 +131,7 @@ public typealias EnvironmentMutation = (DecisionEnvironment) -> Void
93131 }
94132 set {
95133 let root = environment. get ( Root . self, at: id)
96- let observableValue = root [ keyPath: path]
134+ let observableValue = root [ keyPath: path. appending ( path : \ . storage ) ]
97135 observableValue. set ( value: newValue)
98136 }
99137 }
0 commit comments