Optimize Portico state and collection updates
This commit is contained in:
parent
af7fa6656d
commit
3919f1fe34
150 changed files with 2129 additions and 2387 deletions
|
|
@ -16,6 +16,48 @@ import Testing
|
|||
#expect(seen == [2, 3])
|
||||
}
|
||||
|
||||
@Test func reentrantSetDoesNotClobberOuterNotify() {
|
||||
let box = StateBox(0)
|
||||
var log: [Int] = []
|
||||
var didReenter = false
|
||||
for _ in 0..<3 {
|
||||
_ = box.subscribe { value in
|
||||
log.append(value)
|
||||
if !didReenter {
|
||||
didReenter = true
|
||||
box.set(99)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
box.set(1)
|
||||
|
||||
#expect(log.count == 6)
|
||||
#expect(log.filter { $0 == 1 }.count == 3)
|
||||
#expect(log.filter { $0 == 99 }.count == 3)
|
||||
let nestedIndexes = log.indices.filter { log[$0] == 99 }
|
||||
#expect(nestedIndexes.count == 3)
|
||||
#expect(nestedIndexes.last! - nestedIndexes.first! == 2)
|
||||
#expect(box.peek() == 99)
|
||||
}
|
||||
|
||||
@Test func setIfChangedSkipsEqualWrites() {
|
||||
let box = StateBox(7)
|
||||
var callCount = 0
|
||||
_ = box.subscribe { _ in callCount += 1 }
|
||||
let binding = Binding(box)
|
||||
|
||||
binding.setIfChanged(7)
|
||||
|
||||
#expect(callCount == 0)
|
||||
#expect(box.peek() == 7)
|
||||
|
||||
binding.setIfChanged(8)
|
||||
|
||||
#expect(callCount == 1)
|
||||
#expect(box.peek() == 8)
|
||||
}
|
||||
|
||||
@Test func cancelStopsNotifications() {
|
||||
let box = StateBox(0)
|
||||
var callCount = 0
|
||||
|
|
|
|||
|
|
@ -26,6 +26,81 @@ import Adw
|
|||
#expect(box.peek() == false)
|
||||
}
|
||||
|
||||
@Test func detailedNotifyDoesNotCrossProperties() {
|
||||
guard Gtk.initCheck() else { return }
|
||||
let context = MountContext()
|
||||
let widget = Gtk.Switch()
|
||||
let active = StateBox(false)
|
||||
let sensitive = StateBox(true)
|
||||
var activeSetCount = 0
|
||||
var sensitiveSetCount = 0
|
||||
let activeBinding = Binding<Bool>(
|
||||
get: { active.peek() },
|
||||
set: { value in
|
||||
activeSetCount += 1
|
||||
active.set(value)
|
||||
}
|
||||
)
|
||||
let sensitiveBinding = Binding<Bool>(
|
||||
get: { sensitive.peek() },
|
||||
set: { value in
|
||||
sensitiveSetCount += 1
|
||||
sensitive.set(value)
|
||||
}
|
||||
)
|
||||
|
||||
Portico.bindProperty(
|
||||
widget,
|
||||
activeBinding,
|
||||
registry: context.registry,
|
||||
notifyDetail: "active",
|
||||
read: { widget.getActive() },
|
||||
write: { widget.setActive(isActive: $0) }
|
||||
)
|
||||
Portico.bindProperty(
|
||||
widget,
|
||||
sensitiveBinding,
|
||||
registry: context.registry,
|
||||
notifyDetail: "sensitive",
|
||||
read: { widget.getSensitive() },
|
||||
write: { widget.setSensitive(sensitive: $0) }
|
||||
)
|
||||
|
||||
// Keep active out of sync without sending a widget notification. A
|
||||
// broadcast handler would now observe active=true and invoke its setter
|
||||
// when the unrelated sensitive property changes.
|
||||
widget.setActive(isActive: true)
|
||||
active.set(false)
|
||||
activeSetCount = 0
|
||||
sensitiveSetCount = 0
|
||||
|
||||
widget.setSensitive(sensitive: false)
|
||||
|
||||
#expect(activeSetCount == 0)
|
||||
#expect(sensitiveSetCount == 1)
|
||||
#expect(active.peek() == false)
|
||||
#expect(sensitive.peek() == false)
|
||||
}
|
||||
|
||||
@Test func unresolvableDetailFallsBackToBroadcast() {
|
||||
guard Gtk.initCheck() else { return }
|
||||
let box = StateBox(false)
|
||||
let context = MountContext()
|
||||
let widget = Gtk.Switch()
|
||||
Portico.bindProperty(
|
||||
widget,
|
||||
Binding(box),
|
||||
registry: context.registry,
|
||||
notifyDetail: "not-a-real-property",
|
||||
read: { widget.getActive() },
|
||||
write: { widget.setActive(isActive: $0) }
|
||||
)
|
||||
|
||||
widget.setActive(isActive: true)
|
||||
|
||||
#expect(box.peek() == true)
|
||||
}
|
||||
|
||||
// MARK: - SpinRow value
|
||||
|
||||
/// Adw.SpinRow.value propagates both directions via notify.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue