@@ -111,6 +111,73 @@ object BidirectionalVarOperatorTests extends TestSuite {
111111 assert(zipcode.now == 6 )
112112 }
113113
114+ " zoomed Var chained" - {
115+ import Ctx .Owner .Unsafe ._
116+
117+ case class Company (name : String , zipcode : Int )
118+ case class Employee (name : String , company : Company )
119+
120+ val employee = Var (Employee (" jules" , Company (" wules" , 7 )))
121+ val company = employee.zoom(_.company)((old, value) => old.copy(company = value))
122+ val zipcode = company.zoom(_.zipcode)((old, value) => old.copy(zipcode = value))
123+
124+ assert(company.now == Company (" wules" , 7 ))
125+ assert(employee.now == Employee (" jules" , Company (" wules" , 7 )))
126+ assert(zipcode.now == 7 )
127+
128+ zipcode() = 8
129+ assert(company.now == Company (" wules" , 8 ))
130+ assert(employee.now == Employee (" jules" , Company (" wules" , 8 )))
131+ assert(zipcode.now == 8 )
132+
133+ employee() = Employee (" gula" , Company (" bori" , 6 ))
134+ assert(company.now == Company (" bori" , 6 ))
135+ assert(employee.now == Employee (" gula" , Company (" bori" , 6 )))
136+ assert(zipcode.now == 6 )
137+
138+ company() = Company (" borislav" , 13 )
139+ assert(company.now == Company (" borislav" , 13 ))
140+ assert(employee.now == Employee (" gula" , Company (" borislav" , 13 )))
141+ assert(zipcode.now == 13 )
142+ }
143+
144+ " zoomed Var chained with observer" - {
145+ import Ctx .Owner .Unsafe ._
146+
147+ case class Company (name : String , zipcode : Int )
148+ case class Employee (name : String , company : Company )
149+
150+ val employee = Var (Employee (" jules" , Company (" wules" , 7 )))
151+ val company = employee.zoom(_.company)((old, value) => old.copy(company = value))
152+ val zipcode = company.zoom(_.zipcode)((old, value) => old.copy(zipcode = value))
153+
154+ var employeeNow = employee.now
155+ employee.foreach { employeeNow = _ }
156+
157+ assert(company.now == Company (" wules" , 7 ))
158+ assert(employeeNow == Employee (" jules" , Company (" wules" , 7 )))
159+ assert(employee.now == Employee (" jules" , Company (" wules" , 7 )))
160+ assert(zipcode.now == 7 )
161+
162+ zipcode() = 8
163+ assert(company.now == Company (" wules" , 8 ))
164+ assert(employeeNow == Employee (" jules" , Company (" wules" , 8 )))
165+ assert(employee.now == Employee (" jules" , Company (" wules" , 8 )))
166+ assert(zipcode.now == 8 )
167+
168+ employee() = Employee (" gula" , Company (" bori" , 6 ))
169+ assert(company.now == Company (" bori" , 6 ))
170+ assert(employeeNow == Employee (" gula" , Company (" bori" , 6 )))
171+ assert(employee.now == Employee (" gula" , Company (" bori" , 6 )))
172+ assert(zipcode.now == 6 )
173+
174+ company() = Company (" borislav" , 13 )
175+ assert(company.now == Company (" borislav" , 13 ))
176+ assert(employeeNow == Employee (" gula" , Company (" borislav" , 13 )))
177+ assert(employee.now == Employee (" gula" , Company (" borislav" , 13 )))
178+ assert(zipcode.now == 13 )
179+ }
180+
114181 " isomorphic Var function calls" - {
115182 import Ctx .Owner .Unsafe ._
116183
@@ -205,28 +272,100 @@ object BidirectionalVarOperatorTests extends TestSuite {
205272 assert(selectedItem.now == Some (4 ))
206273 }
207274
208- " mapRead then zoom" - {
275+ " mapRead observer" - {
276+ import Ctx .Owner .Unsafe ._
277+
278+ val list = Var (List (1 , 2 , 3 ))
279+ val selectedItem = Var [Option [Int ]](Some (1 )).mapRead {
280+ selected => selected().filter(list() contains _)
281+ }
282+ var myNow : Option [Int ] = None
283+ selectedItem.foreach { myNow = _ }
284+
285+ assert(myNow == Some (1 ))
286+
287+ selectedItem() = Some (4 )
288+ assert(myNow == None )
289+
290+ list.update(4 :: _)
291+ assert(myNow == Some (4 ))
292+ }
293+
294+ " mapRead then zoom (write into outer)" - {
209295 import Ctx .Owner .Unsafe ._
210- case class Store (selected: Option [Int ])
296+ case class SelectedWrapper (selected: Option [Int ])
211297
212298 val list = Var (List (1 , 2 , 3 ))
213- val store = Var [Store ]( Store (Some (1 ))).mapRead {
214- store => store ().copy(selected = store ().selected.filter(list() contains _))
299+ val selWrapper = Var [SelectedWrapper ]( SelectedWrapper (Some (1 ))).mapRead {
300+ selWrapper => selWrapper ().copy(selected = selWrapper ().selected.filter(list() contains _))
215301 }
216- val selectedItem = store .zoom(_.selected)((store ,selected) => store .copy(selected = selected))
302+ val selectedItem = selWrapper .zoom(_.selected)((selWrapper ,selected) => selWrapper .copy(selected = selected))
217303
304+ assert(selWrapper.now.selected == Some (1 ))
218305 assert(selectedItem.now == Some (1 ))
219306
220- selectedItem() = Some (3 )
307+ selWrapper() = SelectedWrapper (Some (4 ))
308+ assert(selWrapper.now.selected == None )
221309 assert(selectedItem.now == None ) // fail: is Some(3) ...
222310
223311 list.update(4 :: _)
224- assert(selectedItem.now == None ) // fail: still is Some(3)
312+ assert(selWrapper.now.selected == Some (4 ))
313+ assert(selectedItem.now == Some (4 )) // fail: still is Some(3)
314+
315+ selWrapper() = SelectedWrapper (Some (4 ))
316+ assert(selWrapper.now.selected == Some (4 ))
317+ assert(selectedItem.now == Some (4 ))
318+ }
319+
320+ " mapRead then zoom (write into zoomed)" - {
321+ import Ctx .Owner .Unsafe ._
322+ case class SelectedWrapper (selected: Option [Int ])
323+
324+ val list = Var (List (1 , 2 , 3 ))
325+ val selWrapper = Var [SelectedWrapper ](SelectedWrapper (Some (1 )))
326+ val selWrapperFiltered = selWrapper.mapRead {
327+ selWrapper => selWrapper().copy(selected = selWrapper().selected.filter(list() contains _))
328+ }
329+ val selectedItem = selWrapperFiltered.zoom(_.selected)((selWrapper,selected) => selWrapper.copy(selected = selected))
330+
331+ assert(selWrapper.now.selected == Some (1 ))
332+ assert(selWrapperFiltered.now.selected == Some (1 ))
333+ assert(selectedItem.now == Some (1 ))
334+
335+ selectedItem() = Some (4 ) // write indirectly into selWrapper
336+ assert(selWrapper.now.selected == Some (4 ))
337+ assert(selWrapperFiltered.now.selected == None )
338+ assert(selectedItem.now == None ) // fail: is Some(3) ...
339+
340+ list.update(4 :: _)
341+ assert(selWrapper.now.selected == Some (4 ))
342+ assert(selWrapperFiltered.now.selected == Some (4 ))
343+ assert(selectedItem.now == Some (4 )) // fail: still is Some(3)
225344
226345 selectedItem() = Some (4 )
346+ assert(selWrapper.now.selected == Some (4 ))
347+ assert(selWrapperFiltered.now.selected == Some (4 ))
227348 assert(selectedItem.now == Some (4 ))
228349 }
229350
351+ " imap then zoom (write into zoomed)" - {
352+ import Ctx .Owner .Unsafe ._
353+ case class Wrapper (x: Int )
354+ val base = Var (Wrapper (5 ))
355+ val imapped = base.imap(w => w.copy(x = w.x + 1 ))(w => w.copy(x = w.x - 1 ))
356+ val zoomed = imapped.zoom(_.x)( (old, value) => old.copy(x = value))
357+
358+ zoomed() = 1
359+ assert(zoomed.now == 1 )
360+ assert(imapped.now == Wrapper (1 ))
361+ assert(base.now == Wrapper (0 ))
362+
363+ zoomed() = 2
364+ assert(zoomed.now == 2 )
365+ assert(imapped.now == Wrapper (2 ))
366+ assert(base.now == Wrapper (1 ))
367+ }
368+
230369 " mapRead function calls" - {
231370 import Ctx .Owner .Unsafe ._
232371
0 commit comments