Skip to content

Commit 9760ccc

Browse files
committed
Generalize ContiguousBytes to be noncopyable and nonescapable for spans
The ContiguousBytes protocol covers various types that can provide unsafe access to their stored bytes. Generalize the ContiguousBytes protocol by making it non-copyable and non-escapable, so that the Span family of types and InlineArray can conform to it. Fixes rdar://163716671.
1 parent 1cda636 commit 9760ccc

File tree

2 files changed

+87
-0
lines changed

2 files changed

+87
-0
lines changed

Sources/FoundationEssentials/Data/ContiguousBytes.swift

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,20 @@
1212

1313
//===--- ContiguousBytes --------------------------------------------------===//
1414

15+
#if compiler(>=6.2)
16+
/// Indicates that the conforming type is a contiguous collection of raw bytes
17+
/// whose underlying storage is directly accessible by withUnsafeBytes.
18+
@available(macOS 10.10, iOS 8.0, watchOS 2.0, tvOS 9.0, *)
19+
public protocol ContiguousBytes: ~Escapable, ~Copyable {
20+
/// Calls the given closure with the contents of underlying storage.
21+
///
22+
/// - note: Calling `withUnsafeBytes` multiple times does not guarantee that
23+
/// the same buffer pointer will be passed in every time.
24+
/// - warning: The buffer argument to the body should not be stored or used
25+
/// outside of the lifetime of the call to the closure.
26+
func withUnsafeBytes<R>(_ body: (UnsafeRawBufferPointer) throws -> R) rethrows -> R
27+
}
28+
#else
1529
/// Indicates that the conforming type is a contiguous collection of raw bytes
1630
/// whose underlying storage is directly accessible by withUnsafeBytes.
1731
@available(macOS 10.10, iOS 8.0, watchOS 2.0, tvOS 9.0, *)
@@ -24,6 +38,7 @@ public protocol ContiguousBytes {
2438
/// outside of the lifetime of the call to the closure.
2539
func withUnsafeBytes<R>(_ body: (UnsafeRawBufferPointer) throws -> R) rethrows -> R
2640
}
41+
#endif
2742

2843
//===--- Collection Conformances ------------------------------------------===//
2944

@@ -109,3 +124,34 @@ extension Slice : ContiguousBytes where Base : ContiguousBytes {
109124
}
110125
}
111126
}
127+
128+
#if compiler(>=6.2)
129+
130+
//===--- Span Conformances -----------------------------------------===//
131+
132+
@available(FoundationPreview 6.3, *)
133+
extension RawSpan: ContiguousBytes {
134+
}
135+
136+
@available(FoundationPreview 6.3, *)
137+
extension MutableRawSpan: ContiguousBytes {
138+
}
139+
140+
@available(FoundationPreview 6.3, *)
141+
extension Span: ContiguousBytes where Element == UInt8 {
142+
}
143+
144+
@available(FoundationPreview 6.3, *)
145+
extension MutableSpan: ContiguousBytes where Element == UInt8 {
146+
}
147+
148+
@available(FoundationPreview 6.3, *)
149+
@available(macOS 26.0, iOS 26.0, tvOS 26.0, watchOS 26.0, visionOS 26.0, *)
150+
extension InlineArray: ContiguousBytes where Element == UInt8 {
151+
@_alwaysEmitIntoClient
152+
public func withUnsafeBytes<R, E>(_ body: (UnsafeRawBufferPointer) throws(E) -> R) throws(E) -> R {
153+
return try span.withUnsafeBytes(body)
154+
}
155+
}
156+
157+
#endif
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2025 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
import Testing
14+
15+
#if canImport(FoundationEssentials)
16+
@testable import FoundationEssentials
17+
#else
18+
@testable import Foundation
19+
#endif
20+
21+
#if compiler(>=6.2)
22+
23+
func acceptContiguousBytes(_ bytes: borrowing some ContiguousBytes & ~Escapable & ~Copyable) { }
24+
25+
@Suite("ContiguousBytesTests")
26+
private struct ContiguousBytesTests {
27+
@available(macOS 26.0, iOS 26.0, tvOS 26.0, watchOS 26.0, visionOS 26.0, *)
28+
@Test func span() throws {
29+
if #available(FoundationPreview 6.3, *) {
30+
var bytes: [UInt8] = [1, 2, 3]
31+
acceptContiguousBytes(bytes.span)
32+
acceptContiguousBytes(bytes.mutableSpan)
33+
acceptContiguousBytes(bytes.span.bytes)
34+
35+
let ms = bytes.mutableSpan
36+
acceptContiguousBytes(ms.bytes)
37+
}
38+
}
39+
}
40+
41+
#endif

0 commit comments

Comments
 (0)