1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
//! Stream combinators for declarative message processing
//!
//! This module provides a fluent API for transforming and filtering message streams.
//!
//! # Examples
//!
//! ## Filtering
//!
//! ```rust
//! use mecha10::prelude::*;
//! use mecha10::topics::perception;
//!
//! # async fn example(ctx: &Context) -> Result<()> {
//! // Only process high-confidence detections
//! let mut detections = ctx.subscribe(perception::DETECTIONS)
//! .filter(|d| d.iter().any(|det| det.confidence > 0.8))
//! .await?;
//!
//! while let Some(dets) = detections.recv().await {
//! // All detections have confidence > 0.8
//! }
//! # Ok(())
//! # }
//! ```
//!
//! ## Throttling
//!
//! ```rust
//! use mecha10::prelude::*;
//! use mecha10::topics::sensor;
//!
//! # async fn example(ctx: &Context) -> Result<()> {
//! // Limit to 10 Hz
//! let mut images = ctx.subscribe(sensor::CAMERA_RGB)
//! .throttle(Duration::from_millis(100))
//! .await?;
//! # Ok(())
//! # }
//! ```
//!
//! ## Latest Only
//!
//! ```rust
//! use mecha10::prelude::*;
//! use mecha10::topics::sensor;
//!
//! # async fn example(ctx: &Context) -> Result<()> {
//! // Always get the latest, drop old messages
//! let mut odom = ctx.subscribe(sensor::ODOMETRY)
//! .latest()
//! .await?;
//! # Ok(())
//! # }
//! ```
//!
//! ## Zipping Streams
//!
//! ```rust
//! use mecha10::prelude::*;
//! use mecha10::topics::sensor;
//!
//! # async fn example(ctx: &Context) -> Result<()> {
//! // Combine camera images with LiDAR scans
//! let mut images = ctx.subscribe(sensor::CAMERA_RGB).await?;
//! let mut scans = ctx.subscribe(sensor::LIDAR_SCAN).await?;
//!
//! let mut zipped = images.zip(scans);
//!
//! while let Some((image, scan)) = zipped.recv().await {
//! // Process synchronized sensor data
//! println!("Image: {}x{}, LiDAR: {} points",
//! image.width, image.height, scan.ranges.len());
//! }
//! # Ok(())
//! # }
//! ```
//!
//! ## Windowing
//!
//! ```rust
//! use mecha10::prelude::*;
//! use mecha10::topics::perception;
//!
//! # async fn example(ctx: &Context) -> Result<()> {
//! // Collect detections over 1-second windows for rate analysis
//! let mut windowed = ctx.subscribe(perception::DETECTIONS)
//! .window(Duration::from_secs(1));
//!
//! while let Some(detections) = windowed.recv().await {
//! let rate = detections.len() as f32; // detections per second
//! println!("Detection rate: {} Hz", rate);
//!
//! // Calculate average confidence over the window
//! let avg_conf = detections.iter()
//! .map(|d| d.confidence)
//! .sum::<f32>() / detections.len() as f32;
//! println!("Average confidence: {:.2}", avg_conf);
//! }
//! # Ok(())
//! # }
//! ```
//!
//! This module is organized into:
//! - `builder`: `StreamBuilder`'s data and pipeline configuration (`filter`, `map`, `throttle`, `debounce`, `latest`)
//! - `pipeline`: `StreamBuilder::build`, running the configured filter/map/throttle/debounce pipeline
//! - `zip`: `StreamBuilder::zip`, pairing two streams
//! - `window`: `StreamBuilder::window`, time-windowed batching
//! - `batch`: `BatchBuilder`, size/timeout-based batching
//! - `receiver_ext`: `ReceiverExt`, the fluent entry point on `Receiver<T>`
pub use BatchBuilder;
pub use StreamBuilder;
pub use ReceiverExt;