Skip to content

Commit d94d5d5

Browse files
committed
Refactor: Remove encoding parameter from StringProtocol extensions
Remove custom encoding parameter from StringProtocol initializers as RFC 1123 domain names are pure ASCII (7-bit). Only UTF-8 interpretation is academically correct since ASCII ⊂ UTF-8. This makes the API more correct and prevents misuse with incompatible encodings like UTF-16 or UTF-32.
1 parent 7872df8 commit d94d5d5

File tree

5 files changed

+56
-67
lines changed

5 files changed

+56
-67
lines changed

Package.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ let package = Package(
2525
.library(name: .rfc1123, targets: [.rfc1123]),
2626
],
2727
dependencies: [
28-
.package(url: "https://github.com/swift-standards/swift-rfc-1035.git", from: "0.0.1"),
28+
.package(url: "https://github.com/swift-standards/swift-rfc-1035", from: "0.1.0"),
2929
.package(url: "https://github.com/swift-standards/swift-standards.git", from: "0.1.0"),
3030
.package(url: "https://github.com/swift-standards/swift-incits-4-1986.git", from: "0.1.0"),
3131
],

Sources/RFC 1123/RFC_1123.Domain.swift

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ extension RFC_1123.Domain {
4545
///
4646
/// Convenience initializer that validates strings as labels (with TLD-specific validation),
4747
/// then delegates to the canonical `init(labels: [Label])`.
48-
public init(labels labelStrings: some Sequence<some StringProtocol>) throws(Error) {
48+
public init<S: StringProtocol>(labels labelStrings: [S]) throws(Error) {
4949
guard !labelStrings.isEmpty else {
5050
throw Error.empty
5151
}
@@ -62,17 +62,15 @@ extension RFC_1123.Domain {
6262
for labelString in labelStrings.dropLast() {
6363
do {
6464
validatedLabels.append(try Label(labelString, validateAs: .label))
65-
} catch {
66-
// Typed throws: compiler knows error is Label.Error
65+
} catch let error {
6766
throw Error.invalidLabel(error)
6867
}
6968
}
7069

7170
// Add TLD with stricter validation
7271
do {
7372
validatedLabels.append(try Label(tld, validateAs: .tld))
74-
} catch {
75-
// Typed throws: compiler knows error is Label.Error
73+
} catch let error {
7674
throw Error.invalidLabel(error)
7775
}
7876

@@ -83,10 +81,10 @@ extension RFC_1123.Domain {
8381
/// Initialize from a string representation (e.g. "host.example.com")
8482
///
8583
/// Convenience initializer that parses dot-separated labels.
86-
public init(_ string: some StringProtocol) throws(Error) {
84+
public init(_ string: String) throws(Error) {
8785
try self.init(
8886
labels: string
89-
.split(separator: ".", omittingEmptySubsequences: true)
87+
.split(separator: Character("."), omittingEmptySubsequences: true)
9088
.map(String.init)
9189
)
9290
}
@@ -122,23 +120,24 @@ extension RFC_1123.Domain {
122120
}
123121

124122
/// Initialize a label from a string, validating RFC 1123 rules
125-
internal init(_ string: some StringProtocol, validateAs type: ValidationType) throws(Error) {
123+
internal init<S: StringProtocol>(_ string: S, validateAs type: ValidationType) throws(Error) {
126124
// Check emptiness
127125
guard !string.isEmpty else {
128126
throw Error.empty
129127
}
130128

131129
// Check length
132130
guard string.count <= RFC_1123.Domain.Limits.maxLabelLength else {
133-
throw Error.tooLong(string.count, label: string)
131+
throw Error.tooLong(string.count, label: String(string))
134132
}
135133

136134
// Validate against appropriate regex
137135
let regex = type == .tld ? RFC_1123.Domain.tldRegex : RFC_1123.Domain.labelRegex
138-
guard (try? regex.wholeMatch(in: string)) != nil else {
136+
let stringValue = String(string)
137+
guard (try? regex.wholeMatch(in: stringValue)) != nil else {
139138
throw type == .tld
140-
? Error.invalidTLD(string)
141-
: Error.invalidCharacters(string)
139+
? Error.invalidTLD(stringValue)
140+
: Error.invalidCharacters(stringValue)
142141
}
143142

144143
// Store as canonical byte representation (ASCII-only)

Sources/RFC 1123/String.swift

Lines changed: 0 additions & 54 deletions
This file was deleted.
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// ===----------------------------------------------------------------------===//
2+
//
3+
// Copyright (c) 2025 Coen ten Thije Boonkkamp
4+
// Licensed under Apache License v2.0
5+
//
6+
// See LICENSE.txt for license information
7+
// See CONTRIBUTORS.txt for the list of project contributors
8+
//
9+
// SPDX-License-Identifier: Apache-2.0
10+
//
11+
// ===----------------------------------------------------------------------===//
12+
13+
// String.swift
14+
// swift-rfc-1123
15+
//
16+
// String representations composed through canonical byte serialization
17+
18+
// MARK: - Label String Representation
19+
20+
extension StringProtocol {
21+
/// Creates string representation of an RFC 1123 domain label
22+
///
23+
/// RFC 1123 domain labels are pure ASCII (7-bit), and this initializer
24+
/// interprets them as UTF-8 (since ASCII ⊂ UTF-8).
25+
///
26+
/// - Parameter label: The domain label to represent
27+
public init(_ label: RFC_1123.Domain.Label) {
28+
self = Self(decoding: [UInt8](label), as: UTF8.self)
29+
}
30+
}
31+
32+
// MARK: - Domain String Representation
33+
34+
extension StringProtocol {
35+
/// Creates string representation of an RFC 1123 domain name
36+
///
37+
/// RFC 1123 domain names are pure ASCII (7-bit), and this initializer
38+
/// interprets them as UTF-8 (since ASCII ⊂ UTF-8).
39+
///
40+
/// - Parameter domain: The domain name to represent
41+
public init(_ domain: RFC_1123.Domain) {
42+
self = Self(decoding: [UInt8](domain), as: UTF8.self)
43+
}
44+
}
File renamed without changes.

0 commit comments

Comments
 (0)