Document several factors constraining `libtock_core`'s design. This Design Considerations document outlines a number of considerations that affect the design of `libtock_core` which do not impact most Rust projects. It is intended to help onboard new contributors and to remind long-term contributors of constraints that other `libtock_core` clients have.
diff --git a/doc/DesignConsiderations.md b/doc/DesignConsiderations.md new file mode 100644 index 0000000..1c1e3bb --- /dev/null +++ b/doc/DesignConsiderations.md
@@ -0,0 +1,120 @@ +Design Considerations +===================== + +This document describes several of the factors that constrain the design of +`libtock_core`. + +## Size impact + +Tock is designed to run on hardware with limited program storage and limited +RAM. On Google's H1 chip, the Tock kernel and apps are limited to a 256 KiB +flash region. The HiFive1 Rev B board has only 16 KiB of RAM. + +Note that a Tock system may have multiple process binaries, each of which uses +`libtock_core`, so `libtock_core` must minimize its size impact to the extent +possible. + +A process binary is generally stored in non-volatile memory and contains: + + * Runtime headers (the `.crt0_header` section) + * Executable code (the `.text` section) + * Read-only data (the `.rodata` section) + * Non-zero-initialized read-write data (the `.data` section) + +A process' memory section is in RAM and contains: + + * Heap memory (if a dynamic memory allocator is present) + * Zero-initialized read-write data (the `.bss` section) + * Non-zero-initialized read-write data (the `.data` section) + * Stack memory + +`libtock_core` developers should consider the space usage of their code, and +where the space usage is (non-volatile memory or RAM). Important note: the +`.data` section consumes space in both non-volatile memory and RAM! + +Most apps will not use all functionality in `libtock_core`. The size impact of +using `libtock_core` in an app should be commensurate with the `libtock_core` +functionality that app uses. If done correctly, this will allow `libtock_core`'s +users to build Tock systems with multiple small, single-purpose apps without +excessive code duplication. + +## Testability + +Programmatic tests are important to verify that new functionality works +correctly and to keep existing functionality working through nontrivial +refactorings. Different types of tests offer different capabilities: + + * **Host-based unit tests** run on a non-Tock host OS (such as Linux). They + can only be used with portable `libtock_core` code, as they code they test + must run on both Tock and the host OS. These tests must either test code + that does not directly use system calls, or must direct the system calls to + a fake Tock kernel. These tests can be fast (compile and run in seconds), + and can easily simulate a variety of failure modes (e.g. kernel errors) that + may be difficult to generate with a real Tock kernel. + * **Emulation tests** run on an emulated Tock system. Currently, emulation + tests run in QEMU on an emulated HiFive1 Rev B board. These test + `libtock_core`'s interaction with a real Tock kernel, albeit with limited + hardware access. + * **Hardware tests** run on physical hardware with a real Tock kernel. These + are end-to-end tests that test not only `libtock_core`'s functionality but + also the Tock kernel's interaction with the real hardware. However, + automating these tests is difficult, and currently we do not have a way to + run hardware tests in CI. + +If `libtock_core` is functional on real hardware with a real kernel, it should +be able to support emulation tests and hardware tests. However, host-based unit +tests require more work. In its intended use case, `libtock_core` is not +supposed to be portable, supporting only the Tock kernel. Hoever, host-based +unit tests are very valuable, both for rapid development and for testing error +handling code. To support host-based tests, `libtock_core` must be built out of +portable pieces that can be unit tested, even though the library as a whole is +not portable. + +Testing pieces of `libtock_core` against a fake kernel can be done using +dependency injection, but most dependency injection techniques have considerable +code size and RAM usage costs. `libtock_core` needs a dependency injection +technique that has minimal size impact. + +## Support multiple asynchronous programming models. + +The general Rust ecosystem has converged on futures as its building block for +interoperable asynchronous APIs, but futures have a [size +cost](https://github.com/tock/design-explorations/tree/master/size_comparison) +that makes them impractical for some use cases of `libtock_core`. Although +`libtock_core` is still a work in progress (see [issue +217](https://github.com/tock/libtock-rs/issues/217)), it will probably use an +asynchronous API design based on the [Asynchronous Components using Zero Sized +Type +Pointers](https://github.com/tock/design-explorations/tree/master/zst_pointer_async) +exploration. + +In order to interoperate with other libraries as well as the `async`/`await` +functionality built in to Rust, we need `libtock_core` to interface well with +futures. In addition, there are several use cases of `libtock_core` that consist +primarily of synchronous code, so we need to be able to use `libtock_core`'s +APIs in a synchronous manner. + +The `libtock-c` developers are already familiar with some of the complications +that come up when synchronous code is interfaced to asynchronous code. For +example, calling `printf` -- an extremely common debugging tool -- causes +callbacks to run in the background. This causes surprising and hard-to-debug +reentrancy issues. + +## Dependency tree minimization + +Some of users of `libtock_core` intend to use it in applications that will +undergo code audits for security certifications. To make this auditing +practical, it is important to allow users to use `libtock_core` without pulling +in a large dependency tree. + +As a general rule, a `libtock_core` should avoid having required dependencies +unless those dependencies are minimal (that is, avoiding the dependency would +require reimplementing nearly all of it). Dependencies included in the Rust +toolchain (such as the `core` crate and its dependencies) are an exception, as +they are a part of the language itself. + +## No hard `alloc` dependency + +It should be possible to use `libtock_core` without bringing in the `alloc`. Of +course, it is fine for `libtock_core` to offer a memory allocator as an optional +feature.