7 ``pw_stream`` provides a foundational interface for streaming data from one part
8 of a system to another. In the simplest use cases, this is basically a memcpy
9 behind a reusable interface that can be passed around the system. On the other
10 hand, the flexibility of this interface means a ``pw_stream`` could terminate is
11 something more complex, like a UART stream or flash memory.
15 At the most basic level, ``pw_stream``'s interfaces provide very simple handles
16 to enabling streaming data from one location in a system to an endpoint.
22 void DumpSensorData(pw::stream::Writer& writer) {
26 size_t bytes_written = imu_sample.AsCsv(temp, sizeof(temp));
27 writer.Write(temp, bytes_written);
30 In this example, ``DumpSensorData()`` only cares that it has access to a
31 ``Writer`` that it can use to stream data to using ``Writer::Write()``. The
32 ``Writer`` itself can be backed by anything that can act as a data "sink."
37 This is the foundational stream ``Writer`` abstract class. Any class that wishes
38 to implement the ``Writer`` interface **must** provide a ``DoWrite()``
39 implementation. Note that ``Write()`` itself is **not** virtual, and should not
44 If any buffering occurs in a ``Writer`` and data must be flushed before it is
45 fully committed to the sink, a ``Writer`` implementation is resposible for any
46 ``Flush()`` capability.
50 This is the foundational stream ``Reader`` abstract class. Any class that wishes
51 to implement the ``Reader`` interface **must** provide a ``DoRead()``
52 implementation. Note that ``Read()`` itself is **not** virtual, and should not
55 pw::stream::MemoryWriter
56 ------------------------
57 The ``MemoryWriter`` class implements the ``Writer`` interface by backing the
58 data destination with an **externally-provided** memory buffer.
59 ``MemoryWriterBuffer`` extends ``MemoryWriter`` to internally provide a memory
62 pw::stream::MemoryReader
63 ------------------------
64 The ``MemoryReader`` class implements the ``Reader`` interface by backing the
65 data source with an **externally-provided** memory buffer.
67 pw::stream::NullWriter
68 ------------------------
69 The ``NullWriter`` class implements the ``Writer`` interface by dropping all
70 requested data writes, similar to ``/dev/null``.
77 ``pw_stream`` provides a standard way for classes to express that they have the
78 ability to write data. Writing to one sink versus another sink is a matter of
79 just passing a reference to the appropriate ``Writer``.
81 As an example, imagine dumping sensor data. If written against a random HAL
82 or one-off class, there's porting work required to write to a different sink
83 (imagine writing over UART vs dumping to flash memory). Building a "dumping"
84 implementation against the ``Writer`` interface prevents a dependency from
85 forming on an artisainal API that would require porting work.
87 Similarly, after building a ``Writer`` implementation for a Sink that data
88 could be dumped to, that same ``Writer`` can be reused for other contexts that
89 already write data to the ``pw::stream::Writer`` interface.
95 // Not reusable, depends on `Uart`.
96 void DumpSensorData(Uart& uart) {
100 size_t bytes_written = imu_sample.AsCsv(temp, sizeof(temp));
101 uart.Transmit(temp, bytes_written, /*timeout_ms=*/ 200);
108 // Reusable; no more Uart dependency!
109 void DumpSensorData(Writer& writer) {
110 static char temp[64];
111 ImuSample imu_sample;
112 imu.GetSample(&info);
113 size_t bytes_written = imu_sample.AsCsv(temp, sizeof(temp));
114 writer.Write(temp, bytes_written);
117 Reduce intermediate buffers
118 ---------------------------
119 Often functions that write larger blobs of data request a buffer is passed as
120 the destination that data should be written to. This *requires* a buffer is
121 allocated, even if the data only exists in that buffer for a very short period
122 of time before it's written somewhere else.
124 In situations where data read from somewhere will immediately be written
125 somewhere else, a ``Writer`` interface can cut out the middleman buffer.
131 // Requires an intermediate buffer to write the data as CSV.
132 void DumpSensorData(Uart* uart) {
134 ImuSample imu_sample;
135 imu.GetSample(&info);
136 size_t bytes_written = imu_sample.AsCsv(temp, sizeof(temp));
137 uart.Transmit(temp, bytes_written, /*timeout_ms=*/ 200);
144 // Both DumpSensorData() and RawSample::AsCsv() use a Writer, eliminating the
145 // need for an intermediate buffer.
146 void DumpSensorData(Writer* writer) {
147 RawSample imu_sample;
148 imu.GetSample(&info);
149 imu_sample.AsCsv(writer);
152 Prevent buffer overflow
153 -----------------------
154 When copying data from one buffer to another, there must be checks to ensure the
155 copy does not overflow the destination buffer. As this sort of logic is
156 duplicated throughout a codebase, there's more opportunities for bound-checking
157 bugs to sneak in. ``Writers`` manage this logic internally rather than pushing
158 the bounds checking to the code that is moving or writing the data.
160 Similarly, since only the ``Writer`` has access to any underlying buffers, it's
161 harder for functions that share a ``Writer`` to accidentally clobber data
162 written by others using the same buffer.
168 Status BuildPacket(Id dest, span<const std::byte> payload,
169 span<std::byte> dest) {
171 if (dest.size_bytes() + payload.size_bytes() < sizeof(Header)) {
172 return Status::RESOURCE_EXHAUSTED;
175 header.src = DeviceId();
176 header.payload_size = payload.size_bytes();
178 memcpy(dest.data(), &header, sizeof(header));
179 // Forgetting this line would clobber buffer contents. Also, using
180 // a temporary span instead could leave `dest` to be misused elsewhere in
182 dest = dest.subspan(sizeof(header));
183 memcpy(dest.data(), payload.data(), payload.size_bytes());
190 Status BuildPacket(Id dest, span<const std::byte> payload, Writer& writer) {
193 header.src = DeviceId();
194 header.payload_size = payload.size_bytes();
196 writer.Write(header);
197 return writer.Write(payload);
202 pw_stream provides a virtual interface. This inherently has more overhead than
203 a regular function call. In extremely performance-sensitive contexts, a virtual
204 interface might not provide enough utility to justify the performance cost.
208 * ``pw_assert`` module
209 * ``pw_preprocessor`` module
210 * ``pw_status`` module