From 093c0bfb2b2d5b6d36800529386a059b4daf6ba8 Mon Sep 17 00:00:00 2001 From: Peter Kehl Date: Thu, 6 Oct 2022 12:50:54 -0700 Subject: [PATCH] Moved parts from peter-kehl/no_std_rust_lib_presentation. Misc. --- README.md | 131 +++++++++++++++++++++++++++++++++++++++++++++++++++-- index.html | 33 ++++++++------ 2 files changed, 147 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index c7c2b72..0438792 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,7 @@ +# Scope + +- Primary focus: Memory handling. + TODO - beware that vscode.dev can't display inferred types (of `let` definitions), neither declared parameter names in function calls @@ -6,7 +10,7 @@ TODO - VS-Code-like horizontal menu (if you have it hidden by default, toggle it with "Alt") - your VS Code theme (if you use VS Code sync) - `Ctrl + comma` shows VS-Code-like Settings -- Alternative online VS Code: +- Alternative: Online VS Code: - https://vscode.dev/github/peter-kehl/no_std_rna_slice_patterns - [Insiders (beta-like version)](https://insiders.vscode.dev/github/peter-kehl/no_std_rna_slice_patterns) - these don't have a horizontal menu, but open it by the hamburger button @@ -16,7 +20,7 @@ TODO - `nightly` Rust compiler - the actual solutions work with `stable` Rust. However, the test harness (with extras on top of of - Exercism's tests) needs `nightly` (as of mid 2022). + Exercism's tests) needs `nightly` Rust (as of mid 2022). # List of patterns (and shared utils) - [00_utils](https://github.com/peter-kehl/no_std_rna_slice_patterns/blob/main/00_utils/src/lib.rs) @@ -80,4 +84,125 @@ implementation) doesn't introduce anything new related to `no_std`, but it fits - All "unlimited" properties are constrained by available memory. - (\*) indicates a property or implementation that isn't `no_std`-specific, or is specific to this workspace. It's here for clarification. -TODO Group implementations. +TODO Group implementations? + +--- + +# Methods + +# no_std with heap + +Replace use of `HashSet/HashMap` with `BTreeSet/BTreeMap` when possible. Or create different data +structures. Or use 3rd party crates. + +Replace `Arc` with `Rc` (since there is no multi-threading in `no_std`). + +# no_std without heap + +- Have your functions accept [slices](https://doc.rust-lang.org/nightly/book/ch04-03-slices.html) + (shared or mutable), rather than `Vec` or `String`, wherever possible. Both `Vec` and `String` + auto cast/expose themselves as a slice. (This is a good practice even with heap, or in `std`.) +- Similarly, whenever possible, have your `struct`-s and `enum`-s store references, or slices, + rather than own the data. It does involve + [`lifetimes`](https://www.cloudbees.com/blog/lifetimes-in-rust), but that can be a good practice, + too. + +- Can't + [`core::iter::Iterator.collect()`](https://doc.rust-lang.org/core/iter/trait.Iterator.html#method.collect). + - Even though `collect()` does exist in `core` (and not only in `std`), it can collect only to + implementations of + [`core::iter::FromIterator`](https://doc.rust-lang.org/core/iter/trait.FromIterator.html). (That, + again, exists in `core`, in addition to `std`). However, there are no `core`-only implementors of + `FromIterator` (other than collecting zero or one item [to + `core::option::Option`](https://doc.rust-lang.org/core/iter/trait.FromIterator.html#impl-FromIterator%3COption%3CA%3E%3E) + or [to + `core::result::Result`](https://doc.rust-lang.org/core/iter/trait.FromIterator.html#impl-FromIterator%3CResult%3CA%2C%20E%3E%3E)). + - `collect()` doesn't exist for arrays nor slices (without heap). Hence we need to iterate and + store in a (mutable) array or slice. _New to Rust? And Worried about side effects?_ Good news: + _Safe_ Rust prevents unintended side effects, because we "[cannot have a mutable reference while + we have an immutable + one](https://doc.rust-lang.org/nightly/book/ch04-02-references-and-borrowing.html#mutable-references) + to the same value." +- there is no dynamic/resizable data storage + - a `no_std` design needs to batch/buffer/limit the total data + - use slices (instead of arrays) as parameter types wherever possible + - design function as accepting (shared or mutable) slices + - functions may need to write to mutable slice parameters (instead of returning). + +--- + +- _New to Rust?_ Mutating slices or references/arrays may sound less "functional". But, in Rust any + mutated parameters must be declared so. Any parameter that may be modified must be either + - [`borrowed`](https://doc.rust-lang.org/nightly/book/ch04-02-references-and-borrowing.html) + (passed) as a mutable reference or slice (which has exclusive access), or + - passing ownership of the object: + - [_"move"-d_](https://doc.rust-lang.org/nightly/book/ch04-01-what-is-ownership.html#ownership-and-functions) + (or [`clone()`-d](https://doc.rust-lang.org/core/clone/trait.Clone.html) first and then the + clone is moved), or + - [_copied_: Ownership > Stack-Only Data: Copy] + ]() + if it implements [`Copy` ](https://doc.rust-lang.org/core/marker/trait.Copy.html) trait. + _New to Rust?_ A `trait` is similar to an `interface` in Java, a `virtual` abstract + field-less class with virtual methods in C++, or a `protocol` in some other languages. + - See also + [ownership](https://doc.rust-lang.org/nightly/book/ch04-00-understanding-ownership.html), + [borrowing](https://doc.rust-lang.org/nightly/book/ch04-02-references-and-borrowing.html) and + [lifetimes](https://doc.rust-lang.org/nightly/book/ch10-03-lifetime-syntax.html). +- alternatively, use [`const` generics](https://rust-lang.github.io/rfcs/2000-const-generics.html), + a subset of Rust [generics](https://doc.rust-lang.org/nightly/book/ch10-00-generics.html), for + both function parameters and return values + - make the array size (which has to be known in compile time) a `const` generic parameter + - beware that generics make the executable larger, and the build process takes longer; it helps to + combine (`const`) generics for some functions, and slices for other +- application's top level function(s) define the array(s), or array-containing structs/enums, on + stack. Then they call the processing functions with slices, or with const generic-sized arrays + (or their references) + +--- + +- this way you can re-use the same processing functions +- if you can process the incoming data last in, first out (in LIFO/stack order), you could recurse + (possibly batching the data in an array at every recursion level) +- Have functions return an iterator wherever possible. (And use it for parameters, too. Again, a + good practice even in `std`.) + - may need to implement + [core::iter::Iterator](https://doc.rust-lang.org/core/iter/trait.Iterator.html) to represents + results of your transformation. Such iterators refer to the underlying iterator (data + source/origin) and they may keep some state on top of it (a state machine). + - You may want to combine/chain functions accepting and returning iterators. Use keyword + [`impl`](https://doc.rust-lang.org/nightly/book/ch10-02-traits.html#returning-types-that-implement-traits) + to define types like `impl Iterator`. + +--- + +# no_std without heap > Alternatives to collect() + +When developing for `no_heap`, we can't `collect()` from iterators. That makes some tasks that need +random access (access to all items at the same time, like sorting) difficult. + +This would need limit on number of items to be known at build time. Then the caller would pass a +(mutable) reference to an array, or a slice, where we would manually collect the items (in a `for` +loop, or `.foreach()` closure). + +--- + +# no_std without heap > Compound iterators + +For some purposes we may not need access to all items if we don't need to access the whole +collection. Then all we do needs sequential access only, for example a one-to-one transformation, +and/or filtering. + +For that we may need to implement a compound iterator. It would contain an underlying iterator (or +several iterators) over the source data. It iterates and transforms and/or filters the source data. + +[Exercism Rust track](https://exercism.org/tracks/rust/exercises) > [RNA +Transcription](https://exercism.org/tracks/rust/exercises/rna-transcription) + +In addition to the text of the assignment, it helps to see the +[tests](https://github.com/peter-kehl/x-rust/blob/main/rust/rna-transcription-std/tests/rna-transcription.rs) +(or the same tests used for [`no_std` +version](https://github.com/peter-kehl/x-rust/blob/main/rust/rna-transcription-no_std-no_heap/tests/rna-transcription.rs)) + + + + diff --git a/index.html b/index.html index e1c7c05..5bd1eea 100644 --- a/index.html +++ b/index.html @@ -3,6 +3,7 @@ https://github.com/hakimel/reveal.js/blob/master/index.html. It contains tabs instead of spaces, because that's how the original file was. Keeping them as tabs makes it easier to compare/update. + However, this uses a customized theme from https://github.com/peter-kehl/reveal.js. --> @@ -12,9 +13,10 @@ + no_std (embedded/low level-compatible) patterns in Rust - + @@ -40,22 +42,32 @@ + +
-
- +
- + - - -