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_idis a public field, not adomain_id()method.- Executors are opened FROM it:
create_executorleaks an executor-lifetime backing (needsalloc), andcreate_executor_intakes caller storage.
Fields§
§domain_id: u32ROS 2 domain ID (ROS_DOMAIN_ID, default 0; baked NROS_DOMAIN_ID
freestanding).
locator: StringMiddleware 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: SessionModeSession mode (NROS_SESSION_MODE, default Client).
rmw: StringRMW 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: ContextSourceSource of this context — useful for diagnostics + tests.
Implementations§
Source§impl Context
impl Context
Sourcepub const fn domain_id(&self) -> usize
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.
Sourcepub fn config<'a>(&'a self, node_name: &'a str) -> ExecutorConfig<'a>
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.
Sourcepub fn default_from_env() -> Result<Context, InitError>
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.
Sourcepub fn from_env(options: InitOptions) -> Result<Context, InitError>
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.
Sourcepub fn new<I, S>(args: I, options: InitOptions) -> Result<Context, InitError>
pub fn new<I, S>(args: I, options: InitOptions) -> Result<Context, InitError>
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.
Sourcepub fn baked() -> Result<Context, InitError>
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; aboveDOMAIN_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.
Sourcepub fn with_locator_override(self, locator: Option<&str>) -> Self
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.
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.
Sourcepub fn create_executor(&self) -> Result<Executor<'static>, InitError>
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.
Sourcepub fn create_executor_in<'b>(
&self,
backing: &'b mut [MaybeUninit<u64>],
) -> Result<Executor<'b>, InitError>
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")?;