1 // Copyright 2025 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 15 #pragma once 16 17 #include "pw_bytes/span.h" 18 #include "pw_multibuf/allocator.h" 19 #include "pw_multibuf/multibuf.h" 20 #include "pw_result/result.h" 21 #include "pw_span/cast.h" 22 #include "pw_span/span.h" 23 24 namespace pw::bluetooth::proxy { 25 26 /// Wraps a fixed-size contiguous MultiBuf and allows for easily writing 27 /// sequential data into it. 28 /// 29 /// * A MultiBufWriter is created using Create(). 30 /// * Data can be written with Write() until IsComplete() returns true. 31 /// * The data can be viewed with U8Span() or TakeMultiBuf(). 32 class MultiBufWriter { 33 public: 34 /// Creates a MultiBufWriter wrapping a fixed-size, contiguous MultiBuf. 35 static pw::Result<MultiBufWriter> Create( 36 multibuf::MultiBufAllocator& multibuf_allocator, size_t size); 37 38 // MultiBufWriter is movable but not copyable. 39 MultiBufWriter(const MultiBufWriter&) = delete; 40 MultiBufWriter& operator=(const MultiBufWriter&) = delete; 41 MultiBufWriter(MultiBufWriter&&) = default; 42 MultiBufWriter& operator=(MultiBufWriter&&) = default; 43 44 /// Gets a span of the previously-written data. 45 /// 46 /// After TakeMultiBuf(), this returns an empty span. U8Span()47 pw::span<uint8_t> U8Span() { 48 // ContiguousSpan() cannot fail because Create() uses AllocateContiguous(). 49 return pw::span_cast<uint8_t>(*buf_.ContiguousSpan()).first(write_offset_); 50 } 51 52 /// Returns true when the MultiBuf is full; i.e., when the total number of 53 /// bytes written equals the size passed to Create(). Always returns true 54 /// after TakeMultiBuf() is called. IsComplete()55 bool IsComplete() const { return remain() == 0; } 56 57 /// Consumes the underlying MultiBuf. 58 /// 59 /// After this method is called, this object is reset to an empty state: 60 /// No data can be written, and all data accesors will return an empty 61 /// result. IsComplete() will return true. TakeMultiBuf()62 multibuf::MultiBuf&& TakeMultiBuf() { 63 write_offset_ = 0; 64 65 // A moved-from MultiBuf is equivalent to a default, empty MultiBuf. 66 return std::move(buf_); 67 } 68 69 /// Writes data into the MultiBuf at the next unwritten location. 70 Status Write(pw::ConstByteSpan data); 71 Write(pw::span<const uint8_t> data)72 Status Write(pw::span<const uint8_t> data) { 73 return Write(pw::as_bytes(data)); 74 } 75 76 private: MultiBufWriter(multibuf::MultiBuf && buf)77 MultiBufWriter(multibuf::MultiBuf&& buf) : buf_(std::move(buf)) {} 78 79 /// Returns the number of bytes remaining to be written before IsComplete() 80 /// returns true. remain()81 size_t remain() const { return buf_.size() - write_offset_; } 82 83 multibuf::MultiBuf buf_; 84 size_t write_offset_ = 0; 85 }; 86 87 } // namespace pw::bluetooth::proxy 88