#slice #no-std #why #consider #rest

no-std loaf

Why have a slice when you can have a loaf?

6 releases

0.2.0-alpha2 Jun 11, 2022
0.1.0-alpha6 Aug 6, 2020
0.1.0-alpha4 Jul 14, 2020
0.1.0-alpha3 Jul 12, 2020

#1786 in Data structures

MIT license

17KB
215 lines

Loaf

Why have a slice when you can have a loaf?

What this is

Sometimes you know that a slice must have at least one element in it, but Rust forces you to do "last minute decision" by unwrap()ing Option from for example first() for split_first() methods.

crates.io docs.rs


lib.rs:

Why have a slice when you can have a loaf?

What this is

Sometimes you know that a slice must have at least one element in it, but Rust forces you to do "last minute decision" by unwrap()ing Option from for example first() for split_first() methods.

[Loaf] guarantees to have at least one element by its definition.

How it works

First, lets consider a simple slice

let x: &[u8] = &[10, 42, 0, 7, 91];

&[u8] underneath is really just a pair of a pointer to buffer and its length (a fat pointer)

[ ptr: *const u8 | len: usize = 5 ]
   |                |
   |                v       
   |    | <-       [u8]       -> |
   |    +----+----+----+----+----+
   +--->| 10 | 42 | 00 | 07 | 91 |
        +----+----+----+----+----+

Thats because size of [u8] can be known only at runtime.

Rust also allows to define a structure that has exactly one dynamically-sized type at the end of it.

struct LoafT<u8, 2> {
    loaf: [u8; 2],
    rest: [u8],
}
let x: &[u8] = &[10, 42, 0, 7, 91];
let loaf: &LoafN<u8, 2> = abracadabra!(slice);

In this case the len also contains the length of [u8]

[ ptr: *const ?? | len: usize = 3 ]
   |                     |
   |                     v       
   |    | [u8; 2] | <-  [u8]  -> |
   |    +----+----+----+----+----+
   +--->| 10 | 42 | 00 | 07 | 91 |
        +----+----+----+----+----+

ptr doesn't have here a clear type, because *const LoafN<u8, 2> is itself a fat pointer (because of the [u8] field).

The Hack

Rust does have a way to fiddle with fat pointer internals, but it requires ptr_metadata feature, which are only avaliable on nightly. The hack here is to create an *mut [T] as it was *mut Loaf<T> and then cast it.

See Loaf::from_slice source code for more details

Safety

As long as two arrays could be interpreted as one bigger and vice versa, everything should be alright

No runtime deps

Features