pub struct Stream { /* private fields */ }Expand description
A streaming session for outputting points to a DAC.
Use run() to stream with buffer-driven timing.
The callback is invoked when the buffer needs filling, providing automatic
backpressure handling and zero allocations in the hot path.
The stream owns pacing, backpressure, and the timebase (StreamInstant).
Implementations§
Source§impl Stream
impl Stream
Sourcepub fn config(&self) -> &StreamConfig
pub fn config(&self) -> &StreamConfig
Returns the stream configuration.
Sourcepub fn control(&self) -> StreamControl
pub fn control(&self) -> StreamControl
Returns a thread-safe control handle.
Sourcepub fn status(&self) -> Result<StreamStatus>
pub fn status(&self) -> Result<StreamStatus>
Returns the current stream status.
Sourcepub fn stop(&mut self) -> Result<()>
pub fn stop(&mut self) -> Result<()>
Stop the stream and terminate output.
Disarms the output (software blanking + hardware shutter) before stopping
the backend to prevent the “freeze on last bright point” hazard.
Use disarm() instead if you want to keep the stream alive but safe.
Sourcepub fn into_dac(self) -> (Dac, StreamStats)
pub fn into_dac(self) -> (Dac, StreamStats)
Consume the stream and recover the device for reuse.
This method disarms and stops the stream (software blanking + hardware shutter),
then returns the underlying Dac along with the final StreamStats.
The device can then be used to start a new stream with different configuration.
§Example
use laser_dac::StreamConfig;
// device: Dac, config: StreamConfig (from prior setup)
let (stream, info) = device.start_stream(config)?;
// ... stream for a while ...
let (device, stats) = stream.into_dac();
println!("Streamed {} points", stats.points_written);
// Restart with different config
let new_config = StreamConfig::new(60_000);
let (stream2, _) = device.start_stream(new_config)?;Sourcepub fn run<F, E>(self, producer: F, on_error: E) -> Result<RunExit>where
F: FnMut(&ChunkRequest, &mut [LaserPoint]) -> ChunkResult + Send + 'static,
E: FnMut(Error) + Send + 'static,
pub fn run<F, E>(self, producer: F, on_error: E) -> Result<RunExit>where
F: FnMut(&ChunkRequest, &mut [LaserPoint]) -> ChunkResult + Send + 'static,
E: FnMut(Error) + Send + 'static,
Run the stream with the zero-allocation callback API.
This method uses pure buffer-driven timing:
- Callback is invoked when
buffered < target_buffer - Points requested varies based on buffer headroom (
min_points,target_points) - Callback fills a library-owned buffer (zero allocations in hot path)
§Callback Contract
The callback receives a ChunkRequest describing buffer state and requirements,
and a mutable slice to fill with points. It returns:
ChunkResult::Filled(n): Wrotenpoints to the bufferChunkResult::Starved: No data available (underrun policy applies)ChunkResult::End: Stream should end gracefully
§Exit Conditions
RunExit::Stopped: Stop requested viaStreamControl::stop().RunExit::ProducerEnded: Callback returnedChunkResult::End.RunExit::Disconnected: Device disconnected.
§Example
use laser_dac::{ChunkRequest, ChunkResult, LaserPoint};
stream.run(
|req: &ChunkRequest, buffer: &mut [LaserPoint]| {
let n = req.target_points;
for i in 0..n {
let t = req.start.as_secs_f64(req.pps) + (i as f64 / req.pps as f64);
let angle = (t * std::f64::consts::TAU) as f32;
buffer[i] = LaserPoint::new(angle.cos(), angle.sin(), 65535, 0, 0, 65535);
}
ChunkResult::Filled(n)
},
|err| eprintln!("Error: {}", err),
)?;