I have this code I'm working on to facilitate interpreting JSON "null" values as empty strings or arrays so that the corresponding properties don't have to be optional:
@propertyWrapper
struct NullToEmpty<T>: Codable where T: Codable & EmptyConstructible {
let wrappedValue: T
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
self.wrappedValue = container.decodeNil() ? T() : try container.decode(T.self)
}
func encode(to encoder: Encoder) throws {
try wrappedValue.encode(to: encoder)
}
}
protocol EmptyConstructible { init() }
extension String: EmptyConstructible {}
extension Array: EmptyConstructible {}
I originally had separate types for the string and array cases, but I thought I could consolidate them.
The problem I'm running into is adding conformance to ExpressibleByArrayLiteral
and ExpressibleByStringLiteral
, with each having different issues.
For ExpressibleByArrayLiteral
, I don't know how to define the extension for the generic Array
case. I can do this:
extension NullToEmpty: ExpressibleByArrayLiteral where T == Array<Int> {
init(arrayLiteral elements: T.ArrayLiteralElement...) {
self.wrappedValue = T(elements)
}
}
..but I want to get rid of Int
there, of course, and the compiler won't let me just say Array
. So how do I express that? I also tried where T: ExpressibleByArrayLiteral
but that runs into the issue of forwarding variadic arguments, which AFAICT you can't do in Swift.
For the string case, I tried this:
extension NullToEmpty: ExpressibleByStringLiteral where T == String {
init(stringLiteral value: String) {
self.wrappedValue = value
}
}
..but the compiler complains that it doesn't also conform to ExpressibleByUnicodeScalarLiteral
and ExpressibleByExtendedGraphemeClusterLiteral
. The latter seems particularly tricky because I'm supposed to have an associated type that conforms to _ExpressibleByBuiltinExtendedGraphemeClusterLiteral
. I don't think I want to mess with that underscore. Is there a way to make that work, or to make those conformances more implicit?