Bare-metal array creation and return


#1

Hi,

I’m new to Rust and trying to implement a bare metal application (with no_std) on ARM. Currently I want to read and write bytes from the SPI interface. The following snippet (kind of) works, but I would prefer to refactor it, so that I have different buffers for read and write. How can I create a object with a length (specified at creation time) without vec!?

pub fn transmit_bytes(buffer: &mut [u8]) {
    let trans_len = buffer.len();

    for b in buffer.iter() {
        send_byte(*b);
    }

    while transmit_fifo_full() {}

    for i in 0..trans_len {
        buffer[i] = recv_byte();
    }
}

Kind regards,
Roman


#2

Your function already allows non-Vec objects of any lengths. For example, this allocates a buffer on the stack

let mut buf = [0u8; 100];
transmit_bytes(&mut buf);

But arrays have compile-time fixed size. For size variable at run time you need to allocate on the heap. For this an alternative to Vec is Box<[T]>, but it’s not worth the effort, since it’s effectively doing the same thing except tracking unused capacity, so the difference in overhead or performance is almost none.


#3

Thank you. I guess I’m thinking the wrong way.


#4

Why not get the user to pass in references to two arrays? That way one can be used for input and the other for output. The caller would then allocate a couple static arrays on the stack and pass them to your transmit_bytes() function as a slice.


#5

That’s what I did now ;-).


#6

What’s really important about this example is that transmit_bytes is accepting a slice (which, in the ABI, is equivalent to a pointer and a length). This means you can do this:

let mut buf = [0u8; 100];
transmit_bytes(&mut buf[50..100]);

Note that the 50, and the 100, can both be variables. So while the actual allocation is fixed size, the slice doesn’t have to be.


#7

Thank you for pointing that out. Maybe that would be useful later.