1 // Copyright 2020 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 #pragma once
15 
16 #include <array>
17 #include <cstddef>
18 #include <span>
19 
20 #include "pw_assert/light.h"
21 #include "pw_bytes/span.h"
22 #include "pw_result/result.h"
23 #include "pw_status/status.h"
24 #include "pw_status/status_with_size.h"
25 
26 namespace pw::stream {
27 
28 // General-purpose writer interface.
29 class Writer {
30  public:
31   // There are no requirements around if or how a `Writer` should call Flush()
32   // at the time of object destruction.
33   virtual ~Writer() = default;
34 
35   // Write data to this stream Writer. Data is
36   // not guaranteed to be fully written out to final resting place on Write
37   // return.
38   //
39   // If the writer is unable to fully accept the input data size it will abort
40   // the write and return RESOURCE_EXHAUSTED.
41   //
42   // If the writer has been exhausted and is and can no longer accept additional
43   // bytes it will return OUT_OF_RANGE. This is similar to EndOfFile. Write will
44   // only return OUT_OF_RANGE if ConservativeWriteLimit() is and will remain
45   // zero. A Write operation that is successful and also exhausts the writer
46   // returns OK, with all following calls returning OUT_OF_RANGE. When
47   // ConservativeWriteLimit() is greater than zero, a Write that is a number of
48   // bytes beyond what will exhaust the Write will abort and return
49   // RESOURCE_EXHAUSTED rather than OUT_OF_RANGE because the writer is still
50   // able to write bytes.
51   //
52   // Derived classes should NOT try to override the public Write methods.
53   // Instead, provide an implementation by overriding DoWrite().
54   //
55   // Returns:
56   //
57   // OK - successful write/enqueue of data.
58   // FAILED_PRECONDITION - writer unable/not in state to accept data.
59   // RESOURCE_EXHAUSTED - unable to write all of requested data at this time. No
60   //     data written.
61   // OUT_OF_RANGE - Writer has been exhausted, similar to EOF. No data written,
62   //     no more will be written.
Write(ConstByteSpan data)63   Status Write(ConstByteSpan data) {
64     PW_DASSERT(data.empty() || data.data() != nullptr);
65     return DoWrite(data);
66   }
Write(const void * data,size_t size_bytes)67   Status Write(const void* data, size_t size_bytes) {
68     return Write(std::span(static_cast<const std::byte*>(data), size_bytes));
69   }
Write(const std::byte b)70   Status Write(const std::byte b) { return Write(&b, 1); }
71 
72   // Probable (not guaranteed) minimum number of bytes at this time that can be
73   // written. This number is advisory and not guaranteed to write without a
74   // RESOURCE_EXHAUSTED or OUT_OF_RANGE. As Writer processes/handles enqueued of
75   // other contexts write data this number can go up or down for some Writers.
76   // Returns zero if, in the current state, Write() would not return
77   // OkStatus().
78   //
79   // Returns std::numeric_limits<size_t>::max() if the implementation has no
80   // limits on write sizes.
ConservativeWriteLimit()81   virtual size_t ConservativeWriteLimit() const {
82     return std::numeric_limits<size_t>::max();
83   }
84 
85  private:
86   virtual Status DoWrite(ConstByteSpan data) = 0;
87 };
88 
89 // General-purpose reader interface
90 class Reader {
91  public:
92   virtual ~Reader() = default;
93 
94   // Read data from this stream Reader. If any number of bytes are read return
95   // OK with a span of the actual byte read.
96   //
97   // If the reader has been exhausted and is and can no longer read additional
98   // bytes it will return OUT_OF_RANGE. This is similar to EndOfFile. Read will
99   // only return OUT_OF_RANGE if ConservativeReadLimit() is and will remain
100   // zero. A Read operation that is successful and also exhausts the reader
101   // returns OK, with all following calls returning OUT_OF_RANGE.
102   //
103   // Derived classes should NOT try to override these public read methods.
104   // Instead, provide an implementation by overriding DoRead().
105   //
106   // Returns:
107   //
108   // OK with span of bytes read - success, between 1 and dest.size_bytes() were
109   //     read.
110   // FAILED_PRECONDITION - Reader unable/not in state to read data.
111   // RESOURCE_EXHAUSTED - unable to read any bytes at this time. No bytes read.
112   //     Try again once bytes become available.
113   // OUT_OF_RANGE - Reader has been exhausted, similar to EOF. No bytes read, no
114   //     more will be read.
Read(ByteSpan dest)115   Result<ByteSpan> Read(ByteSpan dest) {
116     PW_DASSERT(dest.empty() || dest.data() != nullptr);
117     StatusWithSize result = DoRead(dest);
118 
119     if (result.ok()) {
120       return dest.first(result.size());
121     } else {
122       return result.status();
123     }
124   }
Read(void * dest,size_t size_bytes)125   Result<ByteSpan> Read(void* dest, size_t size_bytes) {
126     return Read(std::span(static_cast<std::byte*>(dest), size_bytes));
127   }
128 
129   // Probable (not guaranteed) minimum number of bytes at this time that can be
130   // read. This number is advisory and not guaranteed to read full number of
131   // requested bytes or without a RESOURCE_EXHAUSTED or OUT_OF_RANGE. As Reader
132   // processes/handles/receives enqueued data or other contexts read data this
133   // number can go up or down for some Readers.
134   // Returns zero if, in the current state, Read() would not return
135   // OkStatus().
136   //
137   // Returns std::numeric_limits<size_t>::max() if the implementation imposes no
138   // limits on read sizes.
ConservativeReadLimit()139   virtual size_t ConservativeReadLimit() const {
140     return std::numeric_limits<size_t>::max();
141   }
142 
143  private:
144   virtual StatusWithSize DoRead(ByteSpan dest) = 0;
145 };
146 
147 }  // namespace pw::stream
148