Skip to content

Commit

Permalink
Clean up RFC 2045 “media type” in BodyStructure (apple#717)
Browse files Browse the repository at this point in the history
Each “part” in a `BodyStructure` has an RFC 2045 “media type” — which is a combination of “top level type” + “sub-stype”.

But the types that were previously used, were inconsistently used / named. This PR cleans up the use of these and makes them consistent.

Additionally it adds a
```swift
extension BodyStructure {
    public var mediaType: Media.MediaType
}
```
such that it’s easy to get to a part’s media type, regardless of its kind.
  • Loading branch information
danieleggert authored Oct 6, 2022
1 parent 6eb8a70 commit fc46347
Show file tree
Hide file tree
Showing 18 changed files with 491 additions and 513 deletions.
40 changes: 0 additions & 40 deletions Sources/NIOIMAPCore/Grammar/Body/Body.swift
Original file line number Diff line number Diff line change
Expand Up @@ -195,46 +195,6 @@ extension BodyStructure {
}
}

// MARK: - Types

extension BodyStructure {
/// The subtype of a multi-part body.
public struct MediaSubtype: CustomDebugStringConvertible, Hashable {
/// When used with a `multipart` type, specifies the same data as different formats.
public static var alternative: Self {
.init("alternative")
}

/// When used with a `multipart` type, specifies compound objects consisting of several related body parts.
public static var related: Self {
.init("related")
}

/// When used with a `multipart` type, specifies a generic set of mixed data types.
public static var mixed: Self {
.init("mixed")
}

/// The subtype as a lowercased string
internal let stringValue: String

/// The subtype as a lowercased string
public var debugDescription: String { stringValue }

/// Creates a new `MediaSubtype` from the given `String`, which will be lowercased.
/// - parameter rawValue: The subtype as a `String`. Note that the string will be lowercased.
public init(_ stringValue: String) {
self.stringValue = stringValue.lowercased()
}
}
}

extension String {
public init(_ other: BodyStructure.MediaSubtype) {
self = other.stringValue
}
}

// MARK: - Encoding

extension EncodeBuffer {
Expand Down
10 changes: 2 additions & 8 deletions Sources/NIOIMAPCore/Grammar/Body/Multipart.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ extension BodyStructure {
public var parts: [BodyStructure]

/// The subtype of the message, e.g. `mixed` (from `multipart/mixed`)
public var mediaSubtype: MediaSubtype
public var mediaSubtype: Media.Subtype

/// Optional additional fields that are not required to form a valid `Multipart`
public var `extension`: Extension?
Expand All @@ -32,7 +32,7 @@ extension BodyStructure {
/// - parameter parts: The sub-parts that form the `Multipart`
/// - parameter mediaSubtype: The subtype of the message, e.g. *multipart/mixed*
/// - parameter extension: Optional additional fields that are not required to form a valid `Multipart` body
public init(parts: [BodyStructure], mediaSubtype: MediaSubtype, extension: Extension? = nil) {
public init(parts: [BodyStructure], mediaSubtype: Media.Subtype, extension: Extension? = nil) {
self.parts = parts
self.mediaSubtype = mediaSubtype
self.extension = `extension`
Expand Down Expand Up @@ -68,9 +68,7 @@ extension EncodeBuffer {
result += self.writeBody(body)
} +
self.writeSpace() +
self.writeString("\"multipart/") +
self.writeMediaSubtype(part.mediaSubtype) +
self.writeString("\"") +
self.writeIfExists(part.extension) { (ext) -> Int in
self.writeSpace() +
self.writeBodyExtensionMultipart(ext)
Expand All @@ -83,8 +81,4 @@ extension EncodeBuffer {
self.writeBodyDispositionAndLanguage(dspLanguage)
}
}

@discardableResult mutating func writeMediaSubtype(_ type: BodyStructure.MediaSubtype) -> Int {
self.writeString(type.stringValue)
}
}
28 changes: 15 additions & 13 deletions Sources/NIOIMAPCore/Grammar/Body/Singlepart.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ extension BodyStructure.Singlepart {
/// Represents the type of a single-part message.
public indirect enum Kind: Hashable {
/// A simple message containing only one kind of data.
case basic(Media.Basic)
case basic(Media.MediaType)

/// A "full" email message containing an envelope, and a child body.
case message(Message)
Expand All @@ -55,8 +55,8 @@ extension BodyStructure.Singlepart {

/// Represents a typical "full" email message, containing an envelope and a child message.
public struct Message: Hashable {
/// Indication if the message contains an encapsulated message.
public var message: Media.Message
/// The RFC 2045 sub-type. This will usually be `rfc822`.
public var message: Media.Subtype

/// The envelope of the message, potentially including the message sender, bcc list, etc.
public var envelope: Envelope
Expand All @@ -72,7 +72,7 @@ extension BodyStructure.Singlepart {
/// - parameter envelope: The envelope of the message
/// - parameter body: The encapsulated message. Note that this may be a multi-part.
/// - parameter lineCount: The number of lines in the message
public init(message: Media.Message, envelope: Envelope, body: BodyStructure, lineCount: Int) {
public init(message: Media.Subtype, envelope: Envelope, body: BodyStructure, lineCount: Int) {
self.message = message
self.envelope = envelope
self.body = body
Expand All @@ -82,17 +82,17 @@ extension BodyStructure.Singlepart {

/// Represents a text-based message body.
public struct Text: Hashable {
/// The type of text message, e.g. `text/html` or `text/plain`
public var mediaText: String
/// The media sub-type of a text part, e.g. `html` or `plain` for `text/html` and `text/plain` respectively.
public var mediaSubtype: Media.Subtype

/// The number of lines in the message.
public var lineCount: Int

/// Creates a new `Text`.
/// - parameter mediaText: The type of text message, e.g. `text/html` or `text/plain`
/// - parameter lineCount: The number of lines in the message.
public init(mediaText: String, lineCount: Int) {
self.mediaText = mediaText
public init(mediaSubtype: Media.Subtype, lineCount: Int) {
self.mediaSubtype = mediaSubtype
self.lineCount = lineCount
}
}
Expand Down Expand Up @@ -123,7 +123,7 @@ extension EncodeBuffer {
var size = 0
switch part.kind {
case .basic(let basic):
size += self.writeBodyKindBasic(mediaKind: basic, fields: part.fields)
size += self.writeBodyKindBasic(mediaType: basic, fields: part.fields)
case .message(let message):
size += self.writeBodyKindMessage(message, fields: part.fields)
case .text(let text):
Expand All @@ -138,14 +138,16 @@ extension EncodeBuffer {
}

@discardableResult private mutating func writeBodyKindText(_ body: BodyStructure.Singlepart.Text, fields: BodyStructure.Fields) -> Int {
self.writeMediaText(body.mediaText) +
self.writeString(#""TEXT" "#) +
self.writeMediaSubtype(body.mediaSubtype) +
self.writeSpace() +
self.writeBodyFields(fields) +
self.writeString(" \(body.lineCount)")
}

@discardableResult private mutating func writeBodyKindMessage(_ message: BodyStructure.Singlepart.Message, fields: BodyStructure.Fields) -> Int {
self.writeMediaMessage(message.message) +
self.writeString(#""MESSAGE" "#) +
self.writeMediaSubtype(message.message) +
self.writeSpace() +
self.writeBodyFields(fields) +
self.writeSpace() +
Expand All @@ -155,8 +157,8 @@ extension EncodeBuffer {
self.writeString(" \(message.lineCount)")
}

@discardableResult private mutating func writeBodyKindBasic(mediaKind: Media.Basic, fields: BodyStructure.Fields) -> Int {
self.writeMediaBasic(mediaKind) +
@discardableResult private mutating func writeBodyKindBasic(mediaType: Media.MediaType, fields: BodyStructure.Fields) -> Int {
self.writeMediaType(mediaType) +
self.writeSpace() +
self.writeBodyFields(fields)
}
Expand Down
97 changes: 0 additions & 97 deletions Sources/NIOIMAPCore/Grammar/Media/Basic.swift

This file was deleted.

Loading

0 comments on commit fc46347

Please sign in to comment.