Zinc mini post-mortem


#1

Just wanted to scratch down a few notes on the state of zinc.rs. It was an interesting journey, but it seems to be a big mess now.

TL;DR

Zinc was becoming more and more hard to maintain, as most of the effort was spent to catch up with nightly. The generated ioregs approach was semi-good, the platform tree approach was horribly broken.

Context

Ioregs is zinc implementation of platform registers. It allows a simple and documented API into the hardware memory mapped i/o, with type checking, atomic promises and nice goodies (builder pattern works awesome there).

Platform trees are the API that allows to define hardware configuration in the code and map it to the running functions with rust guarantees of ownership.

What went wrong

Ioregs are getting broken every week, as they depend a lot on the unstable rust code that changes every so often. The concept itself is great, but too painful to manage. Given that most of platform description comes from XML files, it made way more sense to skip the rust macro code and render XML to target code straight from a dynamic-typed language with nice templating capabilities (python). That even makes it to compile faster!

PT problem was originating in HW to SW interaction. I’m a very big fan of nesC development model where you hook up components to each other and everything is instantiated at compile time. TO reimplement that in zinc we had to use lots and lots of static dispatch, where designated types were generated by magic. That is crazy hard to maintain, and it doesn’t allow any sensible autocompletion to kick in as the type you see turn into something entirely different. Dynamic dispatch enforces a performance penalty, that, I guess, I should have been ok with. It’s just way simpler to code.

I wanted to split zinc up into crates to make compilation times faster—specifically there’s little need to recompile every single ioreg definition every time. Zinc moved from feature-enabled to all-enabled/strip at link time model to make better use of unit testing. Apparently, the crate story for cross-compilation isn’t any good still, that caused me bunch of pain points and it never worked after all.

What went good

Ioregs is a brilliant concept that shows how easily readable code can be optimized down to a single STR instruction. It’s great, it’s effective, it’s fun to play with.

Writing embedded code in rust is actually comfortable, even if you’re writing a preemptive scheduler. The careful balance of safe/unsafe code allows to do everything you’d do with C but the compiler is watching over your shoulder and slapping your hands too. I never had any serious issues with borrow checker while writing embedded multi-process code (the IPC was a bunch of duct tape though).

Unit testing of MM I/O is great, simple, and effective. Loved that part.

Final thoughts

If I were to start zinc from scratch, I’d focus more on the KISS approach, and less premature optimization, and would actually make an arduino-like platform at first. The cross-compiling story is still not as good as I want it to be, but it’s not as bad as it was when we started zinc. The rust community is awesome and I saw great amount of the superb code contributions.

Zinc, in the way it is now, is dead, and that’s a horse I stopped beating. Zinc want to see some time in 2017 is one that uses stable rust and just makes things work. And is shipped as a bunch of simple to use crates :slight_smile: