Skip to main content

nros_node/
lib.rs

1//! Node abstraction for nros
2//!
3//! This crate provides the high-level Node API for creating ROS 2 compatible
4//! publishers and subscribers on embedded systems.
5//!
6//! # Executor-Based API
7//!
8//! The executor-based API provides a unified interface that works on both
9//! std (desktop) and no_std (embedded) targets.
10//!
11//! ## Desktop Example
12//!
13//! ```ignore
14//! use nros::prelude::*;
15//! use std_msgs::msg::Int32;
16//!
17//! let config = ExecutorConfig::from_env().node_name("my_node");
18//! let mut executor: Executor = Executor::open(&config)?;
19//!
20//! // Register subscription callback
21//! let node = executor.node_builder("my_node").build()?;
22//! executor.node_mut(node).create_subscription::<Int32, _>("/topic", |msg: &Int32| {
23//!     println!("Received: {}", msg.data);
24//! })?;
25//!
26//! // Spin (processes callbacks)
27//! executor.spin_blocking(SpinOptions::default());
28//! ```
29//!
30//! ## Embedded Example
31//!
32//! ```ignore
33//! use nros::prelude::*;
34//! use std_msgs::msg::Int32;
35//!
36//! let config = ExecutorConfig { locator: "tcp/192.168.1.1:7447", ..Default::default() };
37//! let mut executor: Executor = Executor::open(&config)?;
38//!
39//! // Register subscription callback
40//! let node = executor.node_builder("my_node").build()?;
41//! executor.node_mut(node).create_subscription::<Int32, _>("/cmd", |msg: &Int32| {
42//!     // process message...
43//! })?;
44//!
45//! // In your main loop:
46//! loop {
47//!     executor.spin_once(core::time::Duration::from_millis(10));
48//!     // platform delay...
49//! }
50//! ```
51//!
52//! # Features
53//!
54//! - `std` - Enable standard library support (spin_blocking)
55//! - `alloc` - Enable heap allocation (parameter service boxed replies)
56
57#![no_std]
58
59// Phase 248 (C2) — `nros-rmw-cyclonedds[-sys]` deps removed (issue #60,
60// Tier 1). Per-type descriptor registration is now the generic
61// `nros_rmw::register_type_descriptor` seam (see `cyclonedds_register`);
62// the Cyclone backend installs its registrar from its own crate. The
63// `__cyclonedds-link` marker feature (no dep edge) still emits
64// `cfg(rmw_cyclonedds_present)` to compile the schema-passing body +
65// `M: Message` bound for builds where a descriptor-needing backend is
66// linked by the umbrella.
67
68#[cfg(feature = "std")]
69extern crate std;
70
71#[cfg(feature = "alloc")]
72extern crate alloc;
73
74pub mod c_waker;
75pub mod config;
76/// Phase 212.K.7.6.b — runtime cyclonedds type-descriptor registry hook.
77pub mod cyclonedds_register;
78pub mod executor;
79pub mod lifecycle;
80pub mod limits;
81mod node;
82mod publisher;
83#[cfg(any(has_rmw, test))]
84pub mod session;
85mod subscriber;
86pub mod timer;
87
88// MockSession only matters when neither a real RMW backend feature
89// nor lifecycle-services is enabled — the same gate as
90// `session::ConcreteSession = MockSession` and the executor tests in
91// `executor/mod.rs:42`. Compiling mock.rs unconditionally under
92// `cfg(test)` produced "never constructed / never used" warnings on
93// `cargo build --tests` when feature-unification activated a real
94// RMW backend (e.g. workspace builds with `rmw-uorb` on).
95#[cfg(all(test, not(feature = "rmw-cffi")))]
96pub(crate) mod mock;
97
98#[cfg(feature = "param-services")]
99pub mod parameter_services;
100
101// Re-export parameter types when param-services is enabled
102#[cfg(feature = "param-services")]
103pub use nros_params::{
104    ParameterDescriptor, ParameterServer, ParameterType, ParameterValue, SetParameterResult,
105};
106
107#[cfg(feature = "lifecycle-services")]
108pub mod lifecycle_services;
109
110// Export standalone node (without transport)
111pub use node::{Node as StandaloneNode, NodeConfig, NodeError as StandaloneNodeError};
112
113pub use publisher::PublisherHandle;
114pub use subscriber::SubscriberHandle;
115
116// Re-export transport types for convenience
117pub use nros_rmw::{
118    ActionInfo, QosDurabilityPolicy, QosHistoryPolicy, QosLivelinessPolicy, QosPolicyMask,
119    QosReliabilityPolicy, QosSettings, ServiceInfo, TopicInfo, TransportConfig, TransportError,
120};
121
122// Re-export RMW protocol traits so thin wrappers (nros-c, nros-cpp) can
123// pull them through nros-node instead of going around it. Phase 91.B.
124pub use nros_rmw::{Publisher, ServiceClientTrait, ServiceServerTrait, Session, Subscriber};
125
126// Re-export action protocol types from nros-core. Same motivation as the
127// RMW trait re-exports above — keeps thin wrappers off the
128// nros-core::* path. Phase 91.B5.
129pub use nros_core::{CancelResponse, GoalId, GoalResponse, GoalStatus};
130
131// Re-export lifecycle protocol types. Phase 91.B2.
132pub use nros_core::lifecycle::{LifecycleState, LifecycleTransition, TransitionResult};
133
134// Re-export CDR ser/de types so the C-side serialization helpers in
135// nros-c/src/cdr.rs don't have to reach past nros-node either. These
136// are themselves re-exports from nros-serdes via nros-core; collecting
137// them here keeps the import boundary uniform. Phase 91.B6.
138pub use nros_core::{CdrReader, CdrWriter, DeserError, SerError};
139
140// Re-export safety types when feature is enabled
141#[cfg(feature = "safety-e2e")]
142pub use nros_rmw::{IntegrityStatus, SafetyValidator};
143
144// Re-export publisher/subscriber options (topic + QoS; backend-agnostic).
145pub use node::{PublisherOptions, SubscriberOptions};
146
147// Re-export session mode (used by ExecutorConfig)
148pub use nros_rmw::SessionMode;
149
150// Re-export timer types
151pub use timer::{TimerCallbackFn, TimerDuration, TimerHandle, TimerMode, TimerState};
152
153// Re-export lifecycle types
154pub use lifecycle::{LifecycleCallbackFn, LifecycleError, LifecyclePollingNode};
155
156// Re-export types that don't depend on RMW (always available)
157pub use executor::{
158    ExecutorConfig, ExecutorSemantics, GuardConditionHandle, HandleId, HandleSet, InvocationMode,
159    NodeError, RawAcceptedCallback, RawCancelCallback, RawGoalCallback, RawResponseCallback,
160    RawServiceCallback, RawSubscriptionCallback, ReadinessSnapshot, SpinOnceResult, SpinOptions,
161    SpinPeriodPollingResult, Trigger,
162};
163
164// Re-export RMW-dependent executor types
165#[cfg(any(has_rmw, test))]
166pub use executor::{
167    ActionClient, ActionClientCore, ActionServer, ActionServerCore, ActionServerHandle,
168    ActionServerRawHandle, ActiveGoal, CompletedGoal, EmbeddedPublisher, EmbeddedRawPublisher,
169    EmbeddedServiceClient, EmbeddedServiceServer, Executor, FeedbackStream, GoalFeedbackStream,
170    LoanError, NodeHandle, Promise, PublishLoan, RawActionClientSpec, RawActionServerSpec,
171    RawActiveGoal, RawServiceClient, RawServiceServer, RawSubscription, RecvView, SessionHandle,
172    Subscription,
173};
174
175// Phase 173.5 — bridge multi-session spec (consumed by the generated
176// orchestration package's `Executor::open_multi`). Gated to match
177// `executor::SessionSpec` (needs the cffi vtable surface).
178#[cfg(all(any(has_rmw, test), feature = "rmw-cffi"))]
179pub use executor::SessionSpec;
180
181#[cfg(all(feature = "std", any(has_rmw, test)))]
182pub use executor::SpinPeriodResult;