Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //: [Previous](@previous)
- import Foundation
- protocol Changable {
- associatedtype Change
- mutating func apply(_ diff: Change)
- }
- extension Array: Changable {
- enum Change {
- case insert(Element, at: Index)
- case remove(at: Index)
- }
- mutating func apply(_ diff: Change) {
- switch diff {
- case let .insert(element, at: i):
- self.insert(element, at: i)
- case let .remove(at: i):
- self.remove(at: i)
- }
- }
- }
- // what does filter do? we want to filter changes!
- final class Box<A> where A: Changable {
- private(set) var value: A
- private var observers: [(Pending<A>) -> ()] = []
- init(_ value: A) {
- self.value = value
- }
- func change(_ change: A.Change) {
- let old = value
- value.apply(change)
- for o in observers {
- o(Pending(oldValue: old, change: change))
- }
- }
- func map<B: Changable>(_ f: (A) -> (B, (Pending<A>) -> B.Change?)) -> Box<B> {
- let (initial, transform) = f(value)
- let result = Box<B>(initial)
- observers.append { pending in
- if let c = transform(pending) {
- result.change(c)
- }
- }
- return result
- }
- func addObserver(_ o: @escaping (Pending<A>) -> ()) {
- observers.append(o)
- }
- }
- struct Pending<A: Changable> {
- let oldValue: A
- let change: A.Change
- }
- extension Array {
- fileprivate func filteredIndex(_ filterCond: (Element) -> Bool, at index: Int) -> Int {
- var result = 0
- guard index > 0 else { return 0 }
- for i in 0..<(index-1) {
- if !filterCond(self[i]) { result += 1 }
- }
- return result
- }
- func filtered(_ isIncluded: @escaping (Element) -> Bool) -> ([Element], (Pending<[Element]>) -> Change?) {
- let result = filter(isIncluded)
- return (result, { pending in
- switch pending.change {
- case let .insert(el, at: i):
- guard isIncluded(el) else { return nil }
- return .insert(el, at: pending.oldValue.filteredIndex(isIncluded, at: i)) // todo index
- case let .remove(at: i):
- guard isIncluded(pending.oldValue[i]) else { return nil }
- return .remove(at: i) // todo index
- }
- })
- }
- }
- let x = Box([1,2,3,4])
- let y = x.map { $0.filtered { $0 % 2 == 0 }}
- y.addObserver {
- print($0)
- print(y.value)
- }
- y.value
- x.change(.insert(0, at: 4))
Add Comment
Please, Sign In to add comment