Skip to main content

Context

Struct Context 

Source
pub struct Context {
    pub domain_id: u32,
    pub locator: String,
    pub mode: SessionMode,
    pub rmw: String,
    pub source: ContextSource,
    /* private fields */
}
Expand description

Phase 212.L.5 — resolved init context.

Returned by every init* entry point and every Context::* constructor. Carries the fields the user needs to construct an ExecutorConfig and open a session.

Fields are owned (String) so the Context can outlive transient parents (env caches, parsed launch files, a harness-supplied locator). That is why the type’s feature floor is alloc.

ADOPT-BOUNDED against rclrs::Context, which OWNS the rcl context. This is the resolved identity as a plain value, so:

  • There is no ok(): the value has no shutdown state; liveness is the executor’s.
  • domain_id is a public field, not a domain_id() method.
  • Executors are opened FROM it: create_executor leaks an executor-lifetime backing (needs alloc), and create_executor_in takes caller storage.

Fields§

§domain_id: u32

ROS 2 domain ID (ROS_DOMAIN_ID, default 0; baked NROS_DOMAIN_ID freestanding).

§locator: String

Middleware locator (NROS_LOCATOR; baked NROS_LOCATOR freestanding). Empty means ABSENT: nros is RMW-agnostic, so the linked backend substitutes its own default (issue 0330).

§mode: SessionMode

Session mode (NROS_SESSION_MODE, default Client).

§rmw: String

RMW implementation hint (RMW_IMPLEMENTATION / NROS_RMW).

Empty when neither var is set, and always empty freestanding (an image links exactly one backend). The runtime uses this to pick a primary backend when multiple are linked; see crate::internals::open_session.

§source: ContextSource

Source of this context — useful for diagnostics + tests.

Implementations§

Source§

impl Context

Source

pub const fn domain_id(&self) -> usize

rclrs::Context::domain_id() — the resolved ROS domain.

usize, because that is rclrs’s return type (0.7.0, rclrs/src/context.rs) and this name exists so a ported ctx.domain_id() compiles. The field stays pub and stays u32: Context is a plain value with nothing to hide, u32 is the width every producer and consumer of a domain in this tree speaks (BoardConfig::domain_id, ExecutorConfig::domain_id, NodeHandle::domain_id, the NROS_DOMAIN_ID bake), and fields and methods are in different namespaces in Rust, so the two coexist. The widening is lossless on every target here — usize is at least 32 bits on all of them, down to thumbv7m-none-eabi.

phase-467 row rust:Context::domain_id. The row proposed -> u32 once and that would have been a second, quieter port break; it then argued usize from consistency with InitOptions, which was only two thirds true — the setters took usize, the getter returned Option<u32>. Both getters speak usize now, so the argument is the one this crate can actually make: it is upstream’s type.

Source

pub fn config<'a>(&'a self, node_name: &'a str) -> ExecutorConfig<'a>

Materialise an ExecutorConfig for a node with the given name.

The returned config borrows from self, so callers usually do:

ⓘ
let ctx = nros::Context::default_from_env()?;
let cfg = ctx.config("talker");
let mut executor = nros::Executor::open(&cfg)?;

phase-427 W10 — this is the shape where the executor IS the node it was configured with, and it stays: an entry that opens exactly one node wants exactly this. What it cannot express is the second node, which is why Context::create_executor() + Executor::create_node(name) now sit beside it — the session takes no name, and each node takes its own.

§Refused when the context carries --ros-args remaps

An ExecutorConfig has nowhere to put them, so the executor Executor::open builds from it would never see them — the silent drop init_with_args exists to prevent. Such a context PANICS here, naming Context::create_executor, which installs them.

Source

pub fn default_from_env() -> Result<Context, InitError>

rclrs::Context::default_from_env() — the environment, default options.

Hosted (feature env) this reads the process environment and is exactly init(); freestanding it is Context::baked, the build environment this image was compiled for. RFC-0089 “Context and init, settled”: the semantics survive with the source moved from run time to build time, which is the bounded half of this adoption.

Source

pub fn from_env(options: InitOptions) -> Result<Context, InitError>

rclrs::Context::from_env(options) — default_from_env with the InitOptions applied on top: a Some domain replaces the resolved one, None keeps it.

Bounded: InitOptions carries rclrs’s one option, domain_id, and no other, so an option rclrs adds later is a compile error here. A domain above DOMAIN_ID_MAX is InitError::DomainIdOutOfRange. Freestanding, the base the options override is the BAKED context (Context::baked), not a process environment.

Source

pub fn new<I, S>(args: I, options: InitOptions) -> Result<Context, InitError>
where I: IntoIterator<Item = S>, S: AsRef<str>,

rclrs::Context::new(args, options) — the argv constructor. HOSTED ONLY: a freestanding image has no argv, so the name is absent there and the compiler says so.

What it does with the arguments: the same as init_with_args — -r/--remap rules inside --ros-args are parsed onto the returned context and every other ROS argument is REFUSED LOUDLY at the call (REFUSE_INIT_ARGS). Arguments outside a --ros-args scope are the program’s own and are left alone.

S: AsRef<str> is a superset of rclrs’s Item = String, so Context::new(std::env::args(), InitOptions::new()) compiles as written.

Source

pub fn baked() -> Result<Context, InitError>

phase-427 W9 — the freestanding constructor: the constants baked into this crate at compile time.

  • NROS_LOCATOR — the middleware locator. Unset or empty ⇒ empty ⇒ the linked backend’s own default (issue 0330; for zenoh-pico that is multicast scouting, which native_sim NSOS cannot satisfy — hence the bake).
  • NROS_DOMAIN_ID — the domain. Unset ⇒ 0; non-numeric ⇒ InitError::EnvParseFailed; above DOMAIN_ID_MAX ⇒ InitError::DomainIdOutOfRange.

Both names reach this crate’s build the same way they reach the board crates: on Zephyr, build.rs re-exports CONFIG_NROS_ZENOH_LOCATOR / CONFIG_NROS_DOMAIN_ID from $DOTCONFIG (nros_zephyr_build:: bake_nros_config, the issue-0460 channel); on the other RTOS lanes the fixture build exports them into the process environment. This is the ONE option_env! site for the pair — the entry macros used to carry their own copies (and nros::main!’s Zephyr arm had lost the domain half, issue 0161’s class), which is what “one source of the baked shape” replaces.

Mode is Client and rmw is empty: an image links exactly one backend and nothing bakes a session mode today.

Hosted builds have this too — it answers “what was baked”, which a hosted process rarely wants; Context::default_from_env is the constructor that picks the right source for the build.

Source

pub fn with_locator_override(self, locator: Option<&str>) -> Self

Replace the locator with one handed in at run time, when there is one.

#166 / phase-286 W1 — native_sim test parallelism: the harness launches an image with -testargs --nros-locator=<loc> and a per-test router on that ephemeral port, and nros_runtime_locator_override() (nros-platform-zephyr, argv-backed) hands it back here. None or an empty string keeps the baked value, so on real hardware — where the hook returns NULL — the bake stands. The entry macros call this after Context::default_from_env; a hand-written entry may too.

Source§

impl Context

phase-427 W10 — rclrs::Context::create_executor, and the ours-only no-leak twin beside it.

Both are gated on rmw-cffi, because an executor without the vtable runtime has no session to open; create_executor is additionally gated on alloc, because it is the one that leaks a default-sized backing.

Source

pub fn create_executor(&self) -> Result<Executor<'static>, InitError>

rclrs::Context::create_executor() — open the session this context resolved and hand back the Executor that owns it.

This is the entry a ported rclrs main lands on: upstream writes context.create_basic_executor() (or create_executor(runtime)) and gets an Executor back; ours returns a Result, so the port is a ?. The runtime argument has no counterpart here and is not accepted — one executor per RTOS task is the model (RFC-0002), and there is no runtime to choose between.

The node name is NOT taken here. Name nodes with Executor::create_node, which is where several named nodes on one session already live (RFC-0047).

§Available on alloc only

It leaks an executor-lifetime backing at ExecutorSizing::DEFAULT — the reason it is Executor<'static> and the reason it needs an allocator. A target without one calls create_executor_in with its own static, which is the same open with the storage supplied rather than leaked. (Today Context itself has an alloc floor — its locator and rmw are owned Strings — so the pair moves together; if that floor ever drops, this is the half that stays behind.)

ⓘ
let context = nros::Context::default_from_env()?;
let mut executor = context.create_executor()?;
let mut node = executor.create_node("talker")?;

The -r rules init_with_args / Context::new parsed are installed in the new executor as its fallback remap tier.

Source

pub fn create_executor_in<'b>( &self, backing: &'b mut [MaybeUninit<u64>], ) -> Result<Executor<'b>, InitError>

OURS — create_executor with the storage supplied by the caller instead of leaked.

The freestanding form. An RTOS or bare-metal entry owns a static mut [MaybeUninit<u64>; N] (or the array the nros::main! macro sizes for it) and hands it in; nothing is allocated, and the returned executor borrows the backing for 'b rather than living forever. rclrs has no counterpart — it allocates.

backing must hold at least ExecutorSizing::DEFAULT.u64_len() words. A shorter slice is InitError::BackingTooSmall naming both numbers, never undefined behaviour: this is the safe wrapper around the unsafe Executor::open_in, and the length check is what makes it safe. Size the array with ExecutorSizing::DEFAULT.u64_len() rather than a literal, since the default moves with NROS_EXECUTOR_MAX_CBS and its siblings.

ⓘ
static mut BACKING: [MaybeUninit<u64>; N] = [MaybeUninit::uninit(); N];
let context = nros::Context::default_from_env()?;
// SAFETY: single-threaded entry, taken once.
let mut executor = context.create_executor_in(unsafe { &mut *&raw mut BACKING })?;
let mut node = executor.create_node("talker")?;

Trait Implementations§

Source§

impl Clone for Context

Source§

fn clone(&self) -> Context

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Context

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

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> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. 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> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
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.