Skip to content

Commit d4724d1

Browse files
authored
Adopt typed throws across 'BinaryParsing' (swiftlang#5)
To accommodate both user and library errors on parser function-taking functions (like Range.init(parsingStartAndEnd:parser:)), this adds a 'typealias ThrownParsingError' that aliases 'ParsingError' in embedded mode and 'any Error' elsewhere. This has the benefit of keeping the simplicity of untyped errors in non-embedded code, but means that adopting code can't choose to use explicitly typed errors when in non-embedded mode.
1 parent f694cef commit d4724d1

File tree

14 files changed

+264
-180
lines changed

14 files changed

+264
-180
lines changed

Sources/BinaryParsing/Macros/MagicNumber.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ func _loadAndCheckDirectBytes<
1515
>(
1616
parsing input: inout ParserSpan,
1717
bigEndianValue: T
18-
) throws {
18+
) throws(ParsingError) {
1919
let loadedValue = try T(parsingBigEndian: &input)
2020
guard loadedValue == bigEndianValue else {
2121
throw ParsingError(
@@ -29,7 +29,7 @@ func _loadAndCheckDirectBytesByteOrder<
2929
>(
3030
parsing input: inout ParserSpan,
3131
bigEndianValue: T
32-
) throws -> Endianness {
32+
) throws(ParsingError) -> Endianness {
3333
let loadedValue = try T(parsingBigEndian: &input)
3434
if loadedValue == bigEndianValue {
3535
return .big

Sources/BinaryParsing/Operations/Optionators.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ extension Optional where Wrapped: Comparable {
108108
guard lhs <= rhs else { return nil }
109109
return lhs..<rhs
110110
}
111-
111+
112112
@inlinable @inline(__always)
113113
public static func ...? (lhs: Self, rhs: Self) -> ClosedRange<Wrapped>? {
114114
guard let lhs, let rhs else { return nil }

Sources/BinaryParsing/Operations/ThrowingOperations.swift

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
extension Collection {
1313
@inlinable
1414
public subscript(throwing i: Index) -> Element {
15-
get throws {
15+
get throws(ParsingError) {
1616
guard (startIndex..<endIndex).contains(i) else {
1717
throw ParsingError(statusOnly: .invalidValue)
1818
}
@@ -24,7 +24,7 @@ extension Collection {
2424
extension Optional {
2525
@inlinable
2626
public var unwrapped: Wrapped {
27-
get throws {
27+
get throws(ParsingError) {
2828
switch self {
2929
case .some(let v): return v
3030
case .none:
@@ -36,7 +36,8 @@ extension Optional {
3636

3737
extension BinaryInteger {
3838
@inlinable
39-
public init(throwingOnOverflow other: some BinaryInteger) throws {
39+
public init(throwingOnOverflow other: some BinaryInteger) throws(ParsingError)
40+
{
4041
guard let newValue = Self(exactly: other) else {
4142
throw ParsingError(statusOnly: .invalidValue)
4243
}
@@ -48,7 +49,9 @@ extension FixedWidthInteger {
4849
// MARK: Nonmutating arithmetic
4950

5051
@inlinable
51-
public func addingThrowingOnOverflow(_ other: Self) throws -> Self {
52+
public func addingThrowingOnOverflow(_ other: Self) throws(ParsingError)
53+
-> Self
54+
{
5255
let (result, overflow) = addingReportingOverflow(other)
5356
if overflow {
5457
throw ParsingError(statusOnly: .invalidValue)
@@ -57,7 +60,9 @@ extension FixedWidthInteger {
5760
}
5861

5962
@inlinable
60-
public func subtractingThrowingOnOverflow(_ other: Self) throws -> Self {
63+
public func subtractingThrowingOnOverflow(_ other: Self) throws(ParsingError)
64+
-> Self
65+
{
6166
let (result, overflow) = subtractingReportingOverflow(other)
6267
if overflow {
6368
throw ParsingError(statusOnly: .invalidValue)
@@ -66,7 +71,9 @@ extension FixedWidthInteger {
6671
}
6772

6873
@inlinable
69-
public func multipliedThrowingOnOverflow(by other: Self) throws -> Self {
74+
public func multipliedThrowingOnOverflow(by other: Self) throws(ParsingError)
75+
-> Self
76+
{
7077
let (result, overflow) = multipliedReportingOverflow(by: other)
7178
if overflow {
7279
throw ParsingError(statusOnly: .invalidValue)
@@ -75,7 +82,9 @@ extension FixedWidthInteger {
7582
}
7683

7784
@inlinable
78-
public func dividedThrowingOnOverflow(by other: Self) throws -> Self {
85+
public func dividedThrowingOnOverflow(by other: Self) throws(ParsingError)
86+
-> Self
87+
{
7988
let (result, overflow) = dividedReportingOverflow(by: other)
8089
if overflow {
8190
throw ParsingError(statusOnly: .invalidValue)
@@ -84,7 +93,8 @@ extension FixedWidthInteger {
8493
}
8594

8695
@inlinable
87-
public func remainderThrowingOnOverflow(dividingBy other: Self) throws -> Self
96+
public func remainderThrowingOnOverflow(dividingBy other: Self)
97+
throws(ParsingError) -> Self
8898
{
8999
let (result, overflow) = remainderReportingOverflow(dividingBy: other)
90100
if overflow {
@@ -96,28 +106,35 @@ extension FixedWidthInteger {
96106
// MARK: Mutating arithmetic
97107

98108
@inlinable
99-
public mutating func addThrowingOnOverflow(_ other: Self) throws {
109+
public mutating func addThrowingOnOverflow(_ other: Self) throws(ParsingError)
110+
{
100111
self = try self.addingThrowingOnOverflow(other)
101112
}
102113

103114
@inlinable
104-
public mutating func subtractThrowingOnOverflow(_ other: Self) throws {
115+
public mutating func subtractThrowingOnOverflow(_ other: Self)
116+
throws(ParsingError)
117+
{
105118
self = try self.subtractingThrowingOnOverflow(other)
106119
}
107120

108121
@inlinable
109-
public mutating func multiplyThrowingOnOverflow(by other: Self) throws {
122+
public mutating func multiplyThrowingOnOverflow(by other: Self)
123+
throws(ParsingError)
124+
{
110125
self = try self.multipliedThrowingOnOverflow(by: other)
111126
}
112127

113128
@inlinable
114-
public mutating func divideThrowingOnOverflow(by other: Self) throws {
129+
public mutating func divideThrowingOnOverflow(by other: Self)
130+
throws(ParsingError)
131+
{
115132
self = try self.dividedThrowingOnOverflow(by: other)
116133
}
117134

118135
@inlinable
119136
public mutating func formRemainderThrowingOnOverflow(dividingBy other: Self)
120-
throws
137+
throws(ParsingError)
121138
{
122139
self = try self.remainderThrowingOnOverflow(dividingBy: other)
123140
}

Sources/BinaryParsing/Parser Types/ParserRange.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ public struct ParserRange: Hashable {
3535
}
3636

3737
extension ParserRange {
38-
public func slicing<C: Collection<UInt8>>(_ coll: C) throws -> C.SubSequence
38+
public func slicing<C: Collection<UInt8>>(_ coll: C) throws(ParsingError)
39+
-> C.SubSequence
3940
where C.Index == Int {
4041
let validRange = coll.startIndex...coll.endIndex
4142
guard validRange.contains(range.lowerBound),
@@ -49,7 +50,7 @@ extension ParserRange {
4950

5051
extension RandomAccessCollection<UInt8> where Index == Int {
5152
public subscript(_ range: ParserRange) -> SubSequence {
52-
get throws {
53+
get throws(ParsingError) {
5354
let validRange = startIndex...endIndex
5455
guard validRange.contains(range.lowerBound),
5556
validRange.contains(range.upperBound)

Sources/BinaryParsing/Parser Types/ParserSource.swift

Lines changed: 81 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,20 @@ public import Foundation
1515

1616
public protocol ExpressibleByParsing {
1717
@lifetime(&input)
18-
init(parsing input: inout ParserSpan) throws
18+
init(parsing input: inout ParserSpan) throws(ThrownParsingError)
1919
}
2020

2121
extension ExpressibleByParsing {
22-
public init(parsing data: some RandomAccessCollection<UInt8>) throws {
22+
public init(parsing data: some RandomAccessCollection<UInt8>)
23+
throws(ThrownParsingError)
24+
{
2325
guard
24-
let result = try data.withParserSpanIfAvailable({ span in
26+
let result = try data.withParserSpanIfAvailable({
27+
(span) throws(ThrownParsingError) in
2528
try Self.init(parsing: &span)
2629
})
2730
else {
28-
throw ParsingError(
29-
status: .invalidValue,
30-
location: 0,
31-
message: "Provided data type does not support contiguous access.")
31+
throw ParsingError(statusOnly: .invalidValue)
3232
}
3333
self = result
3434
}
@@ -37,81 +37,113 @@ extension ExpressibleByParsing {
3737
extension RandomAccessCollection<UInt8> {
3838
@inlinable
3939
public func withParserSpanIfAvailable<T>(
40-
_ body: (inout ParserSpan) throws -> T
41-
) throws -> T? {
40+
_ body: (inout ParserSpan) throws(ThrownParsingError) -> T
41+
) throws(ThrownParsingError) -> T? {
4242
#if canImport(Foundation)
4343
if let data = self as? Foundation.Data {
44-
return try data.withUnsafeBytes { buffer -> T in
45-
var span = ParserSpan(_unsafeBytes: buffer)
46-
return try body(&span)
44+
do {
45+
return try data.withUnsafeBytes { buffer -> T in
46+
var span = ParserSpan(_unsafeBytes: buffer)
47+
return try body(&span)
48+
}
49+
} catch {
50+
// Workaround for lack of typed-throwing API on Data
51+
// swift-format-ignore: NeverForceUnwrap
52+
throw error as! ThrownParsingError
4753
}
4854
}
4955
#endif
50-
return try self.withContiguousStorageIfAvailable { buffer in
51-
let rawBuffer = UnsafeRawBufferPointer(buffer)
52-
var span = ParserSpan(_unsafeBytes: rawBuffer)
53-
return try body(&span)
56+
do {
57+
return try self.withContiguousStorageIfAvailable { buffer in
58+
let rawBuffer = UnsafeRawBufferPointer(buffer)
59+
var span = ParserSpan(_unsafeBytes: rawBuffer)
60+
return try body(&span)
61+
}
62+
} catch {
63+
// Workaround for lack of typed-throwing API on Collection
64+
// swift-format-ignore: NeverForceUnwrap
65+
throw error as! ThrownParsingError
5466
}
5567
}
5668
}
5769

5870
// MARK: ParserSpanProvider
5971

6072
public protocol ParserSpanProvider {
61-
func withParserSpan<T>(_ body: (inout ParserSpan) throws -> T) throws -> T
73+
func withParserSpan<T>(
74+
_ body: (inout ParserSpan) throws(ThrownParsingError) -> T
75+
) throws(ThrownParsingError) -> T
6276
}
6377

6478
#if canImport(Foundation)
6579
extension Data: ParserSpanProvider {
6680
@inlinable
67-
public func withParserSpan<T>(_ body: (inout ParserSpan) throws -> T) throws
68-
-> T
69-
{
70-
try withUnsafeBytes { buffer -> T in
71-
// FIXME: RawSpan getter
72-
// var span = ParserSpan(buffer.bytes)
73-
var span = ParserSpan(_unsafeBytes: buffer)
74-
return try body(&span)
81+
public func withParserSpan<T>(
82+
_ body: (inout ParserSpan) throws(ThrownParsingError) -> T
83+
) throws(ThrownParsingError) -> T {
84+
do {
85+
return try withUnsafeBytes { buffer -> T in
86+
// FIXME: RawSpan getter
87+
// var span = ParserSpan(buffer.bytes)
88+
var span = ParserSpan(_unsafeBytes: buffer)
89+
return try body(&span)
90+
}
91+
} catch {
92+
// Workaround for lack of typed-throwing API on Data
93+
// swift-format-ignore: NeverForceUnwrap
94+
throw error as! ThrownParsingError
7595
}
7696
}
7797

7898
@_alwaysEmitIntoClient
7999
@inlinable
80100
public func withParserSpan<T>(
81101
usingRange range: inout ParserRange,
82-
_ body: (inout ParserSpan) throws -> T
83-
) rethrows -> T {
84-
try withUnsafeBytes { buffer -> T in
85-
// FIXME: RawSpan getter
86-
// var span = try ParserSpan(buffer.bytes)
87-
var span = try ParserSpan(_unsafeBytes: buffer)
88-
.seeking(toRange: range)
89-
defer {
90-
range = span.parserRange
102+
_ body: (inout ParserSpan) throws(ThrownParsingError) -> T
103+
) throws(ThrownParsingError) -> T {
104+
do {
105+
return try withUnsafeBytes { (buffer) throws(ThrownParsingError) -> T in
106+
// FIXME: RawSpan getter
107+
// var span = try ParserSpan(buffer.bytes)
108+
var span = try ParserSpan(_unsafeBytes: buffer)
109+
.seeking(toRange: range)
110+
defer {
111+
range = span.parserRange
112+
}
113+
return try body(&span)
91114
}
92-
return try body(&span)
115+
} catch {
116+
// Workaround for lack of typed-throwing API on Data
117+
// swift-format-ignore: NeverForceUnwrap
118+
throw error as! ThrownParsingError
93119
}
94120
}
95121
}
96122
#endif
97123

98124
extension ParserSpanProvider where Self: RandomAccessCollection<UInt8> {
99125
@inlinable
100-
public func withParserSpan<T>(_ body: (inout ParserSpan) throws -> T) throws
101-
-> T
102-
{
103-
guard
104-
let result = try self.withContiguousStorageIfAvailable({ buffer in
105-
// FIXME: RawSpan getter
106-
// var span = ParserSpan(UnsafeRawBufferPointer(buffer).bytes)
107-
let rawBuffer = UnsafeRawBufferPointer(buffer)
108-
var span = ParserSpan(_unsafeBytes: rawBuffer)
109-
return try body(&span)
110-
})
111-
else {
112-
throw ParsingError(status: .userError, location: 0)
126+
public func withParserSpan<T>(
127+
_ body: (inout ParserSpan) throws(ThrownParsingError) -> T
128+
) throws(ThrownParsingError) -> T {
129+
do {
130+
guard
131+
let result = try self.withContiguousStorageIfAvailable({ buffer in
132+
// FIXME: RawSpan getter
133+
// var span = ParserSpan(UnsafeRawBufferPointer(buffer).bytes)
134+
let rawBuffer = UnsafeRawBufferPointer(buffer)
135+
var span = ParserSpan(_unsafeBytes: rawBuffer)
136+
return try body(&span)
137+
})
138+
else {
139+
throw ParsingError(status: .userError, location: 0)
140+
}
141+
return result
142+
} catch {
143+
// Workaround for lack of typed-throwing API on Collection
144+
// swift-format-ignore: NeverForceUnwrap
145+
throw error as! ThrownParsingError
113146
}
114-
return result
115147
}
116148
}
117149

Sources/BinaryParsing/Parser Types/ParserSpan.swift

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -121,10 +121,10 @@ extension ParserSpan {
121121
@_alwaysEmitIntoClient
122122
@inlinable
123123
@unsafe
124-
public func withUnsafeBytes<T>(
125-
_ body: (UnsafeRawBufferPointer) throws -> T
126-
) rethrows -> T {
127-
try _bytes.withUnsafeBytes { fullBuffer in
124+
public func withUnsafeBytes<T, E>(
125+
_ body: (UnsafeRawBufferPointer) throws(E) -> T
126+
) throws(E) -> T {
127+
try _bytes.withUnsafeBytes { (fullBuffer) throws(E) in
128128
let buffer = UnsafeRawBufferPointer(
129129
rebasing: fullBuffer[_lowerBound..<_upperBound])
130130
return try body(buffer)
@@ -137,7 +137,7 @@ extension ParserSpan {
137137
@usableFromInline
138138
internal mutating func _divide(
139139
atByteOffset count: some FixedWidthInteger
140-
) throws -> ParserSpan {
140+
) throws(ParsingError) -> ParserSpan {
141141
guard let count = Int(exactly: count), count >= 0 else {
142142
throw ParsingError(status: .invalidValue, location: startPosition)
143143
}
@@ -186,9 +186,9 @@ extension ParserSpan {
186186
/// `atomically` guarantees that the input span isn't modified in that case.
187187
@inlinable
188188
@lifetime(&self)
189-
public mutating func atomically<T>(_ body: (inout ParserSpan) throws -> T)
190-
rethrows -> T
191-
{
189+
public mutating func atomically<T, E>(
190+
_ body: (inout ParserSpan) throws(E) -> T
191+
) throws(E) -> T {
192192
// Make a mutable copy to perform the work in `body`.
193193
var copy = self
194194
let result = try body(&copy)

0 commit comments

Comments
 (0)