BINDINGS/RUST: Initial Rust bindings #10291
Open
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
What?
Make UCX bindings for Rust so the UCX can be used in Rust programs
Why?
I wanted to learn Rust and decided the best way to do that is with a real project, so UCX gets Rust bindings and I wanted to share the results. This is very incomplete but I'm posting it early to see if someone with more Rust experience has suggestions. Right now you can setup and call an active message
How?
Some of the interesting bits about Rust coming from a C/UCX programming model is that Rust functions often return a
Result
type, which has anOk
andErr
type. Inlib.rs
you can find a wrapper function that will convertucs_status_ptr_t
returned from ucp into aResult<Option<Handle>, ucs_status_t>
. You'll see a lot of.unwrap()
function calls and that will evaluate theResult
to either return the underlyingOption<Handle>
value or handle the error by aborting the programming and giving the string value of the error, something likeUCS_ERR_INVALID_PARAM
. You would think this would cause pain in the code generation, but Rust is very good at optimizing this away. It looks like Rust automatically does the same thing we often do in UCX code where there is a list of resource cleanup labels and goto's to jump to these labels if there is an error. TheOption<Handle>
offers a replacement for checking forUCS_OK
and using theUCS_PTR_IS_PTR()
macros. If the option is empty that is the equivalent to getting backUCS_OK
. A non-empty option will have aHandle
struct that represents a request handle that can be queried for completion. Rust makes very efficient assembly for this, as best as I can tell it's free? It's also a lot more readable if you compare the UCX example codes and the test in thelib.rs
function.Another thing worth explaining is the Builder pattern used. Rust wants to be a safe language free from undefined behavior. In UCX we use field flags in various param structs to define if a field in present in a struct or not and then UCX promises to not access those fields. However, Rust cannot see this promise since it's in the documentation and the compiler cannot read that and will be unhappy. This can be solved though using the
unsafe
keyword. So the builder pattern can be used to mark the field flags and set the parameter in the structure and only touching the struct and declaring it initialized is unsafe. In the generated code this will all compile down into a const struct. Another interesting trick is that in the request param struct builder there is an if to check if there is a mismatch with the user asking for both no immediate completion and force immediate completion. This does not translate into any assembly and will either compile down to a const or it will fail at compile time. It feels like it should be possible to go further and do things like make sure that EP param structs have one and only one connection type.The best way to start reviewing this code should probably start with
lib.rs
. That file is the one with the best docs in the comments. The filecontext.rs
is also good.If you want to try it out you will need to first do the regular configure/build of the base library and then in the Rust bindings dir you can run
cargo build
to build the library andLD_LIBRARY_PATH=$LD_LIBRARY_PATH:../../src/ucs/.libs:../../src/uct/.libs:../../src/ucm/.libs:../../src/ucp/.libs cargo test
to run the test.