Skip to content

Commit e71181d

Browse files
authored
[SE-0456, -0467] Data+Span+MutableSpan (#1276)
* [SE-0456, -0467] Data+Span+MutableSpan * Document compiler issue * fix use of non-public initializers * Address availability and compiler versions * adjust cmake configuration * temporarily disable Span and MutableSpan for Windows The current Windows nightly is too old to be able to compile the expected syntax. * update linux build flags * shield lifetime-dependence syntax * shield new types from testing module * compile out MutableSpan mutations when unsupported by deployment target
1 parent 2393a6b commit e71181d

File tree

6 files changed

+365
-7
lines changed

6 files changed

+365
-7
lines changed

CMakeLists.txt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,13 +111,15 @@ list(APPEND _SwiftFoundation_versions
111111
list(APPEND _SwiftFoundation_availability_names
112112
"FoundationPreview"
113113
"FoundationPredicate"
114-
"FoundationPredicateRegex")
114+
"FoundationPredicateRegex"
115+
"FoundationSpan")
115116

116117
# The aligned availability for each name (in the same order)
117118
list(APPEND _SwiftFoundation_availability_releases
118119
${_SwiftFoundation_BaseAvailability}
119120
${_SwiftFoundation_BaseAvailability}
120-
${_SwiftFoundation_BaseAvailability})
121+
${_SwiftFoundation_BaseAvailability}
122+
${_SwiftFoundation_FutureAvailability})
121123

122124
foreach(version ${_SwiftFoundation_versions})
123125
foreach(name release IN ZIP_LISTS _SwiftFoundation_availability_names _SwiftFoundation_availability_releases)

Package.swift

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ import CompilerPluginSupport
99
let availabilityTags: [_Availability] = [
1010
_Availability("FoundationPreview"), // Default FoundationPreview availability,
1111
_Availability("FoundationPredicate"), // Predicate relies on pack parameter runtime support
12-
_Availability("FoundationPredicateRegex") // Predicate regexes rely on new stdlib APIs
12+
_Availability("FoundationPredicateRegex"), // Predicate regexes rely on new stdlib APIs
13+
_Availability("FoundationSpan", availability: .future), // Availability of Span types
1314
]
1415
let versionNumbers = ["0.1", "0.2", "0.3", "0.4", "6.0.2", "6.1", "6.2"]
1516

@@ -134,6 +135,18 @@ let package = Package(
134135
] + wasiLibcCSettings,
135136
swiftSettings: [
136137
.enableExperimentalFeature("VariadicGenerics"),
138+
.enableExperimentalFeature("LifetimeDependence"),
139+
.enableExperimentalFeature(
140+
"InoutLifetimeDependence",
141+
.when(platforms: [.macOS, .iOS, .watchOS, .tvOS, .linux])
142+
),
143+
.enableExperimentalFeature(
144+
"LifetimeDependenceMutableAccessors",
145+
.when(platforms: [.macOS, .iOS, .watchOS, .tvOS, .linux])
146+
),
147+
.enableExperimentalFeature("AddressableTypes"),
148+
.enableExperimentalFeature("AllowUnsafeAttribute"),
149+
.enableExperimentalFeature("BuiltinModule"),
137150
.enableExperimentalFeature("AccessLevelOnImport")
138151
] + availabilityMacros + featureSettings,
139152
linkerSettings: [
@@ -149,7 +162,16 @@ let package = Package(
149162
resources: [
150163
.copy("Resources")
151164
],
152-
swiftSettings: availabilityMacros + featureSettings
165+
swiftSettings: [
166+
.enableExperimentalFeature(
167+
"InoutLifetimeDependence",
168+
.when(platforms: [.macOS, .iOS, .watchOS, .tvOS, .linux])
169+
),
170+
.enableExperimentalFeature(
171+
"LifetimeDependenceMutableAccessors",
172+
.when(platforms: [.macOS, .iOS, .watchOS, .tvOS, .linux])
173+
),
174+
] + availabilityMacros + featureSettings
153175
),
154176

155177
// FoundationInternationalization

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ On all other Swift platforms, `swift-foundation` is available as part of the too
1818
## Building and Testing
1919

2020
> [!NOTE]
21-
> Building swift-foundation requires the in-development Swift 6.0 toolchain. You can download the Swift 6.0 nightly toolchain from [the Swift website](https://swift.org/install).
21+
> Building swift-foundation requires the in-development Swift 6.2 toolchain. You can download the Swift 6.2 nightly toolchain from [the Swift website](https://swift.org/install).
2222
2323
Before building Foundation, first ensure that you have a Swift toolchain installed. Next, check out the _Getting Started_ section of the [Foundation Build Process](Foundation_Build_Process.md#getting-started) guide for detailed steps on building and testing.
2424

Sources/FoundationEssentials/CMakeLists.txt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,12 +74,17 @@ endif()
7474

7575
if(CMAKE_SYSTEM_NAME STREQUAL Linux OR CMAKE_SYSTEM_NAME STREQUAL Android)
7676
target_compile_options(FoundationEssentials PRIVATE
77-
"SHELL:$<$<COMPILE_LANGUAGE:Swift>:-Xfrontend -Xcc -Xfrontend -D_GNU_SOURCE>")
77+
"SHELL:$<$<COMPILE_LANGUAGE:Swift>:-Xfrontend -Xcc -Xfrontend -D_GNU_SOURCE>"
78+
"SHELL:$<$<COMPILE_LANGUAGE:Swift>:-Xfrontend -enable-experimental-feature -Xfrontend InoutLifetimeDependence>"
79+
"SHELL:$<$<COMPILE_LANGUAGE:Swift>:-Xfrontend -enable-experimental-feature -Xfrontend LifetimeDependenceMutableAccessors>")
7880
list(APPEND CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE)
7981
endif()
8082

8183
target_compile_options(FoundationEssentials PRIVATE
8284
"SHELL:$<$<COMPILE_LANGUAGE:Swift>:-Xfrontend -enable-experimental-feature -Xfrontend VariadicGenerics>"
85+
"SHELL:$<$<COMPILE_LANGUAGE:Swift>:-Xfrontend -enable-experimental-feature -Xfrontend LifetimeDependence>"
86+
"SHELL:$<$<COMPILE_LANGUAGE:Swift>:-Xfrontend -enable-experimental-feature -Xfrontend AddressableTypes>"
87+
"SHELL:$<$<COMPILE_LANGUAGE:Swift>:-Xfrontend -enable-experimental-feature -Xfrontend BuiltinModule>"
8388
"SHELL:$<$<COMPILE_LANGUAGE:Swift>:-Xfrontend -enable-experimental-feature -Xfrontend AccessLevelOnImport>"
8489
"SHELL:$<$<COMPILE_LANGUAGE:Swift>:-Xfrontend -enable-experimental-feature -Xfrontend StrictConcurrency>"
8590
"SHELL:$<$<COMPILE_LANGUAGE:Swift>:-Xfrontend -enable-upcoming-feature -Xfrontend InferSendableFromCaptures>"

Sources/FoundationEssentials/Data/Data.swift

Lines changed: 159 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
#endif
5050

5151
internal import _FoundationCShims
52+
import Builtin
5253

5354
#if canImport(Darwin)
5455
import Darwin
@@ -604,6 +605,9 @@ internal final class __DataStorage : @unchecked Sendable {
604605

605606
@frozen
606607
@available(macOS 10.10, iOS 8.0, watchOS 2.0, tvOS 9.0, *)
608+
#if compiler(>=6.2)
609+
@_addressableForDependencies
610+
#endif
607611
public struct Data : Equatable, Hashable, RandomAccessCollection, MutableCollection, RangeReplaceableCollection, MutableDataProtocol, ContiguousBytes, Sendable {
608612

609613
public typealias Index = Int
@@ -2198,7 +2202,107 @@ public struct Data : Equatable, Hashable, RandomAccessCollection, MutableCollect
21982202
public func withUnsafeBytes<ResultType>(_ body: (UnsafeRawBufferPointer) throws -> ResultType) rethrows -> ResultType {
21992203
return try _representation.withUnsafeBytes(body)
22002204
}
2201-
2205+
2206+
#if compiler(>=6.2) && $LifetimeDependence
2207+
@available(FoundationSpan 6.2, *)
2208+
public var bytes: RawSpan {
2209+
@lifetime(borrow self)
2210+
borrowing get {
2211+
let buffer: UnsafeRawBufferPointer
2212+
switch _representation {
2213+
case .empty:
2214+
buffer = UnsafeRawBufferPointer(start: nil, count: 0)
2215+
case .inline:
2216+
buffer = unsafe UnsafeRawBufferPointer(
2217+
start: UnsafeRawPointer(Builtin.addressOfBorrow(self)),
2218+
count: _representation.count
2219+
)
2220+
case .large(let slice):
2221+
buffer = unsafe UnsafeRawBufferPointer(
2222+
start: slice.storage.mutableBytes?.advanced(by: slice.startIndex), count: slice.count
2223+
)
2224+
case .slice(let slice):
2225+
buffer = unsafe UnsafeRawBufferPointer(
2226+
start: slice.storage.mutableBytes?.advanced(by: slice.startIndex), count: slice.count
2227+
)
2228+
}
2229+
let span = unsafe RawSpan(_unsafeBytes: buffer)
2230+
return unsafe _overrideLifetime(span, borrowing: self)
2231+
}
2232+
}
2233+
2234+
@available(FoundationSpan 6.2, *)
2235+
public var span: Span<UInt8> {
2236+
@lifetime(borrow self)
2237+
borrowing get {
2238+
let span = unsafe bytes._unsafeView(as: UInt8.self)
2239+
return _overrideLifetime(span, borrowing: self)
2240+
}
2241+
}
2242+
#endif
2243+
2244+
#if compiler(>=5.9) && $InoutLifetimeDependence && $LifetimeDependenceMutableAccessors
2245+
@available(FoundationSpan 6.2, *)
2246+
public var mutableBytes: MutableRawSpan {
2247+
@lifetime(&self)
2248+
mutating get {
2249+
let buffer: UnsafeMutableRawBufferPointer
2250+
switch _representation {
2251+
case .empty:
2252+
buffer = UnsafeMutableRawBufferPointer(start: nil, count: 0)
2253+
case .inline:
2254+
buffer = unsafe UnsafeMutableRawBufferPointer(
2255+
start: UnsafeMutableRawPointer(Builtin.addressOfBorrow(self)),
2256+
count: _representation.count
2257+
)
2258+
case .large(let slice):
2259+
buffer = unsafe UnsafeMutableRawBufferPointer(
2260+
start: slice.storage.mutableBytes?.advanced(by: slice.startIndex), count: slice.count
2261+
)
2262+
case .slice(let slice):
2263+
buffer = unsafe UnsafeMutableRawBufferPointer(
2264+
start: slice.storage.mutableBytes?.advanced(by: slice.startIndex), count: slice.count
2265+
)
2266+
}
2267+
let span = unsafe MutableRawSpan(_unsafeBytes: buffer)
2268+
return unsafe _overrideLifetime(span, mutating: &self)
2269+
}
2270+
}
2271+
2272+
@available(FoundationSpan 6.2, *)
2273+
public var mutableSpan: MutableSpan<UInt8> {
2274+
@lifetime(&self)
2275+
mutating get {
2276+
#if false // see https://github.com/swiftlang/swift/issues/81218
2277+
var bytes = mutableBytes
2278+
let span = unsafe bytes._unsafeMutableView(as: UInt8.self)
2279+
return _overrideLifetime(span, mutating: &self)
2280+
#else
2281+
let buffer: UnsafeMutableRawBufferPointer
2282+
switch _representation {
2283+
case .empty:
2284+
buffer = UnsafeMutableRawBufferPointer(start: nil, count: 0)
2285+
case .inline:
2286+
buffer = unsafe UnsafeMutableRawBufferPointer(
2287+
start: UnsafeMutableRawPointer(Builtin.addressOfBorrow(self)),
2288+
count: _representation.count
2289+
)
2290+
case .large(let slice):
2291+
buffer = unsafe UnsafeMutableRawBufferPointer(
2292+
start: slice.storage.mutableBytes?.advanced(by: slice.startIndex), count: slice.count
2293+
)
2294+
case .slice(let slice):
2295+
buffer = unsafe UnsafeMutableRawBufferPointer(
2296+
start: slice.storage.mutableBytes?.advanced(by: slice.startIndex), count: slice.count
2297+
)
2298+
}
2299+
let span = unsafe MutableSpan<UInt8>(_unsafeBytes: buffer)
2300+
return unsafe _overrideLifetime(span, mutating: &self)
2301+
#endif
2302+
}
2303+
}
2304+
#endif // $InoutLifetimeDependence && $LifetimeDependenceMutableAccessors
2305+
22022306
@_alwaysEmitIntoClient
22032307
public func withContiguousStorageIfAvailable<ResultType>(_ body: (_ buffer: UnsafeBufferPointer<UInt8>) throws -> ResultType) rethrows -> ResultType? {
22042308
return try _representation.withUnsafeBytes {
@@ -2870,3 +2974,57 @@ extension Data : Codable {
28702974
}
28712975
}
28722976
}
2977+
2978+
// TODO: remove once _overrideLifetime is public in the standard library
2979+
#if compiler(>=6.2) && $LifetimeDependence
2980+
/// Unsafely discard any lifetime dependency on the `dependent` argument. Return
2981+
/// a value identical to `dependent` with a lifetime dependency on the caller's
2982+
/// borrow scope of the `source` argument.
2983+
@unsafe
2984+
@_unsafeNonescapableResult
2985+
@_alwaysEmitIntoClient
2986+
@_transparent
2987+
@lifetime(borrow source)
2988+
internal func _overrideLifetime<
2989+
T: ~Copyable & ~Escapable, U: ~Copyable & ~Escapable
2990+
>(
2991+
_ dependent: consuming T, borrowing source: borrowing U
2992+
) -> T {
2993+
dependent
2994+
}
2995+
2996+
/// Unsafely discard any lifetime dependency on the `dependent` argument. Return
2997+
/// a value identical to `dependent` that inherits all lifetime dependencies from
2998+
/// the `source` argument.
2999+
@unsafe
3000+
@_unsafeNonescapableResult
3001+
@_alwaysEmitIntoClient
3002+
@_transparent
3003+
@lifetime(copy source)
3004+
internal func _overrideLifetime<
3005+
T: ~Copyable & ~Escapable, U: ~Copyable & ~Escapable
3006+
>(
3007+
_ dependent: consuming T, copying source: borrowing U
3008+
) -> T {
3009+
dependent
3010+
}
3011+
#endif
3012+
3013+
#if compiler(>=5.9) && $InoutLifetimeDependence && $LifetimeDependenceMutableAccessors
3014+
/// Unsafely discard any lifetime dependency on the `dependent` argument.
3015+
/// Return a value identical to `dependent` with a lifetime dependency
3016+
/// on the caller's exclusive borrow scope of the `source` argument.
3017+
@unsafe
3018+
@_unsafeNonescapableResult
3019+
@_alwaysEmitIntoClient
3020+
@_transparent
3021+
@lifetime(&source)
3022+
internal func _overrideLifetime<
3023+
T: ~Copyable & ~Escapable, U: ~Copyable & ~Escapable
3024+
>(
3025+
_ dependent: consuming T,
3026+
mutating source: inout U
3027+
) -> T {
3028+
dependent
3029+
}
3030+
#endif // $InoutLifetimeDependence && $LifetimeDependenceMutableAccessors

0 commit comments

Comments
 (0)