There are cases when you have to deal with a structure of certain type, but the upstream API requires you to present it though a pointer to another type at other places.
For instance, Unix Bind is expecting its second argument to be a pointer to a sockaddr
, whereas the constructor should be sockaddr_in
.
For now I'm sticking to a two-layer with*
:
var sa = sockaddr_in(/* ... */)
withUnsafePointer(to: &sa) { _sa in
_sa.withMemoryRebound(to: sockaddr.self, capacity: 1) { __sa in
let err = bind(fd, __sa, socklen_t(saSize))
precondition(err == 0)
}
}
However, I'm discouraged by noisiness of this approach. When I use unsafeBitCast
between pointer types:
bind(fd, unsafeBitCast(__sa, to: UnsafeMutablePointer<sockaddr>.self), socklen_t(saSize))
Then the compiler warns me not to do so, and recommends resort to withMemoryRebound
.
When I use an in-place constructed pointer:
UnsafeMutablePointer(mutating: &sa).withMemoryRebound(to: sockaddr.self, capacity: 1) { _sa in
let err = bind(fd, _sa, socklen_t(saSize))
precondition(err == 0)
}
Then it works as well as the initial version, and rids us of one level of nesting. Although it looks more frail than with*
. Also it's unclear, if the in-place pointer is the correct approach, why withUnsafePointer
even exists.
Having that said, what is the canonical way to reinterpret a structure in Swift?
Your first method is the correct one, using
withUnsafePointer()
andwithMemoryRebound()
, as one can see from the various examples provided in UnsafeRawPointer Migration, e.g.The other approach
looks fragile to me.
sa
is passed as aninout
parameter to the constructor ofUnsafeMutablePointer()
, but that may be the address of temporary storage, and there is no guarantee that it is still valid when the constructor has returned and the closure is called.