-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathNodeRowCalculatable.swift
More file actions
103 lines (81 loc) · 3.38 KB
/
NodeRowCalculatable.swift
File metadata and controls
103 lines (81 loc) · 3.38 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
//
// NodeRowCalculatable.swift
//
//
// Created by Elliot Boschwitz on 6/8/24.
//
import Foundation
public protocol NodeRowCalculatable: AnyObject, Identifiable where ID == RowID {
associatedtype RowID: NodeRowId
associatedtype PortData: Equatable
// A given port (input or output) has a loop of values
@MainActor var values: [PortData] { get set }
// TODO: move into `InputNodeRowCalculatable`, since only for inputs?
@MainActor var containsUpstreamConnection: Bool { get }
// TODO: put into separate `OutputNodeRowCalculatable` protocol, since only for outputs?
@MainActor func updateOutputValues(_ values: [PortData])
@MainActor func updatePortViewModels(_ graph: any GraphCalculatable)
}
public protocol InputNodeRowCalculatable: NodeRowCalculatable {
associatedtype OutputRowID: NodeRowId
@MainActor var isPulseNodeType: Bool { get }
@MainActor var values: [PortData] { get set }
@MainActor func coerce(theseValues: [PortData],
toThisType: PortData,
currentGraphTime: TimeInterval,
isCycleRedEdge: Bool) -> [PortData]
@MainActor func didInputsUpdate(newValues: [PortData],
oldValues: [PortData])
@MainActor var upstreamOutputCoordinate: OutputRowID? { get }
}
extension InputNodeRowCalculatable {
@MainActor public var containsUpstreamConnection: Bool {
self.upstreamOutputCoordinate != nil
}
}
extension InputNodeRowCalculatable {
@MainActor public func setValuesInInput(_ values: [Self.PortData]) {
let oldValues = self.values
self.values = values
self.didInputsUpdate(newValues: values,
oldValues: oldValues)
}
}
extension Array where Element: NodeRowCalculatable {
@MainActor
public var values: [[Element.PortData]] {
self.map {
$0.values
}
}
}
extension NodeCalculatable {
// fka `updateAllValues`; but renamed since only actually for outputs
@MainActor
func updateOutputs(_ newValuesList: [[PortData]],
nodeDelegate: Self) {
let oldValuesList: [[PortData]] = self.outputsValuesList
let oldPortCount = oldValuesList.count
let newPortCount = newValuesList.count
let currentObserverCount = oldValuesList.count
// Remove view models if loop count decreased
if newPortCount < oldPortCount {
// Sub-array can't exceed its current bounds or we get index-out-of-bounds
// Helpers below will create any missing observers
let arrayBoundary = Swift.min(newPortCount, currentObserverCount)
// Shortens input port count when inputs removed from user
self.outputsObservers = Array(self.outputsObservers[..<arrayBoundary])
}
guard oldValuesList != newValuesList else { return }
newValuesList.enumerated().forEach { portId, values in
guard let observer = self.outputsObservers[safe: portId] else {
fatalErrorIfDebug()
return
}
// Only update values if there's no upstream connection
if !observer.containsUpstreamConnection {
observer.updateOutputValues(values)
}
}
}
}