Last active
July 7, 2022 19:47
-
-
Save cooler333/029db0c43fb6e36a49f0aa043ee54a7e to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
import PlaygroundSupport | |
PlaygroundPage.current.needsIndefiniteExecution = true | |
// 1 | |
struct User: Equatable { | |
// 2 | |
struct Address: Equatable { | |
var street: String | |
} | |
struct Phone: Equatable { | |
var number: String = "+7" | |
} | |
// 3 | |
enum Role { | |
// 4 | |
enum Permission { | |
case create | |
case read | |
case update | |
case delete | |
} | |
case admin | |
case member | |
case guest | |
var permissions: [Permission] { | |
switch self { | |
case .admin: | |
return [.create, .read, .update, .delete] | |
case .member: | |
return [.create, .read] | |
case .guest: | |
return [.read] | |
} | |
} | |
} | |
var name: String | |
let email: String | |
var address: Address? | |
var phone: Phone = .init() | |
let role: Role | |
} | |
struct Reducer<State, Action> { | |
let reduce: (State, Action) -> State | |
} | |
final class Store<State: Equatable, Action> { | |
private var stateGetter: (() -> State)! | |
private var stateSetter: ((State) -> Void)! | |
var state: State { | |
get { stateGetter() } | |
set { stateSetter(newValue) } | |
} | |
var _state: State! { | |
didSet { | |
listners.forEach { listner in | |
listner() | |
} | |
} | |
} | |
let reducer: Reducer<State, Action> | |
var listners: [() -> Void] = [] | |
func addListener(_ listener: @escaping () -> Void) { | |
listners.append(listener) | |
} | |
init( | |
state: State, | |
reducer: Reducer<State, Action> | |
) { | |
self.reducer = reducer | |
self._state = state | |
self.stateGetter = { [unowned self] in | |
return self._state | |
} | |
self.stateSetter = { [unowned self] state in | |
self._state = state | |
} | |
} | |
private init( | |
stateSetter: @escaping (State) -> Void, | |
stateGetter: @escaping () -> State, | |
reducer: Reducer<State, Action> | |
) { | |
self.stateSetter = stateSetter | |
self.stateGetter = stateGetter | |
self.reducer = reducer | |
} | |
func dispatch(_ action: Action) { | |
state = reducer.reduce(state, action) | |
} | |
func createChildStore<ChildState, ChildAction>( | |
keyPath: WritableKeyPath<State, ChildState>, | |
reducer: Reducer<ChildState, ChildAction> | |
) -> Store<ChildState, ChildAction> { | |
let s = Store<ChildState, ChildAction>( | |
stateSetter: { self.state[keyPath: keyPath] = $0 }, | |
stateGetter: { self.state[keyPath: keyPath] }, | |
reducer: reducer | |
) | |
addListener({ [weak s] in | |
guard let s = s else { return } | |
s.listners.forEach { listner in | |
listner() | |
} | |
}) | |
return s | |
} | |
} | |
let subReducer = Reducer<Optional<User.Address>, String>(reduce: { state, action in | |
if var state = state { | |
state.street += ", " + action + "sub" | |
return state | |
} else { | |
return .init(street: "initial " + action) | |
} | |
}) | |
let reducer: Reducer<User, Int> = Reducer( | |
reduce: { state, action in | |
var state = state | |
state.name += "\(action)" | |
return state | |
} | |
) | |
let store = Store<User, Int>( | |
state: User( | |
name: "", | |
email: "", | |
address: nil, | |
role: .guest | |
), | |
reducer: reducer | |
) | |
var aaa = Date().timeIntervalSince1970 | |
let initialAAA = aaa | |
print(Date().timeIntervalSince1970 - aaa, "Baseline") | |
aaa = Date().timeIntervalSince1970 | |
let stores = Array(0...1000).map { _ -> Store<Optional<User.Address>, String> in | |
let subStore = store.createChildStore(keyPath: \.address, reducer: subReducer) | |
return subStore | |
} | |
print(Date().timeIntervalSince1970 - aaa, "createChildStore") | |
aaa = Date().timeIntervalSince1970 | |
var updateCount = 0 | |
stores.first?.listners.append { | |
updateCount += 1 | |
} | |
print(Date().timeIntervalSince1970 - aaa, "updateCount") | |
aaa = Date().timeIntervalSince1970 | |
Array(0...2).forEach { index in | |
stores.first!.dispatch("\(index)") | |
} | |
print(Date().timeIntervalSince1970 - aaa, "stores.first dispatch 3") | |
aaa = Date().timeIntervalSince1970 | |
Array(0...100).forEach { index in | |
stores.last!.dispatch("\(index)") | |
} | |
print(Date().timeIntervalSince1970 - aaa, "stores.last dispatch 101 (* 1000)") | |
if Date().timeIntervalSince1970 - aaa > 1 { | |
print("TOO MUCH") | |
} | |
aaa = Date().timeIntervalSince1970 | |
stores.last!.dispatch("final") | |
print(Date().timeIntervalSince1970 - aaa, "stores.last dispatch final") | |
aaa = Date().timeIntervalSince1970 | |
store.dispatch(1) | |
store.dispatch(2) | |
store.dispatch(3) | |
store.dispatch(4) | |
print(Date().timeIntervalSince1970 - aaa, "rootStore dispatch 1,2,3,4") | |
aaa = Date().timeIntervalSince1970 | |
stores.last!.dispatch("123") | |
print(Date().timeIntervalSince1970 - aaa, "stores.last dispatch 123") | |
aaa = Date().timeIntervalSince1970 | |
print(store.state.name) | |
print(store.state.address?.street ?? "null") | |
print("IS SUBSTORES EQUAL: ", stores.first!.state?.street ?? "null" == stores.last!.state?.street ?? "null") | |
print("IS SUB & STORE EQUAL: ", stores.last!.state?.street ?? "null" == store.state.address?.street ?? "null") | |
print(Date().timeIntervalSince1970 - initialAAA, "final") | |
print("Update count:", updateCount) | |
print("IS UPDATE COUNT 110?", updateCount == 110 ? "TRUE" : "FALSE") | |
// 0.0002391338348388672 Baseline | |
// 1.5412371158599854 createChildStore | |
// 0.000701904296875 updateCount | |
// 0.027843952178955078 stores.first dispatch 3 | |
// 0.9228630065917969 stores.last dispatch 101 (* 1000) | |
// 0.009496927261352539 stores.last dispatch final | |
// 0.04581594467163086 rootStore dispatch 1,2,3,4 | |
// 0.009209156036376953 stores.last dispatch 123 | |
// 1234 | |
// initial 0, 1sub, 2sub, 0sub, 1sub, 2sub, 3sub, 4sub, 5sub, 6sub, 7sub, 8sub, 9sub, 10sub, 11sub, 12sub, 13sub, 14sub, 15sub, 16sub, 17sub, 18sub, 19sub, 20sub, 21sub, 22sub, 23sub, 24sub, 25sub, 26sub, 27sub, 28sub, 29sub, 30sub, 31sub, 32sub, 33sub, 34sub, 35sub, 36sub, 37sub, 38sub, 39sub, 40sub, 41sub, 42sub, 43sub, 44sub, 45sub, 46sub, 47sub, 48sub, 49sub, 50sub, 51sub, 52sub, 53sub, 54sub, 55sub, 56sub, 57sub, 58sub, 59sub, 60sub, 61sub, 62sub, 63sub, 64sub, 65sub, 66sub, 67sub, 68sub, 69sub, 70sub, 71sub, 72sub, 73sub, 74sub, 75sub, 76sub, 77sub, 78sub, 79sub, 80sub, 81sub, 82sub, 83sub, 84sub, 85sub, 86sub, 87sub, 88sub, 89sub, 90sub, 91sub, 92sub, 93sub, 94sub, 95sub, 96sub, 97sub, 98sub, 99sub, 100sub, finalsub, 123sub | |
// IS SUBSTORES EQUAL: true | |
// IS SUB & STORE EQUAL: true | |
// 2.5582311153411865 final | |
// Update count: 110 | |
// IS UPDATE COUNT 110? TRUE |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment