Search code examples
swiftunsafe-pointers

Implicit conversion from UnsafeBufferPointer to UnsafeRawBufferPointer


UnsafePointer can be implicitly cast to UnsafeRawPointers when passed as parameters:

var x = 42

func print<T>(address p: UnsafeRawPointer, as type: T.Type) {
    print(p.load(as: type))
}

withUnsafePointer(to: &x) { (ptr) in
    print(address: ptr, as: Int.self)  // Prints "42"
}

However, it seems that UnsafeBufferPointer cannot be implicitly cast to UnsafeRawBufferPointer:

var x = 42

func printBuffer<T>(address p: UnsafeRawBufferPointer, as type: T.Type) {
    print(p.load(as: type))
}

withUnsafePointer(to: &x) { (ptr) in
    let buff = UnsafeBufferPointer(start: ptr, count: 1)
    printBuffer(address: buff, as: Int.self)  // 1
}

In this snippet, the line marked // 1 errors:

cannot convert value of type 'UnsafeBufferPointer' to expected argument type 'UnsafeRawBufferPointer'

Why is this implicit conversion not possible, when the previous one is allowed?


Solution

  • You cannot cast a UnsafeBufferPointer to a UnsafeRawBufferPointer because that is more than reinterpreting the pointer: It requires to calculate the raw byte count.

    But you can create a UnsafeRawBufferPointer from a UnsafeBufferPointer:

    withUnsafePointer(to: &x) { (ptr) in
        let buff = UnsafeBufferPointer(start: ptr, count: 1)
        let rawBuff = UnsafeRawBufferPointer.init(buff)
        printBuffer(address: rawBuff, as: Int.self)
    }
    

    Here is the implementation of that initializer in UnsafeRawBufferPointer.swift.gyb:

      /// Creates a raw buffer over the contiguous bytes in the given typed buffer.
      ///
      /// - Parameter buffer: The typed buffer to convert to a raw buffer. The
      ///   buffer's type `T` must be a trivial type.
      @_inlineable
      public init<T>(_ buffer: UnsafeMutableBufferPointer<T>) {
        self.init(start: buffer.baseAddress!,
          count: buffer.count * MemoryLayout<T>.stride)
      }