Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 19 additions & 5 deletions Foundation/Data.swift
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,13 @@ public struct Data : ReferenceConvertible, CustomStringConvertible, Equatable, H
public init<SourceType>(buffer: UnsafeBufferPointer<SourceType>) {
_wrapped = _SwiftNSData(immutableObject: NSData(bytes: buffer.baseAddress, length: MemoryLayout<SourceType>.stride * buffer.count))
}

/// Initialize a `Data` with copied memory content.
///
/// - parameter buffer: A buffer pointer to copy. The size is calculated from `SourceType` and `buffer.count`.
public init<SourceType>(buffer: UnsafeMutableBufferPointer<SourceType>) {
_wrapped = _SwiftNSData(immutableObject: NSData(bytes: UnsafePointer(buffer.baseAddress), length: MemoryLayout<SourceType>.stride * buffer.count))
}

/// Initialize a `Data` with the contents of an Array.
///
Expand Down Expand Up @@ -295,11 +302,18 @@ public struct Data : ReferenceConvertible, CustomStringConvertible, Equatable, H
}
}

internal init(_bridged data: NSData) {
/// Initialize a `Data` by adopting a reference type.
///
/// You can use this initializer to create a `struct Data` that wraps a `class NSData`. `struct Data` will use the `class NSData` for all operations. Other initializers (including casting using `as Data`) may choose to hold a reference or not, based on a what is the most efficient representation.
///
/// If the resulting value is mutated, then `Data` will invoke the `mutableCopy()` function on the reference to copy the contents. You may customize the behavior of that function if you wish to return a specialized mutable subclass.
///
/// - parameter reference: The instance of `NSData` that you wish to wrap. This instance will be copied by `struct Data`.
public init(referencing reference: NSData) {
// We must copy the input because it might be mutable; just like storing a value type in ObjC
_wrapped = _SwiftNSData(immutableObject: data.copy() as! NSObject)
_wrapped = _SwiftNSData(immutableObject: reference.copy() as! NSObject)
}

// -----------------------------------
// MARK: - Properties and Functions

Expand Down Expand Up @@ -639,11 +653,11 @@ extension Data {
}

public static func _forceBridgeFromObjectiveC(_ input: NSData, result: inout Data?) {
result = Data(_bridged: input)
result = Data(referencing: input)
}

public static func _conditionallyBridgeFromObjectiveC(_ input: NSData, result: inout Data?) -> Bool {
result = Data(_bridged: input)
result = Data(referencing: input)
return true
}

Expand Down
6 changes: 3 additions & 3 deletions Foundation/NSData.swift
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@ extension NSData {
return Data()
}
if range.location == 0 && range.length == self.length {
return Data(_bridged: self)
return Data(referencing: self)
}
return Data(bytes: bytes.advanced(by: range.location), count: range.length)
}
Expand Down Expand Up @@ -582,7 +582,7 @@ extension NSData {

extension NSData : _CFBridgable, _SwiftBridgable {
typealias SwiftType = Data
internal var _swiftObject: SwiftType { return Data(_bridged: self) }
internal var _swiftObject: SwiftType { return Data(referencing: self) }

public func bridge() -> Data {
return _swiftObject
Expand All @@ -604,7 +604,7 @@ extension CFData : _NSBridgable, _SwiftBridgable {
typealias NSType = NSData
typealias SwiftType = Data
internal var _nsObject: NSType { return unsafeBitCast(self, to: NSType.self) }
internal var _swiftObject: SwiftType { return Data(_bridged: self._nsObject) }
internal var _swiftObject: SwiftType { return Data(referencing: self._nsObject) }
}

extension NSMutableData {
Expand Down
42 changes: 41 additions & 1 deletion TestFoundation/TestNSData.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ class TestNSData: XCTestCase {
("test_replaceBytes", test_replaceBytes),
("test_initDataWithCapacity", test_initDataWithCapacity),
("test_initDataWithCount", test_initDataWithCount),
("test_initDataWithUnsafeBuffer", test_initDataWithUnsafeBuffer),
("test_initDataWithUnsafeMutableBuffer", test_initDataWithUnsafeMutableBuffer),
("test_initDataWithReference", test_initDataWithReference),
]
}

Expand Down Expand Up @@ -393,5 +396,42 @@ class TestNSData: XCTestCase {
return
}
}
}

func test_initDataWithUnsafeBuffer() {
var srcArray: [UInt8] = [0, 1, 2, 3, 4, 5]
let buffer = UnsafeBufferPointer<UInt8>(start: &srcArray,
count: srcArray.count)
let data = Data(buffer: buffer)

XCTAssertEqual(data.count, srcArray.count * MemoryLayout<UInt8>.stride)
XCTAssertTrue(Data(bytes: srcArray) == data)
}

func test_initDataWithUnsafeMutableBuffer() {
var srcArray: [UInt16] = [0, 1, 2, 3, 4, 5]
let buffer = UnsafeMutableBufferPointer<UInt16>(start: &srcArray,
count: srcArray.count)
let data = Data(buffer: buffer)

XCTAssertEqual(data.count, buffer.count * MemoryLayout<UInt16>.stride)

// Mutate the original array to test the new instance is a copy
srcArray[0] = 0xffff
XCTAssertEqual(buffer[0], srcArray[0])
XCTAssertNotEqual(data[0], 0xff)
XCTAssertEqual(data[0], 0x00)
}

func test_initDataWithReference() {
let srcArray: [UInt8] = [1, 2, 3, 4, 5]
let srcNSData = NSData(bytes: srcArray, length: srcArray.count)
var data = Data(referencing: srcNSData)

XCTAssertTrue(data == Data(bytes: srcArray))
XCTAssertEqual(srcNSData.length, srcArray.count)

// Mutate the original array to test the new instance is a copy
data.resetBytes(in: data.startIndex..<data.endIndex)
XCTAssertFalse(data == Data(referencing: srcNSData))
}
}