swift-libs/Sources/Core/Property Wrappers/LossyCodableList.swift

92 lines
2.6 KiB
Swift
Raw Normal View History

//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftLibs open source project
//
// Copyright (c) 2023 Röck+Cöde VoF. and the SwiftLibs project authors
// Licensed under the EUPL 1.2 or later.
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.txt for the list of SwiftLibs project authors
//
//===----------------------------------------------------------------------===//
/// This struct (that could also be used as a property wrapper as well) provides a generic type that acts as a thin wrapper around an array of `Elements` instances to allow a lossy decoding and or encoding process.
///
/// This implementation is heavily influenced by this [article](https://www.swiftbysundell.com/articles/ignoring-invalid-json-elements-codable/).
@propertyWrapper
public struct LossyCodableList<Element> {
// MARK: Properties
private var elements: [Element]
/// Provides read/write access to the array of `Element` instances.
public var wrappedValue: [Element] {
get { elements }
set { elements = newValue }
}
// MARK: Initialisers
/// Initialises this struct.
public init() {
self.elements = []
}
}
// MARK: - Decodable
extension LossyCodableList: Decodable where Element: Decodable {
// MARK: Initialisers
/// Initialises the struct with a lossy decoder.
/// - Parameter decoder: The decoder to use for the lossy decoder process.
public init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
let wrappers = try container.decode([ElementWrapper].self)
self.elements = wrappers.compactMap(\.element)
}
}
// MARK: - Encodable
extension LossyCodableList: Encodable where Element: Encodable {
// MARK: Functions
/// Encodes an array of `Element` instances loosely.
/// - Parameter encoder: The encoder to use for the lossy encoding process.
public func encode(to encoder: Encoder) throws {
var container = encoder.unkeyedContainer()
elements.forEach { element in
try? container.encode(element)
}
}
}
// MARK: - Structs
private extension LossyCodableList where Element: Decodable {
struct ElementWrapper: Decodable {
// MARK: Properties
var element: Element?
// MARK: Initialisers
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
self.element = try? container.decode(Element.self)
}
}
}