Skip to content

Commit 2ddef13

Browse files
authored
Make ParserSpan noncopyable (#15)
This change helps communicate the intended usage of `ParserSpan`, though it doesn't strictly prevent creating a copy that represents the same memory. Specifically, the `seeking(...)` methods return copies of the span with different boundaries, to support separate parsing of different subregions of memory, and calling e.g. `seeking(toRelativeOffset: 0)` returns an exact copy of the parser span. With a few changes inside the library to handle these explicit copies, this change is fully source compatible with all the included example parsers, further showing that it matches the intended usage and semantics of the library.
1 parent 50c7c47 commit 2ddef13

File tree

4 files changed

+17
-9
lines changed

4 files changed

+17
-9
lines changed

Sources/BinaryParsing/Parser Types/ParserSpan.swift

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
/// A non-owning, non-escaping view for parsing binary data.
1313
///
1414
/// You can access a `ParserSpan` from a
15-
public struct ParserSpan: ~Escapable, BitwiseCopyable {
15+
public struct ParserSpan: ~Escapable, ~Copyable {
1616
@usableFromInline
1717
var _bytes: RawSpan
1818
@usableFromInline
@@ -29,6 +29,14 @@ public struct ParserSpan: ~Escapable, BitwiseCopyable {
2929
self._upperBound = _bytes.byteCount
3030
}
3131

32+
@inlinable
33+
@lifetime(copy other)
34+
init(copying other: borrowing ParserSpan) {
35+
self._bytes = other._bytes
36+
self._lowerBound = other._lowerBound
37+
self._upperBound = other._upperBound
38+
}
39+
3240
@unsafe
3341
@inlinable
3442
@lifetime(borrow buffer)
@@ -91,7 +99,7 @@ extension ParserSpan {
9199
mutating func divide(at index: Int) -> ParserSpan {
92100
precondition(index >= _lowerBound)
93101
precondition(index <= _upperBound)
94-
var result = self
102+
var result = ParserSpan(copying: self)
95103
result._upperBound = index
96104
self._lowerBound = index
97105
return result
@@ -193,7 +201,7 @@ extension ParserSpan {
193201
_ body: (inout ParserSpan) throws(E) -> T
194202
) throws(E) -> T {
195203
// Make a mutable copy to perform the work in `body`.
196-
var copy = self
204+
var copy = ParserSpan(copying: self)
197205
let result = try body(&copy)
198206
// `body` didn't throw, so update `self`.
199207
self = copy

Sources/BinaryParsing/Parser Types/Seeking.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ extension ParserSpan {
1515
public func seeking(toRange range: ParserRange)
1616
throws(ParsingError) -> ParserSpan
1717
{
18-
var result = self
18+
var result = ParserSpan(copying: self)
1919
try result.seek(toRange: range)
2020
return result
2121
}
@@ -25,7 +25,7 @@ extension ParserSpan {
2525
public func seeking(toRelativeOffset offset: some FixedWidthInteger)
2626
throws(ParsingError) -> ParserSpan
2727
{
28-
var result = self
28+
var result = ParserSpan(copying: self)
2929
try result.seek(toRelativeOffset: offset)
3030
return result
3131
}
@@ -35,7 +35,7 @@ extension ParserSpan {
3535
public func seeking(toAbsoluteOffset offset: some FixedWidthInteger)
3636
throws(ParsingError) -> ParserSpan
3737
{
38-
var result = self
38+
var result = ParserSpan(copying: self)
3939
try result.seek(toAbsoluteOffset: offset)
4040
return result
4141
}
@@ -45,7 +45,7 @@ extension ParserSpan {
4545
public func seeking(toOffsetFromEnd offset: some FixedWidthInteger)
4646
throws(ParsingError) -> ParserSpan
4747
{
48-
var result = self
48+
var result = ParserSpan(copying: self)
4949
try result.seek(toOffsetFromEnd: offset)
5050
return result
5151
}

Tests/BinaryParsingTests/SeekingTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ struct SeekingTests {
6161

6262
// Absolute offset is always referent to original bounds
6363
var slice1 = try input.sliceSpan(byteCount: 4)
64-
var slice2 = slice1
64+
var slice2 = try input.seeking(toRange: slice1.parserRange)
6565
#expect(slice1.startPosition == 2)
6666
#expect(slice1.count == 4)
6767

Tests/BinaryParsingTests/TestingSupport.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import Testing
1414

1515
/// Returns a Boolean value indicating whether two parser spans are identical,
1616
/// representing the same subregion of the same span of memory.
17-
func === (lhs: ParserSpan, rhs: ParserSpan) -> Bool {
17+
func === (lhs: borrowing ParserSpan, rhs: borrowing ParserSpan) -> Bool {
1818
guard lhs.startPosition == rhs.startPosition,
1919
lhs.count == rhs.count
2020
else { return false }

0 commit comments

Comments
 (0)