Stretch — A flexbox implementation in Rust
Let’s talk about Layout. Layout is fundamental to any UI application. The layout engine is what takes a set of rules and figures out where to place elements on the screen. This sounds simple enough but as UIs become increasingly complex we rely more on the layout engine to be able to create these UIs as easily as possible. Not only should it be easy to build these UIs but the engine performing this work is also required to do so at minimum cost as it runs possibly on every frame (for example when performing layout animations).
Every platform ships with their own take on what a layout engine should be. iOS uses a system called AutoLayout based on an algorithm called Cassowary, Android has a number of layout primitives, one of which is based on the same algorithm which it calls ConstraintLayout. On the web we have a number of layout systems, most commonly we use flexbox or grid layout for building complex UIs. These systems has all of their pros and cons but common to all of them is that they make complex and responsive UIs fairly easy to declare.
When designing a UI framework one of the first choices you have to make is what layout system to adhere to. For the most part this choice is simple, just rely on whatever the framework gives you. This is the appropriate choice for most frameworks and is for example what React has done. However this choice is much less obvious when building a cross-platform framework such as Shard. When developing a cross-platform framework it is key that a layout looks as expected on all platforms. This is incredibly tedious if the underlying layout engine on the various platforms is different. This is even true for cases such as AutoLayout and ConstraintLayout where they are both based on the same underlying algorithm. Differences in implementation and API can easily lead to slight variations in how layouts are calculated.
Prior to starting Visly and working on Shard I led the Yoga team at Facebook solving exactly this problem. My team built the underlying cross-platform layout engine powering React Native as well as a handful of other internal and open source frameworks. All in all most of Facebook runs on Yoga, wether through React Native, Litho, or ComponentKit. I learnt first hand the importance of trusting the layout system. Trusting that a layout on one platform would behave the same across others. Naturally when we started work on Shard we decided to base it on Yoga, a proven cross-platform layout engine. So why create stretch?
- We wanted to move faster than was possible when building on top of Yoga. Due to Yoga powering most of Facebook’s mobile surfaces it is incredibly difficult to make any changes to the algorithm. Especially as we have no insight into Facebook’s test suite.
- Compatibility with web browser implementations of flexbox was a must-have feature. While Yoga for the most part mimics the behavior of Chrome it has some key areas where it differs. Specifically in the way it interprets flex-basis. In the near future we will be developing a version of Shard that runs on the web so this is incredibly important to us. Due to the previous point this would also be near impossible to fix in yoga at this point.
- Finally we wanted to work in a more modern codebase which will allow us to make changes with much higher confidence as well as introduce larger architecture changes more easily in the future such as multi-threaded layout. Choosing rust instead of C/C++ has been great for us so far.
Stretch is still in its infancy and the API is bound to change quite a bit over the next couple of months but we are quite happy with the results so far. We have over 250 tests passing, most of which are autogenerated from running the same layout in Chrome. This ensures web-compatibility and overall correctness.
Head over to https://github.com/vislyhq/stretch to learn more. Also check out https://shardlib.com for more on what we are building or just get an insight into how we are running rust across iOS and Android.