Hello!
I'm trying to interoperate with C in a safe way by annotating the API to generate safe wrappers but I don't know how to pass a mutable span.
To make my issue obvious I created this super simple C module:
int mini_sum(const unsigned char *in32);
int mini_fill(unsigned char *out64, const unsigned char *in32);
With these annotations:
---
Name: CMini
Functions:
- Name: mini_sum
Parameters:
- Position: 0
NoEscape: true
BoundsSafety: { Kind: counted_by, BoundedBy: 32 }
- Name: mini_fill
Parameters:
- Position: 0
NoEscape: true
BoundsSafety: { Kind: counted_by, BoundedBy: 64 }
- Position: 1
NoEscape: true
BoundsSafety: { Kind: counted_by, BoundedBy: 32 }
Taking a look at what that generatesβ¦
xcrun swift-synthesize-interface \
-I Sources/CMini/include \
-Xcc -fmodule-map-file=Sources/CMini/include/module.modulemap \
-module-name CMini \
-target arm64-apple-macos27 \
-sdk $(xcrun --sdk macosx --show-sdk-path)
I get these result (relevant part):
public func mini_sum(_ in32: Span<UInt8>) -> Int32
@_lifetime(out64: copy out64)
public func mini_fill(_ out64: inout MutableSpan<UInt8>, _ in32: Span<UInt8>) -> Int32
So far great. I can call mini_sum with a span and not get any safety warnings!
import CMini
let input = [UInt8](repeating: 7, count: 32)
let n = mini_sum(input.span)
But calling mini_fill in similar fashion has proved impossible with a wack-a-mole of errors:
var out = [UInt8](repeating: 0, count: 64)
var mutableSpan = out.mutableSpan // Lifetime-dependent value escapes its scope
_ = mini_fill(&mutableSpan, input) // Expression uses unsafe constructs but is not marked with 'unsafe'
_ = consume mutableSpan // Missing reinitialization of inout parameter 'mutableSpan' after consume while accessing memory
The example above is just one of the many iterations I have tried which include everything from OutputSpan, to MutableSpan(mutating:) initializer.. nothing seems to fit.
I can compile if I just pass a MutableSpan<UInt8>() but that clearly crashes on runtime. I also suspect the compiler may not be picking up the right overload for the function... although it shows up in the generated wrapper so I don't know.
Can anyone point me in the right direction? Or at least show me how to create a MutableSpan in Swift 6.4.
Thanks!!