-
-
Notifications
You must be signed in to change notification settings - Fork 8
Expand file tree
/
Copy pathJSON.ArrayEncoder.swift
More file actions
75 lines (69 loc) · 2.34 KB
/
JSON.ArrayEncoder.swift
File metadata and controls
75 lines (69 loc) · 2.34 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
import JSONAST
extension JSON {
@frozen public struct ArrayEncoder: Sendable {
@usableFromInline var first: Bool
@usableFromInline var json: JSON
@inlinable init(json: JSON) {
self.first = true
self.json = json
}
}
}
extension JSON.ArrayEncoder: JSON.InlineEncoder {
@inlinable static func move(_ json: inout JSON) -> Self {
json.utf8.append(0x5B) // '['
defer { json.utf8 = [] }
return .init(json: json)
}
@inlinable mutating func move() -> JSON {
self.first = true
self.json.utf8.append(0x5D) // ']'
defer { self.json.utf8 = [] }
return self.json
}
}
extension JSON.ArrayEncoder {
/// Creates a nested JSON encoding context.
///
/// This accessor isn’t very useful on its own, rather, you should chain it with a call to
/// ``JSON.callAsFunction(_:yield:)`` to bind the context to a particular coding key.
///
/// You can also encode values directly with this accessor, via the `encode(to: &$0.next)`
/// pattern, although the ``subscript(_:)`` setter is probably more convenient for that.
@inlinable public var next: JSON {
_read {
yield .init(utf8: [])
}
_modify {
if self.first {
self.first = false
} else {
self.json.utf8.append(0x2C) // ','
}
yield &self.json
}
}
/// Creates a nested object encoding context.
@inlinable public mutating func callAsFunction<Key>(
_: Key.Type = Key.self,
_ yield: (inout JSON.ObjectEncoder<Key>) -> ()
) {
yield(&self.next[as: JSON.ObjectEncoder<Key>.self])
}
/// Creates a nested array encoding context.
@inlinable public mutating func callAsFunction(
_ yield: (inout JSON.ArrayEncoder) -> ()
) {
yield(&self.next[as: Self.self])
}
/// Appends a value to the array.
///
/// Why a subscript and not an `append` method? Because we often want to optionally append a
/// value while building an array, and the subscript syntax is more convenient for that.
@inlinable public subscript<Encodable>(
_: (Index) -> Void
) -> Encodable? where Encodable: JSONEncodable {
get { nil }
set (value) { value?.encode(to: &self.next) }
}
}