Skip to content
26 changes: 20 additions & 6 deletions Sources/FoundationEssentials/Data/Data.swift
Original file line number Diff line number Diff line change
Expand Up @@ -345,9 +345,16 @@ public struct Data : RandomAccessCollection, MutableCollection, RangeReplaceable
}
}

@inlinable // This is @inlinable as a generic, trivially forwarding function.
public func withUnsafeBytes<ResultType>(_ body: (UnsafeRawBufferPointer) throws -> ResultType) rethrows -> ResultType {
return try _representation.withUnsafeBytes(body)
@_alwaysEmitIntoClient
public func withUnsafeBytes<E, ResultType: ~Copyable>(_ body: (UnsafeRawBufferPointer) throws(E) -> ResultType) throws(E) -> ResultType {
try _representation.withUnsafeBytes(body)
}

@abi(func withUnsafeBytes<R>(_: (UnsafeRawBufferPointer) throws -> R) rethrows -> R)
@_spi(FoundationLegacyABI)
@usableFromInline
internal func _legacy_withUnsafeBytes<ResultType>(_ body: (UnsafeRawBufferPointer) throws -> ResultType) rethrows -> ResultType {
try withUnsafeBytes(body)
}

@available(macOS 10.14.4, iOS 12.2, watchOS 5.2, tvOS 12.2, *)
Expand Down Expand Up @@ -473,9 +480,16 @@ public struct Data : RandomAccessCollection, MutableCollection, RangeReplaceable
}
}

@inlinable // This is @inlinable as a generic, trivially forwarding function.
public mutating func withUnsafeMutableBytes<ResultType>(_ body: (UnsafeMutableRawBufferPointer) throws -> ResultType) rethrows -> ResultType {
return try _representation.withUnsafeMutableBytes(body)
@_alwaysEmitIntoClient
public mutating func withUnsafeMutableBytes<E, ResultType: ~Copyable>(_ body: (UnsafeMutableRawBufferPointer) throws(E) -> ResultType) throws(E) -> ResultType {
try _representation.withUnsafeMutableBytes(body)
}

@abi(mutating func withUnsafeMutableBytes<R>(_: (UnsafeMutableRawBufferPointer) throws -> R) rethrows -> R)
@_spi(FoundationLegacyABI)
@usableFromInline
internal mutating func _legacy_withUnsafeMutableBytes<ResultType>(_ body: (UnsafeMutableRawBufferPointer) throws -> ResultType) rethrows -> ResultType {
try withUnsafeMutableBytes(body)
}

// MARK: -
Expand Down
34 changes: 23 additions & 11 deletions Sources/FoundationEssentials/Data/Representations/Data+Inline.swift
Original file line number Diff line number Diff line change
Expand Up @@ -126,22 +126,34 @@ extension Data {
return count
}

@inlinable // This is @inlinable as a generic, trivially forwarding function.
func withUnsafeBytes<Result>(_ apply: (UnsafeRawBufferPointer) throws -> Result) rethrows -> Result {
let count = Int(length)
return try Swift.withUnsafeBytes(of: bytes) { (rawBuffer) throws -> Result in
return try apply(UnsafeRawBufferPointer(start: rawBuffer.baseAddress, count: count))
@_alwaysEmitIntoClient
func withUnsafeBytes<E, Result: ~Copyable>(_ apply: (UnsafeRawBufferPointer) throws(E) -> Result) throws(E) -> Result {
try Swift.withUnsafeBytes(of: bytes) { [count = Int(length)] (rawBuffer) throws(E) -> Result in
try apply(UnsafeRawBufferPointer(start: rawBuffer.baseAddress, count: count))
}
}

@inlinable // This is @inlinable as a generic, trivially forwarding function.
mutating func withUnsafeMutableBytes<Result>(_ apply: (UnsafeMutableRawBufferPointer) throws -> Result) rethrows -> Result {
let count = Int(length)
return try Swift.withUnsafeMutableBytes(of: &bytes) { (rawBuffer) throws -> Result in
return try apply(UnsafeMutableRawBufferPointer(start: rawBuffer.baseAddress, count: count))
@abi(func withUnsafeBytes<R>(_: (UnsafeRawBufferPointer) throws -> R) rethrows -> R)
@_spi(FoundationLegacyABI)
@usableFromInline
internal func _legacy_withUnsafeBytes<ResultType>(_ body: (UnsafeRawBufferPointer) throws -> ResultType) rethrows -> ResultType {
try withUnsafeBytes(body)
}

@_alwaysEmitIntoClient
mutating func withUnsafeMutableBytes<E, Result: ~Copyable>(_ apply: (UnsafeMutableRawBufferPointer) throws(E) -> Result) throws(E) -> Result {
try Swift.withUnsafeMutableBytes(of: &bytes) { [count = Int(length)] (rawBuffer) throws(E) -> Result in
try apply(UnsafeMutableRawBufferPointer(start: rawBuffer.baseAddress, count: count))
}
}


@abi(mutating func withUnsafeMutableBytes<R>(_: (UnsafeMutableRawBufferPointer) throws -> R) rethrows -> R)
@_spi(FoundationLegacyABI)
@usableFromInline
internal mutating func _legacy_withUnsafeMutableBytes<ResultType>(_ body: (UnsafeMutableRawBufferPointer) throws -> ResultType) rethrows -> ResultType {
try withUnsafeMutableBytes(body)
}

@inlinable // This is @inlinable as trivially computable.
mutating func append(byte: UInt8) {
let count = self.count
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,17 +157,31 @@ extension Data {
}
}

@inlinable // This is @inlinable as a generic, trivially forwarding function.
func withUnsafeBytes<Result>(_ apply: (UnsafeRawBufferPointer) throws -> Result) rethrows -> Result {
return try storage.withUnsafeBytes(in: range, apply: apply)
@_alwaysEmitIntoClient
func withUnsafeBytes<E, Result: ~Copyable>(_ apply: (UnsafeRawBufferPointer) throws(E) -> Result) throws(E) -> Result {
try storage.withUnsafeBytes(in: range, apply: apply)
}

@inlinable // This is @inlinable as a generic, trivially forwarding function.
mutating func withUnsafeMutableBytes<Result>(_ apply: (UnsafeMutableRawBufferPointer) throws -> Result) rethrows -> Result {
@abi(func withUnsafeBytes<R>(_: (UnsafeRawBufferPointer) throws -> R) rethrows -> R)
@_spi(FoundationLegacyABI)
@usableFromInline
internal func _legacy_withUnsafeBytes<ResultType>(_ body: (UnsafeRawBufferPointer) throws -> ResultType) rethrows -> ResultType {
try withUnsafeBytes(body)
}

@_alwaysEmitIntoClient
mutating func withUnsafeMutableBytes<E, Result: ~Copyable>(_ apply: (UnsafeMutableRawBufferPointer) throws(E) -> Result) throws(E) -> Result {
ensureUniqueReference()
return try storage.withUnsafeMutableBytes(in: range, apply: apply)
}


@abi(mutating func withUnsafeMutableBytes<R>(_: (UnsafeMutableRawBufferPointer) throws -> R) rethrows -> R)
@_spi(FoundationLegacyABI)
@usableFromInline
internal mutating func _legacy_withUnsafeMutableBytes<ResultType>(_ body: (UnsafeMutableRawBufferPointer) throws -> ResultType) rethrows -> ResultType {
try withUnsafeMutableBytes(body)
}

@inlinable // This is @inlinable as reasonably small.
mutating func append(contentsOf buffer: UnsafeRawBufferPointer) {
assert(endIndex + buffer.count < HalfInt.max)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,17 +145,31 @@ extension Data {
return slice.range
}

@inlinable // This is @inlinable as a generic, trivially forwarding function.
func withUnsafeBytes<Result>(_ apply: (UnsafeRawBufferPointer) throws -> Result) rethrows -> Result {
return try storage.withUnsafeBytes(in: range, apply: apply)
@_alwaysEmitIntoClient
func withUnsafeBytes<E, Result: ~Copyable>(_ apply: (UnsafeRawBufferPointer) throws(E) -> Result) throws(E) -> Result {
try storage.withUnsafeBytes(in: range, apply: apply)
}

@inlinable // This is @inlinable as a generic, trivially forwarding function.
mutating func withUnsafeMutableBytes<Result>(_ apply: (UnsafeMutableRawBufferPointer) throws -> Result) rethrows -> Result {
@abi(func withUnsafeBytes<R>(_: (UnsafeRawBufferPointer) throws -> R) rethrows -> R)
@_spi(FoundationLegacyABI)
@usableFromInline
internal func _legacy_withUnsafeBytes<ResultType>(_ body: (UnsafeRawBufferPointer) throws -> ResultType) rethrows -> ResultType {
try withUnsafeBytes(body)
}

@_alwaysEmitIntoClient
mutating func withUnsafeMutableBytes<E, Result: ~Copyable>(_ apply: (UnsafeMutableRawBufferPointer) throws(E) -> Result) throws(E) -> Result {
ensureUniqueReference()
return try storage.withUnsafeMutableBytes(in: range, apply: apply)
}


@abi(mutating func withUnsafeMutableBytes<R>(_: (UnsafeMutableRawBufferPointer) throws -> R) rethrows -> R)
@_spi(FoundationLegacyABI)
@usableFromInline
internal mutating func _legacy_withUnsafeMutableBytes<ResultType>(_ body: (UnsafeMutableRawBufferPointer) throws -> ResultType) rethrows -> ResultType {
try withUnsafeMutableBytes(body)
}

@inlinable // This is @inlinable as reasonably small.
mutating func append(contentsOf buffer: UnsafeRawBufferPointer) {
ensureUniqueReference()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,8 +213,8 @@ extension Data {
}
}

@inlinable // This is @inlinable as a generic, trivially forwarding function.
func withUnsafeBytes<Result>(_ apply: (UnsafeRawBufferPointer) throws -> Result) rethrows -> Result {
@_alwaysEmitIntoClient
func withUnsafeBytes<E, Result: ~Copyable>(_ apply: (UnsafeRawBufferPointer) throws(E) -> Result) throws(E) -> Result {
switch self {
case .empty:
let empty = InlineData()
Expand All @@ -227,9 +227,16 @@ extension Data {
return try slice.withUnsafeBytes(apply)
}
}

@inlinable // This is @inlinable as a generic, trivially forwarding function.
mutating func withUnsafeMutableBytes<Result>(_ apply: (UnsafeMutableRawBufferPointer) throws -> Result) rethrows -> Result {

@abi(func withUnsafeBytes<R>(_: (UnsafeRawBufferPointer) throws -> R) rethrows -> R)
@_spi(FoundationLegacyABI)
@usableFromInline
internal func _legacy_withUnsafeBytes<ResultType>(_ body: (UnsafeRawBufferPointer) throws -> ResultType) rethrows -> ResultType {
try withUnsafeBytes(body)
}

@_alwaysEmitIntoClient
mutating func withUnsafeMutableBytes<E, Result: ~Copyable>(_ apply: (UnsafeMutableRawBufferPointer) throws(E) -> Result) throws(E) -> Result {
switch self {
case .empty:
var empty = InlineData()
Expand All @@ -247,7 +254,14 @@ extension Data {
return try slice.withUnsafeMutableBytes(apply)
}
}


@abi(mutating func withUnsafeMutableBytes<R>(_: (UnsafeMutableRawBufferPointer) throws -> R) rethrows -> R)
@_spi(FoundationLegacyABI)
@usableFromInline
internal mutating func _legacy_withUnsafeMutableBytes<ResultType>(_ body: (UnsafeMutableRawBufferPointer) throws -> ResultType) rethrows -> ResultType {
try withUnsafeMutableBytes(body)
}

@usableFromInline // This is not @inlinable as it is a non-trivial, non-generic function.
func enumerateBytes(_ block: (_ buffer: UnsafeBufferPointer<UInt8>, _ byteIndex: Index, _ stop: inout Bool) -> Void) {
switch self {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,18 +97,30 @@ internal final class __DataStorage : @unchecked Sendable {
return UnsafeRawPointer(_bytes)?.advanced(by: -_offset)
}

@inlinable // This is @inlinable despite escaping the _DataStorage boundary layer because it is generic and trivially forwarding.
@discardableResult
func withUnsafeBytes<Result>(in range: Range<Int>, apply: (UnsafeRawBufferPointer) throws -> Result) rethrows -> Result {
return try apply(UnsafeRawBufferPointer(start: _bytes?.advanced(by: range.lowerBound - _offset), count: Swift.min(range.upperBound - range.lowerBound, _length)))
@_alwaysEmitIntoClient
func withUnsafeBytes<E, Result: ~Copyable>(in range: Range<Int>, apply: (UnsafeRawBufferPointer) throws(E) -> Result) throws(E) -> Result {
try apply(UnsafeRawBufferPointer(start: _bytes?.advanced(by: range.lowerBound - _offset), count: Swift.min(range.upperBound - range.lowerBound, _length)))
}

@inlinable // This is @inlinable despite escaping the _DataStorage boundary layer because it is generic and trivially forwarding.
@discardableResult
func withUnsafeMutableBytes<Result>(in range: Range<Int>, apply: (UnsafeMutableRawBufferPointer) throws -> Result) rethrows -> Result {
return try apply(UnsafeMutableRawBufferPointer(start: _bytes!.advanced(by:range.lowerBound - _offset), count: Swift.min(range.upperBound - range.lowerBound, _length)))
@abi(func withUnsafeBytes<R>(in: Range<Int>, apply: (UnsafeRawBufferPointer) throws -> R) rethrows -> R)
@_spi(FoundationLegacyABI)
@usableFromInline
func _legacy_withUnsafeBytes<Result>(in range: Range<Int>, apply: (UnsafeRawBufferPointer) throws -> Result) rethrows -> Result {
try withUnsafeBytes(in: range, apply: apply)
}

@_alwaysEmitIntoClient
func withUnsafeMutableBytes<E, Result: ~Copyable>(in range: Range<Int>, apply: (UnsafeMutableRawBufferPointer) throws(E) -> Result) throws(E) -> Result {
try apply(UnsafeMutableRawBufferPointer(start: _bytes!.advanced(by:range.lowerBound - _offset), count: Swift.min(range.upperBound - range.lowerBound, _length)))
}

@abi(func withUnsafeMutableBytes<R>(in: Range<Int>, apply: (UnsafeMutableRawBufferPointer) throws -> R) rethrows -> R)
@_spi(FoundationLegacyABI)
@usableFromInline
internal func _legacy_withUnsafeMutableBytes<ResultType>(in range: Range<Int>, apply: (UnsafeMutableRawBufferPointer) throws -> ResultType) rethrows -> ResultType {
try withUnsafeMutableBytes(in: range, apply: apply)
}

@inlinable // This is @inlinable as trivially computable.
var mutableBytes: UnsafeMutableRawPointer? {
return _bytes?.advanced(by: _offset &* -1) // _offset is guaranteed to be non-negative, so it can never overflow when negating
Expand Down
2 changes: 1 addition & 1 deletion Tests/FoundationEssentialsTests/DataTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1767,7 +1767,7 @@ private final class DataTests {
let byteCount = span.byteCount
#expect(byteCount == count)
let v = UInt8.random(in: 10..<100)
var sub = span.extracting(i..<i+1)
var sub = span._mutatingExtracting(i..<i+1)
sub.storeBytes(of: v, as: UInt8.self)
#expect(source[i] == v)
}
Expand Down