Skip to content

Commit 4612941

Browse files
authored
Remove storage indirection for FileSystemError (#2726)
Motivation: Existentials are boxed if they are wider than 24 bytes. A number of value types in NIO are implemented with storage classes so that the alloaction is only paid for once. However, existential errors are treated differently, they are unconditionally boxed. Implementing errors with storage classes therefore introduces an unnecessary allocation. Modifications: - Remove the storage class for FileSystemError - Remove the copy-on-write test Result: Fewer allocations
1 parent 7d1b76d commit 4612941

File tree

2 files changed

+9
-97
lines changed

2 files changed

+9
-97
lines changed

Sources/NIOFileSystem/FileSystemError.swift

Lines changed: 9 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -26,83 +26,30 @@ import SystemPackage
2626
///
2727
/// Errors may have a ``FileSystemError/cause``, an underlying error which caused the operation to
2828
/// fail which may be platform specific.
29-
public struct FileSystemError: Error, @unchecked Sendable {
30-
// Note: @unchecked because we use a backing class for storage.
31-
32-
private var storage: Storage
33-
private mutating func ensureStorageIsUnique() {
34-
if !isKnownUniquelyReferenced(&self.storage) {
35-
self.storage = self.storage.copy()
36-
}
37-
}
38-
39-
private final class Storage {
40-
var code: Code
41-
var message: String
42-
var cause: Error?
43-
var location: SourceLocation
44-
45-
init(code: Code, message: String, cause: Error?, location: SourceLocation) {
46-
self.code = code
47-
self.message = message
48-
self.cause = cause
49-
self.location = location
50-
}
51-
52-
func copy() -> Self {
53-
return Self(
54-
code: self.code,
55-
message: self.message,
56-
cause: self.cause,
57-
location: self.location
58-
)
59-
}
60-
}
61-
29+
public struct FileSystemError: Error, Sendable {
6230
/// A high-level error code to provide broad a classification.
63-
public var code: Code {
64-
get { self.storage.code }
65-
set {
66-
self.ensureStorageIsUnique()
67-
self.storage.code = newValue
68-
}
69-
}
31+
public var code: Code
7032

7133
/// A message describing what went wrong and how it may be remedied.
72-
public var message: String {
73-
get { self.storage.message }
74-
set {
75-
self.ensureStorageIsUnique()
76-
self.storage.message = newValue
77-
}
78-
}
34+
public var message: String
7935

8036
/// An underlying error which caused the operation to fail. This may include additional details
8137
/// about the root cause of the failure.
82-
public var cause: Error? {
83-
get { self.storage.cause }
84-
set {
85-
self.ensureStorageIsUnique()
86-
self.storage.cause = newValue
87-
}
88-
}
38+
public var cause: Error?
8939

9040
/// The location from which this error was thrown.
91-
public var location: SourceLocation {
92-
get { self.storage.location }
93-
set {
94-
self.ensureStorageIsUnique()
95-
self.storage.location = newValue
96-
}
97-
}
41+
public var location: SourceLocation
9842

9943
public init(
10044
code: Code,
10145
message: String,
10246
cause: Error?,
10347
location: SourceLocation
10448
) {
105-
self.storage = Storage(code: code, message: message, cause: cause, location: location)
49+
self.code = code
50+
self.message = message
51+
self.cause = cause
52+
self.location = location
10653
}
10754

10855
/// Creates a ``FileSystemError`` by wrapping the given `cause` and its location and code.

Tests/NIOFileSystemTests/FileSystemErrorTests.swift

Lines changed: 0 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -147,41 +147,6 @@ final class FileSystemErrorTests: XCTestCase {
147147
)
148148
}
149149

150-
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
151-
func testCopyOnWrite() throws {
152-
let error1 = FileSystemError(
153-
code: .io,
154-
message: "a message",
155-
cause: nil,
156-
location: .init(function: "fn(_:)", file: "file.swift", line: 42)
157-
)
158-
159-
var error2 = error1
160-
error2.code = .invalidArgument
161-
XCTAssertEqual(error1.code, .io)
162-
XCTAssertEqual(error2.code, .invalidArgument)
163-
164-
var error3 = error1
165-
error3.message = "a different message"
166-
XCTAssertEqual(error1.message, "a message")
167-
XCTAssertEqual(error3.message, "a different message")
168-
169-
var error4 = error1
170-
error4.cause = CancellationError()
171-
XCTAssertNil(error1.cause)
172-
XCTAssert(error4.cause is CancellationError)
173-
174-
var error5 = error1
175-
error5.location.file = "different-file.swift"
176-
XCTAssertEqual(error1.location.function, "fn(_:)")
177-
XCTAssertEqual(error1.location.file, "file.swift")
178-
XCTAssertEqual(error1.location.line, 42)
179-
180-
XCTAssertEqual(error5.location.function, "fn(_:)")
181-
XCTAssertEqual(error5.location.file, "different-file.swift")
182-
XCTAssertEqual(error5.location.line, 42)
183-
}
184-
185150
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
186151
func testErrorsMapToCorrectSyscallCause() throws {
187152
let here = FileSystemError.SourceLocation(function: "fn", file: "file", line: 42)

0 commit comments

Comments
 (0)