You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: content/2025-08-20-heapless-091.md
+28-22Lines changed: 28 additions & 22 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -8,18 +8,18 @@ template = "page.html"
8
8
9
9
# Heapless `0.9.1` released
10
10
11
-
Almost 2 years after the last release, the [heapless](https://github.com/rust-embedded/heapless). The first attempt at a `0.9.0` release was yanked, due to including more breaking changes than intended. This has been fixed, and `0.9.1` has been released today.
11
+
Almost 2 years after the last release, the [heapless](https://github.com/rust-embedded/heapless) crate has a new release. The first attempt at a `0.9.0` release was yanked due to including more breaking changes than intended. This has been fixed, and `0.9.1` has been released today.
12
12
13
13
Compared to `0.8.0`, the `0.9.1` release contains a bunch of small everyday improvements and bugfixes. Most users of the library should be able to adapt with minimal changes. For more information, you can check out [the changelog](https://github.com/rust-embedded/heapless/blob/main/CHANGELOG.md). Here are some of the major changes that can improve your usage of the library.
14
14
15
15
<!-- more -->
16
16
17
17
# The `View` types
18
18
19
-
One of the main constraints when working with `heapless` types is that they all have a `const generic`. In a lot of situations, these can be removed thanks to the `View` types.
19
+
One of the main constraints when working with `heapless` types is that they all have a `const generic`. In a lot of situations, these can now be removed thanks to the `View` types.
20
20
21
-
A lot of embedded firmware will allocated a couple of buffers and pass them around to save on memory.
22
-
To make it easy to change the size of the buffers, a lot of functions will carry along these `const generics`:
21
+
A lot of embedded firmware will allocate a couple of buffers and pass them around to save on memory.
22
+
To make it easy to change the size of the buffers, functions will carry along these `const generics`:
The new `View` variants of the types will enable you to remove the `const generics` while still keeping the same functionality:
37
+
The new `View` variants of the types enable you to remove the `const generics` while still keeping the same functionality:
38
38
39
39
```rust
40
40
useheapless::VecView;
@@ -49,10 +49,13 @@ impl App {
49
49
}
50
50
```
51
51
52
-
Callsites of the `handle_request` will essentially be able to stay the same, the function will continue to accept `Vec<u8, N>`. So what's the difference between `VecView` and `Vec`?
53
-
There are almost none, both are aliases of the same underlying type `VecInner`. The only limitation that `VecView` has compared to `Vec` is that `VecView` is `!Sized`. This means that you cannot perform anything that would require the compiler to know the size of the `VecView` at compile-time. In practice, you will always need to manipulate `VecView` through pointer indirection (generally a reference). This means you can't just create a `VecView` out of thin air, the `VecView` is a runtime "View" of an existing `Vec`.
52
+
Call sites of `handle_request` will be able to stay the same. The function will continue to accept `&mut Vec<u8, N>`.
54
53
55
-
So how can we obtain a `VecView` ? It's pretty simple: `Vec` can be *coerced* into a `VecView`. [Coercion](https://doc.rust-lang.org/reference/type-coercions.html) (in this case [`Unsized` coercion](https://doc.rust-lang.org/reference/type-coercions.html#r-coerce.unsize)), is a way the compiler can transform one type into another implicitely. In this case, the compiler is capable of converting pointers to a `Vec` (`&Vec<T>`, `&mut Vec<T>`, `Box<T>` etc...) to pointers to a `VecView`, so you can use a reference to a `Vec` when a reference to a `VecView` is exepected:
54
+
So what's the difference between `VecView` and `Vec`?
55
+
56
+
There are almost none, both are aliases of the same underlying type `VecInner`. The only limitation of `VecView` compared to `Vec` is that `VecView` is `!Sized`. This means that you cannot perform anything that would require the compiler to know the size of the `VecView` at compile-time. You will always need to manipulate `VecView` through pointer indirection (generally a reference). This means you can't just create a `VecView` out of thin air. The `VecView` is always a runtime "View" of an existing `Vec`.
57
+
58
+
So how can we obtain a `VecView` ? It's pretty simple: `Vec` can be *coerced* into a `VecView`. Coercion (in this case [`Unsized` coercion](https://doc.rust-lang.org/reference/type-coercions.html#r-coerce.unsize)), is a way the compiler can transform one type into another implicitly. In this case, the compiler is capable of converting pointers to a `Vec` (`&Vec<T, N>`, `&mut Vec<T, N>`, `Box<Vec<T, N>>` etc...) to pointers to a `VecView` (`&VecView<T>`, `&mut VecView<T>`, `Box<VecView<T>>` etc...), so you can use a reference to a `Vec` when a reference to a `VecView` is expected:
If you prefer things to be explicit, the `View` variants of types (`Vec` is not the only datastructure having `View` variants) can be obtained through `vec.as_view()` or through `vec.as_mut_view()`.
78
+
If you prefer things to be explicit, the `View` variants of types (`Vec` is not the only data structure having `View` variants) can be obtained through `vec.as_view()` or through `vec.as_mut_view()`.
76
79
77
80
The pointer to the `VecView` is the size of 2 `usize`: one for the address of the underlying `Vec`, and one for the capacity of the underlying `Vec`. This is exactly like slices. `VecView<T>` is to `Vec<T, N>` what a slice `[T]` is to an array `[T; N]`.
78
81
Unless you need to store data on the stack, most often you will pass around `&mut [T]` rather than `&mut [T; N]`, because it's simpler. The same applies to `VecView`. Wherever you use `&mut Vec<T, N>`, you can instead use `&mut VecView<T>`.
@@ -85,24 +88,27 @@ The benefits are multiple:
85
88
86
89
### Better compatibility with `dyn Traits`
87
90
88
-
If a trait has a function that takes a generic, it is not `dyn` compatible. By removing the const generic, the `View` types can make `dyn Trait` can pass around data structures without having to hard-code a single size of buffer in the trait definition.
89
-
90
-
### Better ergonomics
91
-
92
-
The View types can remove a ton of excess noise from the generics.
91
+
If a trait has a function that takes a generic, it is not `dyn` compatible. By removing the const generic, the `View` types can make `dyn Trait` pass around data structures without having to hard-code a single size of buffer in the trait definition.
93
92
94
93
### Better binary size and compile times
95
94
96
95
When you use const-generics, the compiler needs to compile a new version of the function for each value of the const-generic.
97
-
Removing the const generic means cutting down on duplicated function that are all almost the same, which improves both compile time and the size of the resulting binary.
96
+
Removing the const generic means cutting down on duplicated functions that are all almost the same, which improves both compile time and the size of the resulting binary.
97
+
98
+
### Better ergonomics
99
+
100
+
The View types can remove a ton of excess noise from the generics.
98
101
99
102
# The `LenType` optimization
100
103
101
104
Most often, buffers in embedded applications will not contain a huge number of items.
102
-
However, until `0.9.1` their capacity was almost always stored as a `usize`, which can often encode much more values than necessary.
105
+
Until `0.9.1` the capacity of the `heapless` data structures were almost always stored as a `usize`, which can often encode much more values than necessary.
106
+
107
+
In 0.9.1, data structures now have a new optional generic parameter called `LenT`. This type accepts `u8`, `u16`, `u32`, and `usize`, and defaults to `usize` to keep uses of the library simple.
103
108
104
-
In 0.9.1, most data structures now have a new optional generic parameter called `LenT`. This type accepts `u8`, `u16`, `u32`, and `usize`, and defaults to `usize` to keep uses of the library simple.
109
+
If you are seriously constrained by memory, a `Vec<T, 28>` (equivalent to `Vec<T, 28, usize>`) can become a `Vec<T, 28, u8>`, saving up to 7 bytes per `Vec`. This is not much, but in very small microcontrollers, it can make the difference between a program that uses all the memory available and one that just fits.
105
110
106
-
If you are seriously constrained by memory, a `Vec<T, 28>` can become a `Vec<T, 28, u8>`, saving up to 7 bytes per `Vec`. This is not much, but in very small microcontrollers it can make the difference between a program that uses all the memory available and one that just fits.
111
+
This release was made possible by [@sgued] and [@zeenix] joining the embedded working group as part of the libs team to help maintain `heapless`.
107
112
108
-
This release was made possible by [@sgued] and [@zeenix] joining the embedded working group as part of the libs team.
0 commit comments