Language-level help for C to Rust porting


#1

Porting C code to Rust is something that probably will happen again and again. This interesting presentation is about porting librsvg from C to Rust:

https://people.gnome.org/~federico/blog/guadec-2018-presentation.html

Having good and updated docs helps doing similar C=>Rust conversions:

https://doc.rust-lang.org/nomicon/ffi.html#representing-opaque-structs

Also IDEs, and some more stdlib care about Rust FFI could help. But “Draining a massive struct field by field” as shown in that presentation is lot of work. How can we reduce the amount of work here (and make it less bug-prone)? Could Rust annotations, or new small Rust features help turn this gruesome work into something more reasonable? Lot of this work seems mechanical to me, so there should be ways to automate part of it.


#2

c2rust might offer at least part of the solution here: https://github.com/immunant/c2rust.

It automates porting C to unsafe Rust. An open question seems to be how to automate porting unsafe rust to safe rust.


#3

In as much as tools like c2rust or its predecessor corrode generate ugly or otherwise non-idiomatic Rust code (potentially with unnecessary use of unsafe), I think those sorts of problems aren’t just unique to mechanical translation, but also happen with human-written code.

Ideally I think a lot of the “cleanup” of translated code could be performed automatically by tools like clippy/rustfix (note I’m mostly echoing corrode author Jamie Sharp’s thoughts on the same matter).

In as much as people can find idiomatic safe patterns for things which otherwise need unsafe today, I think that’d be nice, and could provide a foundation for automatic clippy/rustfix conversions of common unsafe patterns to use new safe features.


#4

I’ve tried to implement automatic cleanups, even incorrect ones, in my C to Rust converter. I don’t think much can be done automatically beyond cosmetic changes, such as making nicer for loops instead of while, and replacing *mut T with &T in a few obvious places.

The main problem is that information required to apply bigger transformation just doesn’t exist in the C code. For example very few places can be changed to slices. I’ve found it’s common in C to give a pointer to an array without an explicit length. The length is “known” from context too opaque for the compiler to figure out.

And there are much bigger refactorings that are even harder, e.g. functions should take &mut Write instead of *mut u8 to write to a buffer, or perhaps return Vec instead of doing some caller-allocated-buffer dance.

So my hope here is: forget about C. Make good Rust refactoring tools, because C-style code in Rust’s skin is going to need a major reorganization.