More often than not, the value in Swift is doing to be a Data, which would be very common if you were storing JSON objects. So far, I've come up with this code snippet, but is there a more efficient way?
let valueData = try JSONEncoder().encode(record)
valueData.withUnsafeBytes { (valueBytes: UnsafeRawBufferPointer) in
let valuePtr = valueBytes.bindMemory(to: CChar.self).baseAddress!
rocksdb_put(db, writeOptions, keyData, keyData.count, valuePtr, valueBytes.count, &error)
}
It's my understanding that when rocksdb_put returns, then the caller is free to deallocate any bytes used for the key or value field.
Internally, RocksDB uses a non-owning structure called a Slice to store char *data_ and size_t size_ members. If you trace through a Put call, the contents of a Slice are eventually copied into an std::string using .append. At that point, I assume RocksDB has a copy by the time the initial _put call returns.
Assuming this is true, then there is no more efficient pattern. The call to bindMemory(to:) is technically unsafe: Swift does not allow you to randomly bind this memory. However, as a practical matter, as used here, you are extremely unlikely to violate an aliasing rule.
However, in Swift 5.6 you should be able to avoid the pointer binding and pass the UnsafeRawPointer from bytes.baseAddress directly to the C call, thanks to SR-0324.
nope, the only cases are DataProtocol and those of which that are not contiguous bytes that have to allocate for that method. All Data instances have contiguous storage and can at least temporarily expose it via that family of methods.