mecha10_core/
prelude.rs

1// Mecha10 Framework Prelude
2//
3// This module provides a comprehensive set of re-exports that covers
4// everything needed for typical node development. The goal is to enable
5// developers to write nodes with a single import:
6//
7// ```rust
8// use mecha10::prelude::*;
9// ```
10
11// ============================================================================
12// Core Traits and Types
13// ============================================================================
14
15// Core execution context
16pub use crate::context::{
17    Context, InfrastructureConfig, MinioConfig, MlflowConfig, PostgresConfig, Receiver, RedisConfig,
18};
19
20// Stream combinators
21pub use crate::stream::ReceiverExt;
22
23// Conditional publishing
24pub use crate::publish::ContextPublishExt;
25
26// Request/Response (RPC) pattern
27pub use crate::rpc::{Request, Response, RpcExt};
28
29// Streaming RPC for long-running operations
30pub use crate::rpc_streaming::{
31    StreamError, StreamMessage, StreamPayload, StreamReceiver, StreamSender, StreamingRpcExt,
32};
33
34// Service discovery
35pub use crate::discovery::{DiscoveryExt, NodeMetadata, NodeStatus};
36
37// Schema registry with versioning
38pub use crate::schema::{
39    CompatibilityCheck, CompatibilityMode, MessageSchema, MessageVersionInfo, SchemaEvolution, SchemaField,
40    SchemaRegistryExt, SchemaVersioningExt,
41};
42
43// Authorization
44pub use crate::auth::{AuthExt, Permission, Policy, Rule};
45
46// Secrets management
47pub use crate::secrets::{
48    EnvironmentBackend, RedisBackend, SecretBackend, SecretsConfig, SecretsManager, VaultBackend,
49};
50
51// Health monitoring
52pub use crate::health::{
53    HealthMonitor, HealthReport, HealthReporter, HealthReportingExt, NodeHealthInfo, SystemHealth,
54};
55
56// Behavior interrupt trigger for autonomous behavior control
57pub use crate::behavior_interrupt::{
58    BehaviorControl, BehaviorInterruptConfig, BehaviorInterruptTrigger, InterruptMode,
59};
60
61// Metrics collection
62pub use crate::metrics::{Counter, Gauge, Histogram, MetricsRegistry, NodeMetrics};
63
64// Rate limiting
65pub use crate::rate_limit::{MultiKeyRateLimiter, RateLimit, RateLimiter, RateLimiterManager};
66
67// Circuit breaker for fault tolerance
68pub use crate::circuit_breaker::{CircuitBreaker, CircuitBreakerConfig, CircuitState};
69
70// Dead letter queue for failed messages
71pub use crate::dead_letter::{DeadLetterConfig, DeadLetterQueue, FailedMessage};
72
73// JSON Schema validation for configuration files
74pub use crate::schema_validation::{
75    export_project_schema, get_node_config_schema, get_project_schema, load_and_validate_project,
76    validate_node_config_json, validate_project_config, validate_project_json,
77};
78
79// Dependency resolution for node ordering
80pub use crate::dependency::{create_graph, DependencyGraph, ShutdownPlan, StartupPlan};
81
82// Lifecycle event schemas for mode-based management
83pub use crate::lifecycle::{
84    get_timestamp_ms, topic_node_lifecycle, topic_node_status, ModeChanged, ModeError, ModeRequest,
85    NodeLifecycleAction, NodeLifecycleEvent, NodeLifecycleStatus, NodeStatusEvent, TOPIC_MODE_CHANGED,
86    TOPIC_MODE_ERROR, TOPIC_MODE_REQUEST,
87};
88
89// Topic registry for runtime introspection
90pub use crate::topic_registry::{TopicInfo, TopicRegistry, TopologyStats};
91
92// Topic utilities (categorization, formatting, metadata)
93pub use crate::topic_utils::{extract_category, format_elapsed_time, TopicMetadata};
94
95// Persistent state storage abstraction
96pub use crate::state::{
97    FilesystemStateManager, MemoryStateManager, StateManager, StateOptions, StateSnapshot, VersionedState,
98};
99
100// Graceful degradation and recovery policies
101pub use crate::recovery::{
102    BackoffStrategy, DegradationMode, RecoveryAction, RecoveryAttempt, RecoveryHistory, RecoveryManager,
103    RecoveryPolicy, RecoveryPolicyBuilder, RecoveryStats,
104};
105
106// Distributed tracing
107pub use crate::tracing_otel::{
108    JaegerExporter, SpanBuilder, SpanData, TraceContext, TraceExporter, TracedMessage, TracingConfig, TracingExt,
109    TracingHandle, ZipkinExporter,
110};
111
112// Performance profiling
113pub use crate::profiling::{
114    measure_latency, ExecutionStats, LatencyStats, MemoryStats, PerformanceMetrics, PerformanceReport, ProfilingExt,
115    ThroughputStats, TimerGuard,
116};
117
118// Service pattern for infrastructure components
119pub use crate::service::Service;
120pub use crate::service_manager::ServiceManager;
121
122// Node lifecycle management
123pub use crate::node::{run_node, HealthPriority, HealthReportingConfig, HealthStatusExt, Node, NodeImpl, RateConfig};
124
125// Configuration loading and validation
126pub use crate::config::{load_and_validate, load_config, load_config_from_env, substitute_env_vars, Validate};
127
128// Model configuration utilities for AI nodes
129pub use crate::model::{load_labels, load_model_config, CustomLabelsConfig, ModelConfig, PreprocessingConfig};
130
131// Convenience macros for reducing boilerplate
132pub use crate::run_node_simple;
133pub use crate::run_node_with_instance;
134
135// Message trait
136pub use crate::messages::Message;
137
138// All shared types (Image, LaserScan, Odometry, Twist, etc.)
139pub use crate::types::*;
140
141// ============================================================================
142// Error Handling
143// ============================================================================
144
145/// Result type with Mecha10 error
146pub use crate::error::{Mecha10Error, Result};
147
148// ============================================================================
149// Async Runtime
150// ============================================================================
151
152/// async_trait macro for async trait methods
153pub use async_trait::async_trait;
154
155/// Tokio re-exports
156pub use tokio::{
157    self, select,
158    time::{interval, sleep, timeout, Duration, Instant},
159};
160
161/// JoinHandle for background tasks
162pub use tokio::task::JoinHandle;
163
164// ============================================================================
165// Serialization
166// ============================================================================
167
168/// Serde re-exports
169pub use serde::{Deserialize, Serialize};
170pub use serde_json::{self, json, Value as JsonValue};
171
172// ============================================================================
173// Logging
174// ============================================================================
175
176/// Tracing macros for structured logging
177pub use tracing::{debug, error, info, instrument, trace, warn, Level};
178
179// ============================================================================
180// Derive Macros (when available)
181// ============================================================================
182
183/// Derive macro for Node trait
184///
185/// # Example
186/// ```rust
187/// use mecha10::prelude::*;
188///
189/// #[derive(Node)]
190/// #[subscribe("/input")]
191/// #[publish("/output")]
192/// struct MyNode {
193///     config: MyConfig,
194/// }
195/// ```
196#[cfg(feature = "macros")]
197pub use mecha10_macros::Node;
198
199/// Derive macro for Message trait
200///
201/// Automatically implements: Debug, Clone, Serialize, Deserialize, Message
202///
203/// # Example
204/// ```rust
205/// use mecha10::prelude::*;
206///
207/// #[derive(Message)]
208/// struct CustomMessage {
209///     pub value: f32,
210///     pub timestamp: u64,
211/// }
212/// ```
213// Note: Message trait is defined in messages::mod, no derive macro needed
214// #[cfg(feature = "macros")]
215// pub use mecha10_macros::Message as DeriveMessage;
216/// Derive macro for Config with validation
217///
218/// # Example
219/// ```rust
220/// use mecha10::prelude::*;
221///
222/// #[derive(Config)]
223/// struct MyConfig {
224///     #[validate(range = "0.0..=10.0")]
225///     max_speed: f32,
226/// }
227/// ```
228#[cfg(feature = "macros")]
229pub use mecha10_macros::Config;
230
231/// Derive macro for ConfigDefaults
232///
233/// Automatically generates default_* functions for config fields
234///
235/// # Example
236/// ```rust
237/// use mecha10::prelude::*;
238///
239/// #[derive(ConfigDefaults)]
240/// struct MyConfig {
241///     #[config(default = 10.0)]
242///     max_speed: f32,
243/// }
244/// ```
245#[cfg(feature = "macros")]
246pub use mecha10_macros::ConfigDefaults;
247
248// ============================================================================
249// Utility Functions (stubs for now)
250// ============================================================================
251
252/// Get current time in microseconds since UNIX epoch
253pub fn now_micros() -> u64 {
254    std::time::SystemTime::now()
255        .duration_since(std::time::UNIX_EPOCH)
256        .unwrap()
257        .as_micros() as u64
258}
259
260/// Create a periodic interval from a frequency in Hz
261///
262/// This is a convenience helper that converts frequency (Hz) to a tokio interval.
263/// Commonly used for periodic publishing in drivers and nodes.
264///
265/// # Arguments
266///
267/// * `hz` - Frequency in Hertz (cycles per second)
268///
269/// # Returns
270///
271/// A tokio::time::Interval that ticks at the specified frequency
272///
273/// # Example
274///
275/// ```rust
276/// use mecha10::prelude::*;
277///
278/// # async fn example() {
279/// // Instead of:
280/// // let interval_duration = Duration::from_secs_f32(1.0 / 30.0);
281/// // let mut interval = tokio::time::interval(interval_duration);
282///
283/// // Simply use:
284/// let mut interval = interval_at_hz(30.0);
285///
286/// loop {
287///     interval.tick().await;
288///     // Publish at 30 Hz
289/// }
290/// # }
291/// ```
292pub fn interval_at_hz(hz: f32) -> tokio::time::Interval {
293    let duration = std::time::Duration::from_secs_f32(1.0 / hz);
294    tokio::time::interval(duration)
295}
296
297/// Initialize logging with sensible defaults
298///
299/// This function is safe to call multiple times - it will silently succeed if
300/// a tracing subscriber is already set (e.g., when running bundled in the CLI).
301///
302/// The logging system will automatically include node context (node_id) in all
303/// log messages when using the Context's logging methods or the `in_node_context!` macro.
304pub fn init_logging() {
305    use tracing_subscriber::EnvFilter;
306
307    // Use try_init() which silently succeeds if a subscriber is already set.
308    // This allows nodes to be run both standalone (where they init logging)
309    // and bundled in the CLI (where CLI already initialized logging).
310    let _ = tracing_subscriber::fmt()
311        .with_env_filter(EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")))
312        .try_init();
313}
314
315/// Macro to execute code within a node's logging context
316///
317/// This macro creates a tracing span with the node_id field, ensuring all logs
318/// within the scope are automatically tagged with the node identifier.
319///
320/// # Example
321///
322/// ```rust
323/// use mecha10::prelude::*;
324///
325/// # async fn example(ctx: &Context) -> Result<()> {
326/// in_node_context!(ctx, {
327///     info!("Starting processing");  // Will show: node_id=my-node Starting processing
328///     debug!("Details here");         // Will show: node_id=my-node Details here
329/// });
330/// # Ok(())
331/// # }
332/// ```
333#[macro_export]
334macro_rules! in_node_context {
335    ($ctx:expr, $body:block) => {{
336        let _span = tracing::info_span!("node", node_id = $ctx.node_id()).entered();
337        $body
338    }};
339}
340
341/// Re-export the in_node_context macro
342pub use in_node_context;
343
344// ============================================================================
345// Additional Time & Timestamp Helpers
346// ============================================================================
347
348/// Get the current time in milliseconds since UNIX epoch
349///
350/// This is useful when microsecond precision is excessive (logs, metrics, etc.).
351///
352/// # Example
353///
354/// ```rust
355/// use mecha10::prelude::*;
356///
357/// let timestamp_ms = now_millis();
358/// println!("Current time: {} ms", timestamp_ms);
359/// ```
360pub fn now_millis() -> u64 {
361    std::time::SystemTime::now()
362        .duration_since(std::time::UNIX_EPOCH)
363        .expect("Time went backwards")
364        .as_millis() as u64
365}
366
367/// Calculate time elapsed in microseconds since a given timestamp
368///
369/// # Arguments
370///
371/// * `timestamp_micros` - A timestamp in microseconds (from `now_micros()`)
372///
373/// # Returns
374///
375/// Elapsed time in microseconds
376///
377/// # Example
378///
379/// ```rust
380/// use mecha10::prelude::*;
381///
382/// let start = now_micros();
383/// // ... do work ...
384/// let elapsed = elapsed_micros(start);
385/// println!("Operation took {} μs", elapsed);
386/// ```
387pub fn elapsed_micros(timestamp_micros: u64) -> u64 {
388    now_micros().saturating_sub(timestamp_micros)
389}
390
391/// Calculate time elapsed in milliseconds since a given timestamp
392///
393/// # Arguments
394///
395/// * `timestamp_millis` - A timestamp in milliseconds (from `now_millis()`)
396///
397/// # Returns
398///
399/// Elapsed time in milliseconds
400pub fn elapsed_millis(timestamp_millis: u64) -> u64 {
401    now_millis().saturating_sub(timestamp_millis)
402}
403
404/// Convert a microsecond timestamp to seconds (as f64)
405///
406/// Useful for displaying timestamps in human-readable format.
407///
408/// # Example
409///
410/// ```rust
411/// use mecha10::prelude::*;
412///
413/// let timestamp = now_micros();
414/// let seconds = timestamp_as_secs(timestamp);
415/// println!("Time: {:.6} seconds", seconds);
416/// ```
417pub fn timestamp_as_secs(timestamp_micros: u64) -> f64 {
418    timestamp_micros as f64 / 1_000_000.0
419}
420
421/// Create a Duration from a frequency in Hz
422///
423/// # Example
424///
425/// ```rust
426/// use mecha10::prelude::*;
427///
428/// let duration = duration_from_hz(30.0);  // 33.33ms for 30Hz
429/// ```
430pub fn duration_from_hz(hz: f32) -> Duration {
431    Duration::from_secs_f32(1.0 / hz)
432}
433
434// ============================================================================
435// Angle & Rotation Helpers
436// ============================================================================
437
438/// Normalize an angle in radians to the range [-π, π]
439///
440/// This is essential for angle calculations to avoid unwanted wraparound effects.
441///
442/// # Example
443///
444/// ```rust
445/// use mecha10::prelude::*;
446///
447/// let angle = normalize_angle(7.0);  // Returns ~0.717 (7.0 - 2π)
448/// let angle2 = normalize_angle(-4.0); // Returns ~2.283 (-4.0 + 2π)
449/// ```
450pub fn normalize_angle(angle: f32) -> f32 {
451    use std::f32::consts::PI;
452    let mut normalized = angle;
453    while normalized > PI {
454        normalized -= 2.0 * PI;
455    }
456    while normalized < -PI {
457        normalized += 2.0 * PI;
458    }
459    normalized
460}
461
462/// Normalize an angle in degrees to the range [-180, 180]
463///
464/// # Example
465///
466/// ```rust
467/// use mecha10::prelude::*;
468///
469/// let angle = normalize_angle_degrees(270.0);  // Returns -90.0
470/// ```
471pub fn normalize_angle_degrees(angle: f32) -> f32 {
472    let mut normalized = angle;
473    while normalized > 180.0 {
474        normalized -= 360.0;
475    }
476    while normalized < -180.0 {
477        normalized += 360.0;
478    }
479    normalized
480}
481
482/// Calculate the shortest angular difference between two angles in radians
483///
484/// Returns the angular distance in the range [-π, π].
485///
486/// # Example
487///
488/// ```rust
489/// use mecha10::prelude::*;
490///
491/// let diff = angle_difference(0.1, 6.2);  // Shortest path wrapping around
492/// ```
493pub fn angle_difference(from: f32, to: f32) -> f32 {
494    normalize_angle(to - from)
495}
496
497/// Convert degrees to radians
498///
499/// # Example
500///
501/// ```rust
502/// use mecha10::prelude::*;
503///
504/// let radians = degrees_to_radians(180.0);  // Returns π
505/// ```
506pub fn degrees_to_radians(degrees: f32) -> f32 {
507    degrees * std::f32::consts::PI / 180.0
508}
509
510/// Convert radians to degrees
511///
512/// # Example
513///
514/// ```rust
515/// use mecha10::prelude::*;
516///
517/// let degrees = radians_to_degrees(std::f32::consts::PI);  // Returns 180.0
518/// ```
519pub fn radians_to_degrees(radians: f32) -> f32 {
520    radians * 180.0 / std::f32::consts::PI
521}
522
523// ============================================================================
524// Math & Safety Helpers
525// ============================================================================
526
527/// Safely divide two numbers, returning a default value if divisor is zero
528///
529/// # Example
530///
531/// ```rust
532/// use mecha10::prelude::*;
533///
534/// let result = safe_divide(10.0, 2.0, 0.0);   // Returns 5.0
535/// let result = safe_divide(10.0, 0.0, 99.0);  // Returns 99.0 (default)
536/// ```
537pub fn safe_divide(numerator: f32, denominator: f32, default: f32) -> f32 {
538    if denominator.abs() < f32::EPSILON {
539        default
540    } else {
541        numerator / denominator
542    }
543}
544
545/// Clamp a value between a minimum and maximum
546///
547/// This is available in std but this wrapper makes it more discoverable.
548///
549/// # Example
550///
551/// ```rust
552/// use mecha10::prelude::*;
553///
554/// let value = clamp(15.0, 0.0, 10.0);  // Returns 10.0
555/// ```
556pub fn clamp<T: PartialOrd>(value: T, min: T, max: T) -> T {
557    if value < min {
558        min
559    } else if value > max {
560        max
561    } else {
562        value
563    }
564}
565
566/// Linear interpolation between two values
567///
568/// # Arguments
569///
570/// * `a` - Start value
571/// * `b` - End value
572/// * `t` - Interpolation factor [0.0, 1.0]
573///
574/// # Example
575///
576/// ```rust
577/// use mecha10::prelude::*;
578///
579/// let mid = lerp(0.0, 10.0, 0.5);  // Returns 5.0
580/// ```
581pub fn lerp(a: f32, b: f32, t: f32) -> f32 {
582    a + (b - a) * t
583}
584
585// ============================================================================
586// Common Standard Library Types
587// ============================================================================
588
589/// HashMap and HashSet from std
590pub use std::collections::{HashMap, HashSet};
591
592/// Sync primitives
593pub use std::sync::{Arc, Mutex};
594
595/// Path types
596pub use std::path::{Path, PathBuf};
597
598// ============================================================================
599// Convenience Type Aliases
600// ============================================================================
601
602/// Shared pointer to a value
603pub type Shared<T> = Arc<T>;
604
605/// Shared mutable state
606pub type SharedMut<T> = Arc<Mutex<T>>;