Permalink
Switch branches/tags
Nothing to show
Commits on Dec 3, 2018
  1. Create README.md

    bonzini committed Dec 3, 2018
  2. "rustify" implementation, with bindings provided as extern functions

    bonzini committed Dec 3, 2018
    Finally in this patch we complete the exercise and we are able to enjoy
    the benefits of Rust in implementing the Foo data structure.
    
    The data structure is still defined in a C header, and the
    "bindgen::foo:Foo" struct that bindgen created for us is still what
    gets re-exported as "foo::Foo".  However, it now grows Rust methods,
    including a constructor "Foo::new" that was not even there in the original
    C API, and the C API becomes a simple wrapper that converts the raw
    pointers to C code and calls those methods.  In this commit we add a
    second test, which calls those Rust methods instead of relying on the
    C API.  Note that this test does not have to use any unsafe block,
    and in fact none of the code added in this commit does.
  3. replace with Rust implementation

    bonzini committed Dec 3, 2018
    In this commit, the foo_get and foo_set functions switch to a Rust
    implementation.  Even though bindgen still generates the prototypes
    for them in "bindgen::foo", we do not re-export them from "foo".
    Instead, "foo" implements the functions that C code will call.  They
    are marked as "no_mangle" which is essentially the Rust equivalent
    of C++'s extern "C".
    
    Note that the implementation is unsafe; it has to be for two reasons.
    First, because it dereferences a raw pointer ("let foo = &*foo" and
    the similar assignment in foo_set) that could be pointing to garbage
    or to freed data---and this is unsafe, so much that the code would not
    compile at all if those dereferences were not "unsafe".  Second, because
    we have no idea of what could be in the struct, for example it might
    be uninitialized.  This is not something that the compiler tells us,
    we have to figure it out!
    
    Note that this is probably not a step that you would do explicitly,
    in practice.  As long as you have tests for the C API written in either
    Rust or C, you can switch directly to a Rust implementation as in the
    next patch.
  4. add Rust bindings to the C library

    bonzini committed Dec 3, 2018
    In this commit, we start integrating the C and Rust code; in particular,
    we keep the C implementation and add Rust tests for it.
    
    The Rust library grows two modules, "foo" and "bindgen::foo".  The former
    provides the public API, while the latter is the automatically generated
    code from bindgen.  We do this already, even though for now the public API
    is just forwarding the bindgen struct and entry points using "pub use".
    Separating the automatically generated code into the bindgen module lets
    us disable some errors that make no sense for bindgen code, so it's a
    good idea.
    
    We also need to link the C code into the Rust tests.  Doing this
    requires adding a build.rs file.  This Rust source file produces two
    directives for cargo, essentially corresponding to -L and -l on the
    linker command line.
  5. integrate Cargo into the Makefile

    bonzini committed Dec 3, 2018
    Here we add a Rust library, just like one for which "cargo new --lib"
    creates the scaffolding, to the project's build system.
    The Rust library creates another static library, and the Makefile
    takes care of linking it into the main program.
    
    For simplicity we will let Cargo run the build of the Rust parts, but
    since the project is still first and foremost a C one, the overall build
    will be driven by "make".  Therefore, after this commit you will be able
    to do "make check" and see some Rust tests run.
    
    At this point, the C code is already linking to the Rust library, but
    the Rust library however is not able to use the C code; this will change
    in the next commit.
  6. initial C code

    bonzini committed Dec 3, 2018
    The C code consists of a trivial library with three functions.
    This commits adds the library (src/foo.c and src/foo.h), a program
    that uses it, and a Makefile to build it.
    
    The plan is to move two of them (foo_get and foo_set) to Rust, while
    keeping the third (foo_print) in C.  Both C and Rust code must be
    able to access the entire implementation, because the program will
    remain in C, while the tests will be in Rust and will want to call
    foo_print.
    
    The conversion to Rust is pretty smooth, because there are no ownership
    issues---the data structure is entirely self-contained.  There is only one
    prerequisite for the API to be nicely usable from Rust code, which is
    to use "const" properly in "foo_get", "foo_set" and "foo_print".