Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ let package: Package = .init(
.library(name: "JSONAST", targets: ["JSONAST"]),
.library(name: "JSONLegacy", targets: ["JSONLegacy"]),
.library(name: "JavaScriptPersistence", targets: ["JavaScriptPersistence"]),

.library(name: "_JSON_SnippetsAnchor", targets: ["_JSON_SnippetsAnchor"]),
],
dependencies: [
.package(url: "https://github.com/tayloraswift/swift-grammar", from: "0.5.0"),
Expand Down Expand Up @@ -69,6 +71,18 @@ let package: Package = .init(
.target(name: "JSON"),
]
),


.target(
name: "_JSON_SnippetsAnchor",
dependencies: [
.target(name: "JSON"),
],
path: "Snippets/_Anchor",
linkerSettings: [
.linkedLibrary("m"),
],
),
]
)
package.targets = package.targets.map {
Expand Down
3 changes: 3 additions & 0 deletions Snippets/_Anchor/anchor.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/// This target functions as an anchor to remind SwiftPM to link `libm` before trying to compile
/// snippets. Without it, there would be no attachment point for the linker settings, unless we
/// were to dirty the actual library targets with snippet-specific settings
12 changes: 0 additions & 12 deletions Sources/JSONAST/JSON.Node.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,6 @@ extension JSON {
case object(Object)
}
}

extension String {
init(_ literal: JSON.Literal<String>) {
var json: JSON = .init(utf8: [])

json.utf8.reserveCapacity(literal.value.utf8.count + 2)
json += literal

self.init(decoding: json.utf8, as: Unicode.UTF8.self)
}
}

extension JSON.Node {
// TODO: optimize this, it should operate at the utf8 level, and be @inlinable

Expand Down
2 changes: 1 addition & 1 deletion Sources/JSONAST/JSON.Number.Inline.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ extension JSON.Number {
/// The sign of this numeric literal.
public var sign: FloatingPointSign
// cannot have an inlinable property wrapper
@usableFromInline internal var _places: UInt32
@usableFromInline var _places: UInt32
/// The number of decimal places this numeric literal has.
///
/// > Note:
Expand Down
10 changes: 10 additions & 0 deletions Sources/JSONAST/String (ext).swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
extension String {
init(_ literal: JSON.Literal<String>) {
var json: JSON = .init(utf8: [])

json.utf8.reserveCapacity(literal.value.utf8.count + 2)
json += literal

self.init(decoding: json.utf8, as: Unicode.UTF8.self)
}
}
4 changes: 2 additions & 2 deletions Sources/JSONDecoding/Conformances/Array (ext).swift
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
extension Array: JSONDecodable where Element: JSONDecodable {
@inlinable public init(json: JSON.Node) throws {
@inlinable public init(json: borrowing JSON.Node) throws {
try self.init(json: try .init(json: json))
}
}
extension Array where Element: JSONDecodable {
@inlinable public init(json: JSON.Array) throws {
@inlinable public init(json: borrowing JSON.Array) throws {
self = try json.map { try $0.decode(to: Element.self) }
}
}
2 changes: 1 addition & 1 deletion Sources/JSONDecoding/Conformances/Bool (ext).swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
extension Bool: JSONDecodable {
@inlinable public init(json: JSON.Node) throws {
@inlinable public init(json: borrowing JSON.Node) throws {
self = try json.cast { $0.as(Self.self) }
}
}
2 changes: 1 addition & 1 deletion Sources/JSONDecoding/Conformances/Character (ext).swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ extension Character: JSONStringDecodable {
/// witness traps on invalid input instead of returning nil, which
/// causes its default implementation (where `Self: LosslessStringConvertible`)
/// to do the same.
@inlinable public init(json: JSON.Node) throws {
@inlinable public init(json: borrowing JSON.Node) throws {
let string: String = try .init(json: json)
if string.startIndex < string.endIndex,
string.index(after: string.startIndex) == string.endIndex {
Expand Down
6 changes: 3 additions & 3 deletions Sources/JSONDecoding/Conformances/Dictionary (ext).swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ extension Dictionary: JSONDecodable where Key == String, Value: JSONDecodable {
/// Decodes an unordered dictionary from the given document. Dictionaries
/// are not ``JSONEncodable``, because round-tripping them loses the field
/// ordering information.
@inlinable public init(json: JSON.Node) throws {
@inlinable public init(json: borrowing JSON.Node) throws {
try self.init(json: try .init(json: json))
}
@inlinable public init(json: JSON.Object) throws {
@inlinable public init(json: borrowing JSON.Object) throws {
self.init(minimumCapacity: json.count)
for field: JSON.FieldDecoder<String> in json {
for field: JSON.FieldDecoder<String> in copy json {
if case _? = self.updateValue(try field.decode(to: Value.self), forKey: field.key) {
throw JSON.ObjectKeyError<String>.duplicate(field.key)
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/JSONDecoding/Conformances/Double (ext).swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
extension Double: JSONDecodable {
@inlinable public init(json: JSON.Node) throws {
@inlinable public init(json: borrowing JSON.Node) throws {
self = try json.cast { $0.as(Self.self) }
}
}
2 changes: 1 addition & 1 deletion Sources/JSONDecoding/Conformances/Float (ext).swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
extension Float: JSONDecodable {
@inlinable public init(json: JSON.Node) throws {
@inlinable public init(json: borrowing JSON.Node) throws {
self = try json.cast { $0.as(Self.self) }
}
}
2 changes: 1 addition & 1 deletion Sources/JSONDecoding/Conformances/Float16 (ext).swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
@available(macOS 11.0, iOS 14.0, tvOS 14.0, watchOS 7.0, *)
extension Float16: JSONDecodable {
@inlinable public init(json: JSON.Node) throws {
@inlinable public init(json: borrowing JSON.Node) throws {
self = try json.cast { $0.as(Self.self) }
}
}
2 changes: 1 addition & 1 deletion Sources/JSONDecoding/Conformances/Float80 (ext).swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#if (os(Linux) || os(macOS)) && arch(x86_64)
extension Float80: JSONDecodable {
@inlinable public init(json: JSON.Node) throws {
@inlinable public init(json: borrowing JSON.Node) throws {
self = try json.cast { $0.as(Self.self) }
}
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/JSONDecoding/Conformances/Set (ext).swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
extension Set: JSONDecodable where Element: JSONDecodable {
@inlinable public init(json: JSON.Node) throws {
@inlinable public init(json: borrowing JSON.Node) throws {
let array: JSON.Array = try .init(json: json)

self.init()
Expand Down
2 changes: 1 addition & 1 deletion Sources/JSONDecoding/Conformances/String (ext).swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
extension String: JSONStringDecodable {
@inlinable public init(json: JSON.Node) throws {
@inlinable public init(json: borrowing JSON.Node) throws {
self = try json.cast { $0.as(String.self) }
}
}
6 changes: 3 additions & 3 deletions Sources/JSONDecoding/Decoding/JSON.ObjectDecoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ extension JSON {
}
}
extension JSON.ObjectDecoder: JSONDecodable {
@inlinable public init(json: JSON.Node) throws {
@inlinable public init(json: borrowing JSON.Node) throws {
try self.init(indexing: try .init(json: json))
}
}
extension JSON.ObjectDecoder where CodingKey: RawRepresentable<String> {
@inlinable public init(indexing object: JSON.Object) throws {
@inlinable public init(indexing object: borrowing JSON.Object) throws {
self.init(.init(minimumCapacity: object.count))
for field: JSON.FieldDecoder<String> in object {
for field: JSON.FieldDecoder<String> in copy object {
guard let key: CodingKey = .init(rawValue: field.key) else {
continue
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/JSONDecoding/JSON.Array (ext).swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ extension JSON.Array: RandomAccessCollection {
}
}
extension JSON.Array: JSONDecodable {
@inlinable public init(json: JSON.Node) throws {
@inlinable public init(json: borrowing JSON.Node) throws {
self = try json.cast(with: \.array)
}
}
2 changes: 1 addition & 1 deletion Sources/JSONDecoding/JSON.Object (ext).swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ extension JSON.Object: RandomAccessCollection {
}
}
extension JSON.Object: JSONDecodable {
@inlinable public init(json: JSON.Node) throws {
@inlinable public init(json: borrowing JSON.Node) throws {
self = try json.cast(with: \.object)
}
}
8 changes: 4 additions & 4 deletions Sources/JSONDecoding/JSONDecodable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,20 @@ public protocol JSONDecodable {
/// Attempts to cast a JSON variant backed by some storage type to an
/// instance of this type. The implementation can copy the contents
/// of the backing storage if needed.
init(json: JSON.Node) throws
init(json: borrowing JSON.Node) throws
}
extension JSONDecodable where Self: SignedInteger & FixedWidthInteger {
@inlinable public init(json: JSON.Node) throws {
@inlinable public init(json: borrowing JSON.Node) throws {
self = try json.cast { try $0.as(Self.self) }
}
}
extension JSONDecodable where Self: UnsignedInteger & FixedWidthInteger {
@inlinable public init(json: JSON.Node) throws {
@inlinable public init(json: borrowing JSON.Node) throws {
self = try json.cast { try $0.as(Self.self) }
}
}
extension JSONDecodable where Self: RawRepresentable, RawValue: JSONDecodable & Sendable {
@inlinable public init(json: JSON.Node) throws {
@inlinable public init(json: borrowing JSON.Node) throws {
let rawValue: RawValue = try .init(json: json)
if let value: Self = .init(rawValue: rawValue) {
self = value
Expand Down
6 changes: 3 additions & 3 deletions Sources/JSONDecoding/JSONObjectDecodable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@
public protocol JSONObjectDecodable<CodingKey>: JSONDecodable {
associatedtype CodingKey: RawRepresentable<String> & Hashable & Sendable = JSON.Key

init(json: JSON.ObjectDecoder<CodingKey>) throws
init(json: borrowing JSON.ObjectDecoder<CodingKey>) throws
}
extension JSONObjectDecodable {
@inlinable public init(json: JSON.Object) throws {
@inlinable public init(json: borrowing JSON.Object) throws {
try self.init(json: try .init(indexing: json))
}
@inlinable public init(json: JSON.Node) throws {
@inlinable public init(json: borrowing JSON.Node) throws {
try self.init(json: try .init(json: json))
}
}
2 changes: 1 addition & 1 deletion Sources/JSONDecoding/JSONStringDecodable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ extension JSONStringDecodable {
/// itself to prevent unexpected behavior for types (such as ``Int``)
/// who implement ``LosslessStringConvertible``, but expect to be
/// decoded from a variant value that is not a string.
@inlinable public init(json: JSON.Node) throws {
@inlinable public init(json: borrowing JSON.Node) throws {
let string: String = try .init(json: json)
if let value: Self = .init(string) {
self = value
Expand Down
2 changes: 1 addition & 1 deletion Sources/JSONDecoding/Never (ext).swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
extension Never: JSONDecodable {
/// Always throws a ``JSON.TypecastError``.
@inlinable public init(json: JSON.Node) throws {
@inlinable public init(json: borrowing JSON.Node) throws {
throw JSON.TypecastError<Never>.init(invalid: json)
}
}
4 changes: 2 additions & 2 deletions Sources/JSONDecoding/Optional (ext).swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
extension Optional: JSONDecodable where Wrapped: JSONDecodable {
@inlinable public init(json: JSON.Node) throws {
if case .null = json {
@inlinable public init(json: borrowing JSON.Node) throws {
if case .null = copy json {
self = .none
} else {
self = .some(try .init(json: json))
Expand Down
8 changes: 1 addition & 7 deletions Sources/JSONEncoding/Conformances/Array (ext).swift
Original file line number Diff line number Diff line change
@@ -1,9 +1,3 @@
extension Array: JSONEncodable where Element: JSONEncodable {
@inlinable public func encode(to json: inout JSON) {
{
for element: Element in self {
$0[+] = element
}
} (&json[as: JSON.ArrayEncoder.self])
}
@inlinable public func encode(to json: inout JSON) { self.encodeElements(to: &json) }
}
8 changes: 1 addition & 7 deletions Sources/JSONEncoding/Conformances/ArraySlice (ext).swift
Original file line number Diff line number Diff line change
@@ -1,9 +1,3 @@
extension ArraySlice: JSONEncodable where Element: JSONEncodable {
@inlinable public func encode(to json: inout JSON) {
{
for element: Element in self {
$0[+] = element
}
} (&json[as: JSON.ArrayEncoder.self])
}
@inlinable public func encode(to json: inout JSON) { self.encodeElements(to: &json) }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
extension LazyDropWhileSequence: JSONEncodable where Element: JSONEncodable {
@inlinable public func encode(to json: inout JSON) { self.encodeElements(to: &json) }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
extension LazyFilterSequence: JSONEncodable where Element: JSONEncodable {
@inlinable public func encode(to json: inout JSON) { self.encodeElements(to: &json) }
}
3 changes: 3 additions & 0 deletions Sources/JSONEncoding/Conformances/LazyMapSequence (ext).swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
extension LazyMapSequence: JSONEncodable where Element: JSONEncodable {
@inlinable public func encode(to json: inout JSON) { self.encodeElements(to: &json) }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
extension LazyPrefixWhileSequence: JSONEncodable where Element: JSONEncodable {
@inlinable public func encode(to json: inout JSON) { self.encodeElements(to: &json) }
}
11 changes: 11 additions & 0 deletions Sources/JSONEncoding/Conformances/Sequence (ext).swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
extension Sequence where Self: JSONEncodable, Element: JSONEncodable {
// this does not directly witness the requirement, we don’t want it to show up on
// ``String``, for instance
@inlinable func encodeElements(to json: inout JSON) {
{
for element: Element in self {
$0[+] = element
}
} (&json[as: JSON.ArrayEncoder.self])
}
}
10 changes: 5 additions & 5 deletions Sources/JSONEncoding/Encoders/JSON.ArrayEncoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,22 @@ import JSONAST

extension JSON {
@frozen public struct ArrayEncoder: Sendable {
@usableFromInline internal var first: Bool
@usableFromInline internal var json: JSON
@usableFromInline var first: Bool
@usableFromInline var json: JSON

@inlinable internal init(json: JSON) {
@inlinable init(json: JSON) {
self.first = true
self.json = json
}
}
}
extension JSON.ArrayEncoder: JSON.InlineEncoder {
@inlinable internal static func move(_ json: inout JSON) -> Self {
@inlinable static func move(_ json: inout JSON) -> Self {
json.utf8.append(0x5B) // '['
defer { json.utf8 = [] }
return .init(json: json)
}
@inlinable internal mutating func move() -> JSON {
@inlinable mutating func move() -> JSON {
self.first = true
self.json.utf8.append(0x5D) // ']'
defer { self.json.utf8 = [] }
Expand Down
8 changes: 4 additions & 4 deletions Sources/JSONEncoding/Encoders/JSON.Literal (ext).swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,26 @@ import JSONAST

extension JSON.Literal<Never?> {
/// Encodes `null` to the provided JSON stream.
@inlinable internal static func += (json: inout JSON, self: Self) {
@inlinable static func += (json: inout JSON, self: Self) {
json.utf8 += "null".utf8
}
}
extension JSON.Literal<Bool> {
/// Encodes `true` or `false` to the provided JSON stream.
@inlinable internal static func += (json: inout JSON, self: Self) {
@inlinable static func += (json: inout JSON, self: Self) {
json.utf8 += (self.value ? "true" : "false").utf8
}
}
extension JSON.Literal where Value: BinaryInteger {
/// Encodes this literal’s integer ``value`` to the provided JSON stream. The value’s
/// ``CustomStringConvertible description`` witness must format the value in base-10.
@inlinable internal static func += (json: inout JSON, self: Self) {
@inlinable static func += (json: inout JSON, self: Self) {
json.utf8 += self.value.description.utf8
}
}
extension JSON.Literal where Value: BinaryFloatingPoint & LosslessStringConvertible {
/// Encodes this literal’s floating-point ``value`` to the provided JSON stream.
@inlinable internal static func += (json: inout JSON, self: Self) {
@inlinable static func += (json: inout JSON, self: Self) {
if self.value.isSignalingNaN {
json.utf8 += "snan".utf8
} else if self.value.isNaN {
Expand Down
Loading
Loading