libwally-swift
libwally-swift copied to clipboard
Reduce boiler plate c-bridge code
For example in order to call bip39_mnemonic_from_bytes
and convert Data
to String
:
precondition(entropy.data.count <= MAX_WORDS)
var bytes = UnsafeMutablePointer<UInt8>.allocate(capacity: MAX_WORDS)
let bytes_len = entropy.data.count
var output: UnsafeMutablePointer<Int8>?
defer {
wally_free_string(output)
}
entropy.data.copyBytes(to: bytes, count: entropy.data.count)
precondition(bip39_mnemonic_from_bytes(nil, bytes, bytes_len, &output) == WALLY_OK)
if let words_c_string = output {
let words = String(cString: words_c_string)
self.init(words)
} else {
return nil
}
This code is currently not reused in any way, even though libwally-core only uses a limited number of input and output data types.
One approach could be similar to how libwally-core Python tests work, with a mapping of C to Python: https://github.com/ElementsProject/libwally-core/blob/master/src/test/util.py
-
('bip39_mnemonic_from_bytes', c_int, [c_void_p, c_void_p, c_ulong, c_char_p_p])
The Swift Package Manager should be useful ingredient. See e.g. this blog post, which suggests creating a "basic wrapper" and then "create a second Swift wrapper: a wrapper around the wrapper, providing a more natural Swift implementation".
@Sjors do you think this approach with extensions might be worth it?
Here's the resulting example saving some lines (don't think it's possible to get rid of defer
here):
precondition(entropy.data.count <= MAX_BYTES)
var output: UnsafeMutablePointer<Int8>?
defer {
wally_free_string(output)
}
precondition(bip39_mnemonic_from_bytes(nil, entropy.data.toPointer(), entropy.data.count, &output) == WALLY_OK)
if let words_c_string = output {
let words = String(cString: words_c_string)
self.init(words)
} else {
return nil
}
Please note that wally now has a wrapper generator script: https://github.com/ElementsProject/libwally-core/blob/master/tools/build_wrappers.py
This has enough information to generate the c++ wrapper https://github.com/ElementsProject/libwally-core/blob/master/include/wally.hpp, and so should be enough to generate a low-level swift wrapper for you to wrap further.
I'm happy to take patches that do this into wally, if you need help feel free to @ me.
Last time I tried it was an unbelievable pain to get C++ to work with Swift, whereas C was easy. But that may just me my bad.
Last time I tried it was an unbelievable pain to get C++ to work with Swift, whereas C was easy. But that may just me my bad.
Yes, its easier to wrap C - however my comment above is referring to the fact that in wally we can now generate C++ wrappers that call the wally C code. Looking at the wrapper code posted above, I think the wally code generation framework would be easy to modify to fully generate a low-level swift wrapper.