Skip to main content

ParameterStorage

Struct ParameterStorage 

Source
pub struct ParameterStorage<const N: usize = nros_params::::server::ParameterStorage::{constant#0}> { /* private fields */ }
Expand description

Backing storage a caller places, then lends to a ParameterServer.

N defaults to MAX_PARAMETERS, the build-time knob (NROS_MAX_PARAMETERS / CONFIG_NROS_MAX_PARAMETERS). It is a DEFAULT, not a cap — ParameterStorage::<8>::new() and ParameterStorage::<256> are equally valid, and the server takes its capacity from whatever table it is handed.

The intended shapes are a static, a caller-owned struct field, or (with alloc) one allocation made once at start-up:

use nros_params::{ParameterServer, ParameterStorage, ParameterValue};

let mut storage: ParameterStorage<8> = ParameterStorage::new();
let mut server = ParameterServer::new_in(storage.as_table());
assert!(server.declare("max_speed", ParameterValue::Double(1.0)));

§Why this type exists at all — issue 0756

This is where the size lives, and it is enormous: ParameterValue is sized by its largest variant (StringArray(Vec<String<MAX_STRING_VALUE_LEN>, MAX_ARRAY_LEN>)), so every slot costs ~8.5 KiB whatever it actually holds. Measured: 285,184 bytes at the default 32 slots, 2,281,472 at 256. (The eight extra bytes in issue 0756’s 285,192 were the count that stayed behind on ParameterServer, which is 24 bytes total now.)

Before phase-382 W2’ that bulk was INSIDE ParameterServer, so Box::new(ParameterServer::new()) built a multi-hundred-KiB value on the STACK before copying it into the allocation — Rust has no placement-new — which silently overran a thread stack sized for anything smaller. On the Zephyr lane an image built with 256 slots booted to dds_create_participant and hung with no fault and no output, while 32 — which fits the 512 KiB main stack the cyclonedds snippet asks for — ran clean. The mitigation then was ParameterServer::init_in_place, a placement initialiser that bounded the largest temporary at one Option<ParameterEntry>.

W2’ dissolves the server half of that: ParameterServer is now a table borrow plus a count (tens of bytes), so nothing about constructing a server depends on the knob. The bulk did not vanish, it MOVED here — and so did the hazard, verbatim: Box::new(ParameterStorage::new()) is the same stack-first copy the issue was about. init_in_place is therefore kept, on the type that is actually big, and any heap-placed storage must go through it. A caller who places the storage as a static or lets W3’ carve it out of the executor backing never materialises it by value and does not need it.

Implementations§

Source§

impl<const N: usize> ParameterStorage<N>

Source

pub const fn new() -> ParameterStorage<N>

Create empty storage.

const, so a static NROS_PARAMS: ParameterStorage = ParameterStorage::new(); lands in .bss with no initialiser and no stack temporary.

Source

pub const fn capacity(&self) -> usize

Slots in this storage.

Source

pub fn as_table(&mut self) -> ParameterTable<'_>

Lend the storage to a ParameterServer.

Source

pub unsafe fn init_in_place(dst: *mut ParameterStorage<N>)

Initialise storage directly into dst, without ever materialising one by value.

Issue 0756 — see this type’s documentation for why that matters. The short version: this type is 285,184 bytes at the default 32 slots and 2,281,472 at 256, and Rust has no placement-new, so Box::new(ParameterStorage::new()) builds all of it on the caller’s stack first. Initialising through the allocation bounds the largest stack temporary at one Option<ParameterEntry>, so the NROS_MAX_PARAMETERS knob no longer decides whether boot survives.

§Safety

dst must be non-null, correctly aligned, and valid for writes of size_of::<Self>() bytes. The pointee may be uninitialised on entry; it is fully initialised on return.

Auto Trait Implementations§

§

impl<const N: usize> Freeze for ParameterStorage<N>

§

impl<const N: usize> RefUnwindSafe for ParameterStorage<N>

§

impl<const N: usize> Send for ParameterStorage<N>

§

impl<const N: usize> Sync for ParameterStorage<N>

§

impl<const N: usize> Unpin for ParameterStorage<N>

§

impl<const N: usize> UnsafeUnpin for ParameterStorage<N>

§

impl<const N: usize> UnwindSafe for ParameterStorage<N>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.