over the weekend, swift-json
’s CI caught a nearly 6x performance regression resulting from a recent API adjustment.
i was able to narrow down the offending change to a seemingly innocuous refactor: moving the definition of a type and its conformances from a nested type to the parent type (which was previously an empty namespace enum
).
public
enum Rule<Location>
{
// @available(*, deprecated, renamed: "JSON.Rule")
// public
// typealias Root = JSON.Rule<Location>
public
enum Root:ParsingRule
{
public
typealias Terminal = UInt8
@inlinable public static
func parse<Diagnostics>(_ input:inout ParsingInput<Diagnostics>) throws -> JSON
where Diagnostics:ParsingDiagnostics,
Diagnostics.Source.Index == Location,
Diagnostics.Source.Element == Terminal
{
if let items:[(key:String, value:JSON)] = input.parse(as: Object?.self)
{
return .object(items)
}
else
{
return .array(try input.parse(as: Array.self))
}
}
}
}
[15/16] Linking benchmark
Build complete! (45.71s)
swift-json: decoded 38295 messages
foundation: decoded 38295 messages
swift-json decoding time: 0.482016238 seconds
foundation decoding time: 4.450682692 seconds
public
enum Rule<Location>:ParsingRule
{
// @available(*, deprecated, renamed: "JSON.Rule")
// public
// typealias Root = JSON.Rule<Location>
// public
// enum Root:ParsingRule
// {
public
typealias Terminal = UInt8
@inlinable public static
func parse<Diagnostics>(_ input:inout ParsingInput<Diagnostics>) throws -> JSON
where Diagnostics:ParsingDiagnostics,
Diagnostics.Source.Index == Location,
Diagnostics.Source.Element == Terminal
{
if let items:[(key:String, value:JSON)] = input.parse(as: Object?.self)
{
return .object(items)
}
else
{
return .array(try input.parse(as: Array.self))
}
}
// }
}
Build complete! (37.48s)
swift-json: decoded 38295 messages
foundation: decoded 38295 messages
swift-json decoding time: 2.875409557 seconds
foundation decoding time: 3.795551295 seconds
all of the types involved were public
, and all of the implementations involved were @inlinable
. what is going on here?