Skip to content

Add support for Display String type to StructuredFieldValues #51

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Dec 10, 2024
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
12 changes: 8 additions & 4 deletions Sources/StructuredFieldValues/Decoder/BareInnerListDecoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -66,16 +66,20 @@ extension BareInnerListDecoder: UnkeyedDecodingContainer {
self.decoder.pop()
}

if type is Data.Type {
switch type {
case is Data.Type:
let container = try self.decoder.singleValueContainer()
return try container.decode(Data.self) as! T
} else if type is Decimal.Type {
case is Decimal.Type:
let container = try self.decoder.singleValueContainer()
return try container.decode(Decimal.self) as! T
} else if type is Date.Type {
case is Date.Type:
let container = try self.decoder.singleValueContainer()
return try container.decode(Date.self) as! T
} else {
case is DisplayString.Type:
let container = try self.decoder.singleValueContainer()
return try container.decode(DisplayString.self) as! T
default:
return try type.init(from: self.decoder)
}
}
Expand Down
10 changes: 10 additions & 0 deletions Sources/StructuredFieldValues/Decoder/BareItemDecoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,14 @@ extension BareItemDecoder: SingleValueDecodingContainer {
return Date(timeIntervalSince1970: Double(date))
}

func decode(_: DisplayString.Type) throws -> DisplayString {
guard case .displayString(let string) = self.item else {
throw StructuredHeaderError.invalidTypeForItem
}

return DisplayString(rawValue: string)
}

func decodeNil() -> Bool {
// Items are never nil.
false
Expand Down Expand Up @@ -182,6 +190,8 @@ extension BareItemDecoder: SingleValueDecodingContainer {
return try self.decode(Decimal.self) as! T
case is Date.Type:
return try self.decode(Date.self) as! T
case is DisplayString.Type:
return try self.decode(DisplayString.self) as! T
default:
throw StructuredHeaderError.invalidTypeForItem
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,16 +49,20 @@ extension DictionaryKeyedContainer: KeyedDecodingContainerProtocol {
self.decoder.pop()
}

if type is Data.Type {
switch type {
case is Data.Type:
let container = try self.decoder.singleValueContainer()
return try container.decode(Data.self) as! T
} else if type is Decimal.Type {
case is Decimal.Type:
let container = try self.decoder.singleValueContainer()
return try container.decode(Decimal.self) as! T
} else if type is Date.Type {
case is Date.Type:
let container = try self.decoder.singleValueContainer()
return try container.decode(Date.self) as! T
} else {
case is DisplayString.Type:
let container = try self.decoder.singleValueContainer()
return try container.decode(DisplayString.self) as! T
default:
return try type.init(from: self.decoder)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,16 +54,20 @@ extension KeyedInnerListDecoder: KeyedDecodingContainerProtocol {
self.decoder.pop()
}

if type is Data.Type {
switch type {
case is Data.Type:
let container = try self.decoder.singleValueContainer()
return try container.decode(Data.self) as! T
} else if type is Decimal.Type {
case is Decimal.Type:
let container = try self.decoder.singleValueContainer()
return try container.decode(Decimal.self) as! T
} else if type is Date.Type {
case is Date.Type:
let container = try self.decoder.singleValueContainer()
return try container.decode(Date.self) as! T
} else {
case is DisplayString.Type:
let container = try self.decoder.singleValueContainer()
return try container.decode(DisplayString.self) as! T
default:
return try type.init(from: self.decoder)
}
}
Expand Down
12 changes: 8 additions & 4 deletions Sources/StructuredFieldValues/Decoder/KeyedItemDecoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -54,16 +54,20 @@ extension KeyedItemDecoder: KeyedDecodingContainerProtocol {
self.decoder.pop()
}

if type is Data.Type {
switch type {
case is Data.Type:
let container = try self.decoder.singleValueContainer()
return try container.decode(Data.self) as! T
} else if type is Decimal.Type {
case is Decimal.Type:
let container = try self.decoder.singleValueContainer()
return try container.decode(Decimal.self) as! T
} else if type is Date.Type {
case is Date.Type:
let container = try self.decoder.singleValueContainer()
return try container.decode(Date.self) as! T
} else {
case is DisplayString.Type:
let container = try self.decoder.singleValueContainer()
return try container.decode(DisplayString.self) as! T
default:
return try type.init(from: self.decoder)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,16 +54,20 @@ extension KeyedTopLevelListDecoder: KeyedDecodingContainerProtocol {
self.decoder.pop()
}

if type is Data.Type {
switch type {
case is Data.Type:
let container = try self.decoder.singleValueContainer()
return try container.decode(Data.self) as! T
} else if type is Decimal.Type {
case is Decimal.Type:
let container = try self.decoder.singleValueContainer()
return try container.decode(Decimal.self) as! T
} else if type is Date.Type {
case is Date.Type:
let container = try self.decoder.singleValueContainer()
return try container.decode(Date.self) as! T
} else {
case is DisplayString.Type:
let container = try self.decoder.singleValueContainer()
return try container.decode(DisplayString.self) as! T
default:
return try type.init(from: self.decoder)
}
}
Expand Down
12 changes: 8 additions & 4 deletions Sources/StructuredFieldValues/Decoder/ParametersDecoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,16 +49,20 @@ extension ParametersDecoder: KeyedDecodingContainerProtocol {
self.decoder.pop()
}

if type is Data.Type {
switch type {
case is Data.Type:
let container = try self.decoder.singleValueContainer()
return try container.decode(Data.self) as! T
} else if type is Decimal.Type {
case is Decimal.Type:
let container = try self.decoder.singleValueContainer()
return try container.decode(Decimal.self) as! T
} else if type is Date.Type {
case is Date.Type:
let container = try self.decoder.singleValueContainer()
return try container.decode(Date.self) as! T
} else {
case is DisplayString.Type:
let container = try self.decoder.singleValueContainer()
return try container.decode(DisplayString.self) as! T
default:
return try type.init(from: self.decoder)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,16 +111,20 @@ extension StructuredFieldValueDecoder {

// An escape hatch here for top-level data: if we don't do this, it'll ask for
// an unkeyed container and get very confused.
if type is Data.Type {
switch type {
case is Data.Type:
let container = try decoder.singleValueContainer()
return try container.decode(Data.self) as! StructuredField
} else if type is Decimal.Type {
case is Decimal.Type:
let container = try decoder.singleValueContainer()
return try container.decode(Decimal.self) as! StructuredField
} else if type is Date.Type {
case is Date.Type:
let container = try decoder.singleValueContainer()
return try container.decode(Date.self) as! StructuredField
} else {
case is DisplayString.Type:
let container = try decoder.singleValueContainer()
return try container.decode(DisplayString.self) as! StructuredField
default:
return try type.init(from: decoder)
}
}
Expand Down
12 changes: 8 additions & 4 deletions Sources/StructuredFieldValues/Decoder/TopLevelListDecoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -66,16 +66,20 @@ extension TopLevelListDecoder: UnkeyedDecodingContainer {
self.decoder.pop()
}

if type is Data.Type {
switch type {
case is Data.Type:
let container = try self.decoder.singleValueContainer()
return try container.decode(Data.self) as! T
} else if type is Decimal.Type {
case is Decimal.Type:
let container = try self.decoder.singleValueContainer()
return try container.decode(Decimal.self) as! T
} else if type is Date.Type {
case is Date.Type:
let container = try self.decoder.singleValueContainer()
return try container.decode(Date.self) as! T
} else {
case is DisplayString.Type:
let container = try self.decoder.singleValueContainer()
return try container.decode(DisplayString.self) as! T
default:
return try type.init(from: self.decoder)
}
}
Expand Down
23 changes: 23 additions & 0 deletions Sources/StructuredFieldValues/DisplayString.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftNIO open source project
//
// Copyright (c) 2020-2024 Apple Inc. and the SwiftNIO project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.txt for the list of SwiftNIO project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//

/// A type that represents the Display String Structured Type.
public struct DisplayString: RawRepresentable, Codable, Equatable, Hashable {
public typealias RawValue = String
public var rawValue: String

public init(rawValue: String) {
self.rawValue = rawValue
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -150,19 +150,20 @@ class _StructuredFieldEncoder {
fileprivate func encodeItemField<StructuredField: Encodable>(_ data: StructuredField) throws -> [UInt8] {
self.push(key: .init(stringValue: ""), newStorage: .itemHeader)

// There's an awkward special hook here: if the outer type is `Data` or `Decimal`,
// we skip the regular encoding path. This is because otherwise `Data` will
// ask for an unkeyed container and `Decimal` for a keyed one,
// and it all falls apart.
// There's an awkward special hook here: if the outer type is `Data`, `Decimal`, `Date` or
// `DisplayString`, we skip the regular encoding path.
//
// Everything else goes through the normal flow.
if let value = data as? Data {
try self.encode(value)
} else if let value = data as? Decimal {
try self.encode(value)
} else if let value = data as? Date {
try self.encode(value)
} else {
switch data {
case is Data:
try self.encode(data)
case is Decimal:
try self.encode(data)
case is Date:
try self.encode(data)
case is DisplayString:
try self.encode(data)
default:
try data.encode(to: self)
}

Expand Down Expand Up @@ -316,6 +317,10 @@ extension _StructuredFieldEncoder: SingleValueEncodingContainer {
try self.currentStackEntry.storage.insertBareItem(.date(date))
}

func encode(_ data: DisplayString) throws {
try self.currentStackEntry.storage.insertBareItem(.displayString(data.rawValue))
}

func encode<T>(_ value: T) throws where T: Encodable {
switch value {
case let value as UInt8:
Expand Down Expand Up @@ -352,6 +357,8 @@ extension _StructuredFieldEncoder: SingleValueEncodingContainer {
try self.encode(value)
case let value as Date:
try self.encode(value)
case let value as DisplayString:
try self.encode(value)
default:
throw StructuredHeaderError.invalidTypeForItem
}
Expand Down Expand Up @@ -480,6 +487,10 @@ extension _StructuredFieldEncoder {
try self.currentStackEntry.storage.appendBareItem(.date(date))
}

func append(_ value: DisplayString) throws {
try self.currentStackEntry.storage.appendBareItem(.displayString(value.rawValue))
}

func append<T>(_ value: T) throws where T: Encodable {
switch value {
case let value as UInt8:
Expand Down Expand Up @@ -516,6 +527,8 @@ extension _StructuredFieldEncoder {
try self.append(value)
case let value as Date:
try self.append(value)
case let value as DisplayString:
try self.append(value)
default:
// Some other codable type.
switch self.currentStackEntry.storage {
Expand Down Expand Up @@ -658,6 +671,12 @@ extension _StructuredFieldEncoder {
try self.currentStackEntry.storage.insertBareItem(.date(date), atKey: key)
}

func encode(_ value: DisplayString, forKey key: String) throws {
let key = self.sanitizeKey(key)
let displayString = value.rawValue
try self.currentStackEntry.storage.insertBareItem(.displayString(displayString), atKey: key)
}

func encode<T>(_ value: T, forKey key: String) throws where T: Encodable {
let key = self.sanitizeKey(key)

Expand Down Expand Up @@ -696,6 +715,8 @@ extension _StructuredFieldEncoder {
try self.encode(value, forKey: key)
case let value as Date:
try self.encode(value, forKey: key)
case let value as DisplayString:
try self.encode(value, forKey: key)
default:
// Ok, we don't know what this is. This can only happen for a dictionary, or
// for anything with parameters, or for lists, or for inner lists.
Expand Down
Loading
Loading