-
-
Notifications
You must be signed in to change notification settings - Fork 43
Expand file tree
/
Copy pathPropertyVariableTreeNode+CodingData.swift
More file actions
113 lines (105 loc) · 4 KB
/
PropertyVariableTreeNode+CodingData.swift
File metadata and controls
113 lines (105 loc) · 4 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
104
105
106
107
108
109
110
111
112
113
import OrderedCollections
import SwiftSyntax
import SwiftSyntaxBuilder
import SwiftSyntaxMacros
extension PropertyVariableTreeNode {
/// A type storing variable and `CodingKey`
/// data using the "trie" tree algorithm.
///
/// Use `register` method to register new data and
/// use this data to choose which variables to decode in
/// `PropertyVariableTreeNode`.
///
/// See https://en.wikipedia.org/wiki/Trie
/// for more information.
struct CodingData: VariableTreeNode {
/// All the variables registered at this node.
var variables: [any PropertyVariable] = []
/// Nested registration node associated with keys.
var children = OrderedDictionary<CodingKeysMap.Key, Self>()
/// Whether the encoding container variable linked to this node
/// should be declared as immutable.
///
/// This is used to suppress mutability warning in case of
/// internally tagged enums.
var immutableEncodeContainer: Bool = false
}
}
protocol VariableTreeNode {
/// All the variables registered at this node.
var variables: [any PropertyVariable] { get set }
/// Nested registration node associated with keys.
var children: OrderedDictionary<CodingKeysMap.Key, Self> { get set }
/// Whether the encoding container variable linked to this node
/// should be declared as immutable.
///
/// This is used to suppress mutability warning in case of
/// internally tagged enums.
var immutableEncodeContainer: Bool { get set }
/// Creates a new tree node instance.
///
/// Creates new node with empty children and data.
init()
}
extension VariableTreeNode {
/// List of all the linked variables registered.
///
/// Gets all variables at current node
/// and children nodes.
var linkedVariables: [any PropertyVariable] {
variables + children.flatMap { $1.linkedVariables }
}
/// Register variable for the provided `CodingKey` path.
///
/// Create node at the `CodingKey` path if doesn't exist
/// and register the variable at the node.
///
/// - Parameters:
/// - variable: The variable data, i.e. name, type and
/// additional macro metadata.
/// - keyPath: The `CodingKey` path where the value
/// will be decode/encoded.
/// - immutableEncodeContainer: Whether the encoding container variable
/// direct parent of `variable` should be declared as immutable.
mutating func register<Variable: PropertyVariable>(
variable: Variable, keyPath: [CodingKeysMap.Key],
immutableEncodeContainer: Bool = false
) {
if keyPath.isEmpty {
let depIndex = variables.firstIndex { $0.depends(on: variable) }
if let index = depIndex {
variables.insert(variable, at: index)
} else {
variables.append(variable)
}
return
}
let key = keyPath.first!
if children[key] == nil {
children[key] = .init()
}
if keyPath.count == 1 {
precondition(
!immutableEncodeContainer
|| linkedVariables.filter { $0.encode ?? true }.isEmpty
)
self.immutableEncodeContainer = immutableEncodeContainer
}
children[key]!.register(
variable: variable,
keyPath: Array(keyPath.dropFirst()),
immutableEncodeContainer: immutableEncodeContainer
)
}
/// Checks whether node has variables registered at the key provided.
///
/// Checks if there is node available at the specified key and it has
/// some variables or nested variables registered.
///
/// - Parameter key: The key to search for.
/// - Returns: Whether this node has children variables at the key.
func hasKey(_ key: CodingKeysMap.Key) -> Bool {
guard let child = children[key] else { return false }
return !child.variables.isEmpty || !child.children.isEmpty
}
}