I mentioned this in Pitch: Unicode Processing APIs, but I think it's a separate enough issue to warrant a different thread. It would be good to discuss this now before all the new ownership stuff gets locked in. What follows is a lightly adapted version of what I posted before.
There's a class of C APIs that are designed to be zero copy that are impossible to use from Swift – at least using String – without doing a memcpy of the underlying data. Here's an example.
Consider this (simplified) API from Tree-sitter:
typedef struct {
void *payload;
const char *(*read)(void *payload, uint32_t byte_index, uint32_t *bytes_read);
} TSInput;
TSTree *ts_parser_parse(TSParser *self, TSInput input);
TSInput is a closure. When you call ts_parser_parse
, your TSInput closure is called N times, giving you the opportunity to provide a (pointer, length) pair to some contiguous string data. You don't have to provide the whole string at once. Just whatever is convenient – if you were using this with BigString
from Swift Collections, returning a pointer to the data stored in a single leaf of the tree each time your closure is called is the obvious choice.
A Swift API might look something like this:
let str = "..."
let parse = Parser()
let syntaxTree = parser.parse {
// this does not exist
return str.escapingBufferPointer
}
// make sure str's lifetime extends to here
While your pointers escape the TSInput closure, Tree-sitter guarantees they do not escape the call to ts_parser_parse
.
There's no way to safely do this using String without manually allocating a buffer, copying the contents of the string you want to escape into that buffer, and making sure to clean it up when you're done. For a concrete example, look at how SwiftTreeSitter handles this.
This is a more general problem than just String though, because Swift doesn't have any way to escape a pointer. AFAIK this is not fixed by [Pitch] Safe Access to Contiguous Storage. StorageView has withUnsafeBufferPointer, similar to other standard library types, but just like the existing methods, the provided pointer isn't allowed to escape from the closure that it's yielded to.
I think this is a relatively common pattern in C APIs, and it should be possible to call this class of API efficiently from Swift.