Nonescapable types don't by themselves change anything about withUnsafePointer and other unsafe APIs. It is still undefined behavior under any circumstance to escape the pointer outside of the withUnsafePointer block.
You are right; we are not yet finished providing the necessary primitives in the standard library and compiler implementation. InlineArray and Span provide the primitives for owning and referencing arrays of values, but we have yet to provide the same primitives for scalars akin to Rust's reference types. With a complete set of standard library reference types, there should be much less need to drop down to unsafe primitives. One complicating factor for Swift is that, since values do not generally have stable addresses, a stored borrow must sometimes be able to store an independent bitwise copy of the value representation, as you alluded to.
To get around the lack of scalar references, you might try using InlineArray<1, T> and Span as a stand-in:
struct ImageInfo: ~Copyable {
var raw: InlineArray<1, ImageInfoC>
init(
width: Int32,
height: Int32
) {
self.raw = [ImageInfoC(
width: width,
height: height
)]
}
}
struct UserInfo: ~Escapable {
var profileImage: Span<ImageInfoC>
var age: Int32
@lifetime(borrow profileImage)
init(
profileImage: borrowing ImageInfo,
age: Int32
) {
self.profileImage = profileImage.span
self.age = age
}
}
A fair question might be whether we should treat all imported C types as @_addressableForDependencies, since it is highly likely that code will want to form pointers to C types for interop purposes where a non-pointer Swift borrow representation would not be acceptable.