Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reduce boiler plate c-bridge code #2

Open
Sjors opened this issue Jun 13, 2019 · 4 comments
Open

Reduce boiler plate c-bridge code #2

Sjors opened this issue Jun 13, 2019 · 4 comments

Comments

@Sjors
Copy link
Owner

Sjors commented Jun 13, 2019

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".

@pavel-bc
Copy link

@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
}

@jgriffiths
Copy link

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.

@Sjors
Copy link
Owner Author

Sjors commented Sep 14, 2020

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.

@jgriffiths
Copy link

jgriffiths commented Sep 14, 2020

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants