Sane C++ Libraries
C++ Platform Abstraction Libraries
Loading...
Searching...
No Matches
AsyncStreams.h
1// Copyright (c) Stefano Cristiano
2// SPDX-License-Identifier: MIT
3#pragma once
4
5#include "../Common/CompilerMacrosExport.h"
6#include "../Common/PlatformMacrosInstructionSet.h"
7#ifndef SC_EXPORT_LIBRARY_ASYNC_STREAMS
8#define SC_EXPORT_LIBRARY_ASYNC_STREAMS 0
9#endif
10#define SC_ASYNC_STREAMS_EXPORT SC_COMPILER_LIBRARY_EXPORT(SC_EXPORT_LIBRARY_ASYNC_STREAMS)
11
12#include "../Common/AlignedStorage.h"
13#include "../Common/Assert.h"
14#include "../Common/Function.h"
15#include "../Common/IGrowableBufferSpan.h"
16#include "../Common/PlatformMacrosInstructionSet.h"
17#include "../Common/Result.h"
18#include "../Common/Span.h"
19#include "AsyncStreamsError.h"
20#include "Internal/CircularQueue.h"
21#include "Internal/Event.h"
22
52
55namespace SC
56{
57SC_DECLARE_ASSERT_PROVIDER(AsyncStreamsAssert, SC_ASYNC_STREAMS_EXPORT);
58
59#define SC_ASYNC_STREAMS_ASSERT_RELEASE(e) SC_ASSERT_PROVIDER_RELEASE(SC::AsyncStreamsAssert, e)
60#define SC_ASYNC_STREAMS_ASSERT_DEBUG(e) SC_ASSERT_PROVIDER_DEBUG(SC::AsyncStreamsAssert, e)
61#define SC_ASYNC_STREAMS_TRUST_RESULT(expression) SC_ASYNC_STREAMS_ASSERT_RELEASE(expression)
62
64struct SC_ASYNC_STREAMS_EXPORT AsyncBufferView
65{
66 struct SC_ASYNC_STREAMS_EXPORT ID
67 {
68 using NumericType = int32_t;
69
70 static constexpr NumericType InvalidValue = -1;
71
72 NumericType identifier;
73
74 constexpr ID() : identifier(InvalidValue) {}
75 explicit constexpr ID(int32_t value) : identifier(value) {}
76
77 [[nodiscard]] constexpr bool isValid() const { return identifier != InvalidValue; }
78 [[nodiscard]] constexpr bool operator==(ID other) const { return identifier == other.identifier; }
79 };
80 enum class Type : uint8_t
81 {
82 Empty,
83 Writable,
84 ReadOnly,
85 Growable,
86 Child,
87 };
88
89 AsyncBufferView() : writableData(), offset(0), length(0), refs(0), type(Type::Empty), reUse(false) {}
90 AsyncBufferView(Span<char> data) : writableData(data)
91 {
92 type = Type::Writable;
93 offset = 0;
94 length = data.sizeInBytes();
95 parentID = ID();
96 }
97 AsyncBufferView(Span<const char> data) : readonlyData(data)
98 {
99 type = Type::ReadOnly;
100 offset = 0;
101 length = data.sizeInBytes();
102 parentID = ID();
103 }
104
106 void setReusable(bool reusable) { reUse = reusable; }
107
111 template <typename T>
112 AsyncBufferView(T&& t) // universal reference, it can capture both lvalue and rvalue
113 {
114 type = Type::Growable;
115 offset = 0;
116 length = 0;
117 parentID = ID();
118 // Here we're type-erasing T in our own inline storage provided by a slightly oversized Function<>
119 // that it will be able to construct (and destruct) the right GrowableBuffer<T> from just a piece of storage
120 // and return a pointer to the corresponding IGrowableBuffer* interface
121 getGrowableBuffer = [t = forward<T>(t)](GrowableStorage& storage, bool construct) mutable -> IGrowableBuffer*
122 {
123 using Type = typename TypeTraits::RemoveReference<T>::type;
124 if (construct)
125 {
126 placementNew(storage.reinterpret_as<GrowableBuffer<Type>>(), t);
127 return &storage.reinterpret_as<GrowableBuffer<Type>>();
128 }
129 else
130 {
131 dtor(storage.reinterpret_as<GrowableBuffer<Type>>());
132 return nullptr;
133 }
134 };
135 }
136
137 template <int N>
138 AsyncBufferView(const char (&literal)[N])
139 {
140 readonlyData = {literal, N - 1};
141 type = Type::ReadOnly;
142 offset = 0;
143 length = N - 1;
144 }
145
146 Type getType() const { return type; }
147
148 private:
149#if SC_PLATFORM_64_BIT
150 static constexpr int TypeErasedCaptureSize = sizeof(void*) * 3; // This is enough to hold String / Buffer by copy
151#else
152 static constexpr int TypeErasedCaptureSize = sizeof(void*) * 6; // This is enough to hold String / Buffer by copy
153#endif
154 static constexpr int TypeErasedGrowableSize = sizeof(void*) * 6;
155
156 using GrowableStorage = AlignedStorage<TypeErasedGrowableSize>;
157 Function<IGrowableBuffer*(GrowableStorage&, bool), TypeErasedCaptureSize> getGrowableBuffer;
158
159 union
160 {
161 Span<char> writableData;
162 Span<const char> readonlyData;
163 };
164 AsyncBufferView::ID parentID;
165
166 friend struct AsyncBuffersPool;
167
168 size_t offset = 0;
169 size_t length = 0;
170 int32_t refs = 0; // Counts AsyncReadable (single) or AsyncWritable (multiple) using it
171 Type type = Type::Empty; // If it's Empty, Writable, ReadOnly, Growable or Child
172 bool reUse = false; // If it can be re-used after refs == 0
173};
174
177struct SC_ASYNC_STREAMS_EXPORT AsyncBuffersPool
178{
181
185
187 Result getReadableData(AsyncBufferView::ID bufferID, Span<const char>& data);
188
190 Result getWritableData(AsyncBufferView::ID bufferID, Span<char>& data);
191
194
196 Result requestNewBuffer(size_t minimumSizeInBytes, AsyncBufferView::ID& bufferID, Span<char>& data);
197
199 void setNewBufferSize(AsyncBufferView::ID bufferID, size_t newSizeInBytes);
200
202 Result pushBuffer(AsyncBufferView&& buffer, AsyncBufferView::ID& bufferID);
203
205 static Result sliceInEqualParts(Span<AsyncBufferView> buffers, Span<char> memory, size_t numSlices);
206
208 void setBuffers(Span<AsyncBufferView> newBuffers) { buffers = newBuffers; }
209
211 [[nodiscard]] size_t getNumBuffers() const { return buffers.sizeInElements(); }
212
214 Result createChildView(AsyncBufferView::ID parentBufferID, size_t offset, size_t length,
215 AsyncBufferView::ID& outChildBufferID);
216
217 private:
219 Span<AsyncBufferView> buffers;
220};
221
228struct SC_ASYNC_STREAMS_EXPORT AsyncReadableStream
229{
232
233 struct Request
234 {
235 AsyncBufferView::ID bufferID;
236 };
237
238 static constexpr int MaxListeners = 8;
239
240 Event<MaxListeners, Result> eventError;
241 Event<MaxListeners, AsyncBufferView::ID> eventData;
242 Event<MaxListeners> eventEnd;
243 Event<MaxListeners> eventClose;
244
248 Result init(AsyncBuffersPool& buffersPool);
249
251 Result start();
252
254 void pause();
255
258
261 void destroy();
262
264 [[nodiscard]] bool isEnded() const { return state == State::Ended; }
265
267 [[nodiscard]] bool hasQueuedData() const { return not readQueue.isEmpty(); }
268
270 [[nodiscard]] bool hasBeenDestroyed() const { return destroyed; }
271
273 [[nodiscard]] bool canStart() const { return state == State::CanRead; }
274
277
279 constexpr void setReadQueue(Span<Request> requests) { readQueue = requests; }
280
282 [[nodiscard]] size_t getReadQueueSize() const { return readQueue.size(); }
283
286 [[nodiscard]] bool push(AsyncBufferView::ID bufferID, size_t newSize);
287
289 Result unshift(AsyncBufferView::ID bufferID);
290
292 void pushEnd();
293
296 void reactivate(bool doReactivate);
297
299 void emitError(Result error);
300
302 [[nodiscard]] bool getBufferOrPause(size_t minumumSizeInBytes, AsyncBufferView::ID& bufferID, Span<char>& data);
303
305 void setAutoDestroy(bool value) { autoDestroy = value; }
306
308 [[nodiscard]] bool getAutoDestroy() const { return autoDestroy; }
309
310 protected:
311 virtual ~AsyncReadableStream();
312
314 virtual Result asyncRead() = 0;
315
317 virtual Result asyncResumeReading();
318
321 virtual Result asyncDestroyReadable();
322
325
326 private:
327 void maybeDestroyEndedReadable();
328 void emitOnData();
329 void executeRead();
330
331 enum class State : uint8_t
332 {
333 Stopped, // Stream must be inited
334 CanRead, // Stream is ready to issue a read ( AsyncReadableStream::start / AsyncReadableStream::resume)
335 Reading, // A read is being issued (may be sync or async)
336 SyncPushing, // One or multiple AsyncReadableStream::push have been received (sync)
337 SyncReadMore, // SyncPushing + AsyncReadableStream::reactivate(true)
338 AsyncReading, // An async read is in flight
339 AsyncPushing, // AsyncReading + AsyncReadableStream::push
340 Pausing, // Pause requested while read in flight
341 Paused, // Actually paused with no read in flight
342 Ended, // Emitted all data, no more data will be emitted
343 Destroying, // Destroy has been requested and it's in progress
344 Errored, // Error occurred
345 };
346 State state = State::Stopped;
347
348 bool destroyed = false;
349 bool autoDestroy = true;
350
351 AsyncBuffersPool* buffers = nullptr;
352
353 CircularQueue<Request> readQueue;
354};
355
364struct SC_ASYNC_STREAMS_EXPORT AsyncWritableStream
365{
368
369 friend struct AsyncPipeline;
370
371 struct Request
372 {
373 AsyncBufferView::ID bufferID;
374
375 Function<void(AsyncBufferView::ID)> cb;
376 };
377 static constexpr int MaxListeners = 8;
378
379 Event<MaxListeners, Result> eventError;
380
381 Event<MaxListeners> eventDrain;
382 Event<MaxListeners> eventFinish;
383 Event<MaxListeners> eventClose;
384
388 Result init(AsyncBuffersPool& buffersPool);
389
391 constexpr void setWriteQueue(Span<Request> requests) { writeQueue = requests; }
392
394 [[nodiscard]] size_t getWriteQueueSize() const { return writeQueue.size(); }
395
402 Result write(AsyncBufferView::ID bufferID, Function<void(AsyncBufferView::ID)> cb = {});
403
406 Result write(AsyncBufferView&& bufferView, Function<void(AsyncBufferView::ID)> cb = {});
407
410 void end();
411
414 void destroy();
415
418
420 void finishedWriting(AsyncBufferView::ID bufferID, Function<void(AsyncBufferView::ID)>&& cb, Result res);
421
424
426 Result unshift(AsyncBufferView::ID bufferID, Function<void(AsyncBufferView::ID)>&& cb);
427
429 void emitError(Result error);
430
432 void tryAsync(Result potentialError);
433
435 [[nodiscard]] bool isStillWriting() const { return state == State::Writing or state == State::Ending; }
436
438 [[nodiscard]] bool hasBeenDestroyed() const { return destroyed; }
439
441 void setAutoDestroy(bool value) { autoDestroy = value; }
442
444 [[nodiscard]] bool getAutoDestroy() const { return autoDestroy; }
445
446 protected:
447 virtual ~AsyncWritableStream();
448
450 virtual Result asyncWrite(AsyncBufferView::ID, Function<void(AsyncBufferView::ID)> func) = 0;
451
455 virtual bool canEndWritable();
456
459 virtual Result asyncDestroyWritable();
460
463
464 [[nodiscard]] bool isEndingWritable() const { return state == State::Ending; }
465
466 void stop() { state = State::Stopped; }
467
468 private:
469 [[nodiscard]] bool canAcceptWrite() const
470 {
471 return (state == State::Stopped or state == State::Writing) and not writeQueue.isFull();
472 }
473
474 enum class State : uint8_t
475 {
476 Stopped,
477 Writing,
478 Ending,
479 Ended,
480 Destroying,
481 Errored,
482 };
483 State state = State::Stopped;
484
485 bool destroyed = false;
486 bool autoDestroy = true;
487
488 AsyncBuffersPool* buffers = nullptr;
489
490 CircularQueue<Request> writeQueue;
491};
492
494struct SC_ASYNC_STREAMS_EXPORT AsyncDuplexStream : public AsyncReadableStream, public AsyncWritableStream
495{
497
498 Result init(AsyncBuffersPool& buffersPool, Span<AsyncReadableStream::Request> readableRequests,
499 Span<AsyncWritableStream::Request> writableRequests);
500
501 virtual Result asyncRead() override;
502};
503
505struct SC_ASYNC_STREAMS_EXPORT AsyncTransformStream : public AsyncDuplexStream
506{
508
509 void afterProcess(Span<const char> inputAfter, Span<char> outputAfter);
510 void afterFinalize(Span<char> outputAfter, bool streamEnded);
511
512 virtual Result onProcess(Span<const char>, Span<char>) = 0;
513 virtual Result onFinalize(Span<char>) = 0;
514
515 private:
516 virtual Result asyncWrite(AsyncBufferView::ID bufferID, Function<void(AsyncBufferView::ID)> cb) override;
517 virtual bool canEndWritable() override;
518
519 Function<void(AsyncBufferView::ID)> inputCallback;
520
521 Span<const char> inputData;
522 Span<char> outputData;
523
524 AsyncBufferView::ID inputBufferID;
525 AsyncBufferView::ID outputBufferID;
526
527 Result prepare(AsyncBufferView::ID bufferID, Function<void(AsyncBufferView::ID)> cb);
528
529 void tryFinalize();
530
531 enum class State
532 {
533 None,
534 Paused,
535 Processing,
536 Finalizing,
537 Finalized,
538 };
539 State state = State::None;
540};
541
544struct SC_ASYNC_STREAMS_EXPORT AsyncStreams
545{
551};
552
560struct SC_ASYNC_STREAMS_EXPORT AsyncPipeline
561{
562 static constexpr int MaxListeners = 8;
563 static constexpr int MaxTransforms = 8;
564 static constexpr int MaxSinks = 8;
565
566 AsyncPipeline() = default;
567 AsyncPipeline(const AsyncPipeline&) = delete;
568 AsyncPipeline(AsyncPipeline&&) = delete;
569 AsyncPipeline& operator=(const AsyncPipeline&) = delete;
570 AsyncPipeline& operator=(AsyncPipeline&&) = delete;
572
573 AsyncReadableStream* source = nullptr;
574 AsyncDuplexStream* transforms[MaxTransforms] = {nullptr};
575 AsyncWritableStream* sinks[MaxSinks] = {nullptr};
576 Event<MaxListeners, Result> eventError = {};
577
580 Result pipe();
581
583 [[nodiscard]] bool unpipe();
584
587 Result start();
588
589 // Internal state used by the pipeline implementation.
590 AsyncReadableStream* dispatchReadable = nullptr;
591 AsyncReadableStream* transformInputs[MaxTransforms] = {nullptr};
592
594 {
595 AsyncReadableStream* readable = nullptr;
596 AsyncWritableStream* writable = nullptr;
597 AsyncBufferView::ID bufferID;
598 };
599 PendingWrite pendingWrites[MaxTransforms + MaxSinks] = {};
600 bool shouldEndWhenDrained = false;
601 bool endingPipes = false;
602
603 // TODO: Add a pause and cancel/step
604 private:
605 void emitError(Result res);
606 Result checkBuffersPool();
607 Result chainTransforms(AsyncReadableStream*& readable);
608 Result validate();
609
610 void asyncWriteWritable(AsyncBufferView::ID bufferID, AsyncReadableStream& readable, AsyncWritableStream& writable);
611 void dispatchToPipes(AsyncBufferView::ID bufferID);
612 void endPipes();
613 void afterSinkEnd();
614 void afterWrite(AsyncBufferView::ID bufferID);
615 void dispatchToTransform(AsyncBufferView::ID bufferID, size_t transformIndex);
616 bool retryPendingWrites();
617 bool hasPendingWrites() const;
618 bool hasPendingWritesForReadable(const AsyncReadableStream& readable) const;
619 void releasePendingWrites();
620 bool listenToEventData(AsyncReadableStream& readable, AsyncDuplexStream& transform, bool listen);
621
622 PendingWrite* findPendingWrite(AsyncReadableStream& readable, AsyncWritableStream& writable);
623};
624} // namespace SC
Definition AsyncStreams.h:67
A Span of bytes memory to be read or written by async streams.
Definition AsyncStreams.h:65
AsyncBufferView(T &&t)
Saves a copy (or a moved instance) of a String / Buffer (or anything that works with GrowableBuffer<T...
Definition AsyncStreams.h:112
void setReusable(bool reusable)
Tags this AsyncBufferView as reusable after its refCount goes to zero.
Definition AsyncStreams.h:106
Holds a Span of AsyncBufferView (allocated by user) holding available memory for the streams.
Definition AsyncStreams.h:178
Result getReadableData(AsyncBufferView::ID bufferID, Span< const char > &data)
Access data span owned by the buffer.
void setBuffers(Span< AsyncBufferView > newBuffers)
Sets memory for the new buffers.
Definition AsyncStreams.h:208
void refBuffer(AsyncBufferView::ID bufferID)
Increments a buffer reference count.
AsyncBufferView * getBuffer(AsyncBufferView::ID bufferID)
Access the raw AsyncBufferView (if any) at a given bufferID (or nullptr if invalid)
Result createChildView(AsyncBufferView::ID parentBufferID, size_t offset, size_t length, AsyncBufferView::ID &outChildBufferID)
Creates a child view that references a slice of the parent buffer.
void setNewBufferSize(AsyncBufferView::ID bufferID, size_t newSizeInBytes)
Sets the new size in bytes for the buffer.
Result getWritableData(AsyncBufferView::ID bufferID, Span< char > &data)
Access data span owned by the buffer.
static Result sliceInEqualParts(Span< AsyncBufferView > buffers, Span< char > memory, size_t numSlices)
Splits a span of memory in equally sized slices, assigning them to buffers and marking them as reusab...
Result requestNewBuffer(size_t minimumSizeInBytes, AsyncBufferView::ID &bufferID, Span< char > &data)
Requests a new available buffer that is at least minimumSizeInBytes, incrementing its refcount.
Result pushBuffer(AsyncBufferView &&buffer, AsyncBufferView::ID &bufferID)
Adds a buffer to the pool in any empty slot (found by scanning from start to end)
void unrefBuffer(AsyncBufferView::ID bufferID)
Decrements a buffer reference count.
size_t getNumBuffers() const
Gets size of buffers held by the pool.
Definition AsyncStreams.h:211
A stream that can both produce and consume buffers.
Definition AsyncStreams.h:495
virtual Result asyncRead() override
Function that every stream must define to implement its custom read operation.
Definition AsyncStreams.h:594
Pipes read data from SC::AsyncReadableStream, forwarding them to SC::AsyncWritableStream.
Definition AsyncStreams.h:561
Result pipe()
Reports errors by source, transforms or sinks.
bool unpipe()
Unregisters all events from source, transforms and sinks.
Result start()
Starts the pipeline.
Definition AsyncStreams.h:234
Async source abstraction emitting data events in caller provided byte buffers.
Definition AsyncStreams.h:229
bool getAutoDestroy() const
Returns true if stream will automatically call .destroy() when Ended state is reached.
Definition AsyncStreams.h:308
void pushEnd()
Use pushEnd from inside AsyncReadableStream::asyncRead to signal production end.
void emitError(Result error)
Signals an async error received.
void resumeReading()
Resumes the readable stream paused by AsyncReadableStream::pause.
bool push(AsyncBufferView::ID bufferID, size_t newSize)
Use push from inside AsyncReadableStream::asyncRead function to queue received data.
Event< MaxListeners > eventEnd
Emitted when a new buffer has been read.
Definition AsyncStreams.h:242
bool hasBeenDestroyed() const
Returns true if the stream has been already destroyed (asynchronously through destroy())
Definition AsyncStreams.h:270
Result finishedDestroyingReadable()
Called from inside asyncDestroy to transition from Destroying to Destroyed state (emitting eventClose...
virtual Result asyncResumeReading()
Function that streams may define to resume an already pending async read.
bool hasQueuedData() const
Returns true if there are buffered reads waiting to be emitted.
Definition AsyncStreams.h:267
Event< MaxListeners > eventClose
Emitted when there is no more data.
Definition AsyncStreams.h:243
Event< MaxListeners, AsyncBufferView::ID > eventData
Emitted when an error occurs.
Definition AsyncStreams.h:241
AsyncBuffersPool & getBuffersPool()
Obtains the AsyncBuffersPool to request more buffers.
size_t getReadQueueSize() const
Returns the size of read queue.
Definition AsyncStreams.h:282
void setAutoDestroy(bool value)
If set to true will automatically call .destroy() when Ended state is reached.
Definition AsyncStreams.h:305
virtual Result asyncDestroyReadable()
Function that a readable stream can re-implement to release its internal resources.
void destroy()
Forcefully destroys the readable stream before calling end event releasing all resources.
virtual Result asyncRead()=0
Function that every stream must define to implement its custom read operation.
bool getBufferOrPause(size_t minumumSizeInBytes, AsyncBufferView::ID &bufferID, Span< char > &data)
Returns an unused buffer from pool or pauses the stream if none is available.
bool isEnded() const
Returns true if the stream is ended (AsyncReadableStream::end has been called)
Definition AsyncStreams.h:264
constexpr void setReadQueue(Span< Request > requests)
Sets the read queue for this readable stream.
Definition AsyncStreams.h:279
Result init(AsyncBuffersPool &buffersPool)
Emitted when the underlying resource has been closed.
void reactivate(bool doReactivate)
Use reactivate(true) from inside AsyncReadableStream::asyncRead function to ask the state machine to ...
void pause()
Pauses the readable stream (that can be later resumed)
bool canStart() const
Returns true when start() is currently valid for this stream.
Definition AsyncStreams.h:273
Result unshift(AsyncBufferView::ID bufferID)
Push back a buffer to the front of the read queue (e.g. for un-consumed data)
Result start()
Starts the readable stream, that will emit eventData.
Traits exposing AsyncStreams public types through a single template parameter.
Definition AsyncStreams.h:545
A duplex stream that produces new buffers transforming received buffers.
Definition AsyncStreams.h:506
Definition AsyncStreams.h:372
Async destination abstraction where bytes can be written to.
Definition AsyncStreams.h:365
size_t getWriteQueueSize() const
Returns the size of write queue.
Definition AsyncStreams.h:394
Event< MaxListeners > eventFinish
Emitted when write queue is empty.
Definition AsyncStreams.h:382
Result write(AsyncBufferView::ID bufferID, Function< void(AsyncBufferView::ID)> cb={})
Writes a buffer (that must be allocated by the AsyncBuffersPool passed in AsyncWritableStream) When t...
void end()
Ends the writable stream, waiting for all in-flight and queued writes to finish.
void destroy()
Forcefully destroys the writable stream before calling end event releasing all resources.
void emitError(Result error)
Signals an async error received.
void finishedDestroyingWritable()
Function that MUST be called by re-implementations of asyncDestroyWritable once they're done.
Event< MaxListeners > eventDrain
Emitted when an error occurs.
Definition AsyncStreams.h:381
virtual bool canEndWritable()
Allows keeping a writable in ENDING state until it has finished flushing all pending data.
virtual Result asyncWrite(AsyncBufferView::ID, Function< void(AsyncBufferView::ID)> func)=0
Function that every stream must define to implement its custom write operation.
bool isStillWriting() const
Returns true if this stream is writing something.
Definition AsyncStreams.h:435
void resumeWriting()
Resumes writing queued requests for this stream.
virtual Result asyncDestroyWritable()
Function that a writable stream can re-implement to release its internal resources.
void setAutoDestroy(bool value)
If set to true will automatically call .destroy() when Ended state is reached.
Definition AsyncStreams.h:441
bool hasBeenDestroyed() const
Returns true if the stream has been already destroyed (asynchronously through destroy())
Definition AsyncStreams.h:438
Result init(AsyncBuffersPool &buffersPool)
Emitted when the underlying resource has been closed.
void finishedWriting(AsyncBufferView::ID bufferID, Function< void(AsyncBufferView::ID)> &&cb, Result res)
Signals that the given buffer (previously queued by write) has been fully written.
bool getAutoDestroy() const
Returns true if stream will automatically call .destroy() when Ended state is reached.
Definition AsyncStreams.h:444
void tryAsync(Result potentialError)
Will emit error if the passed in Result is false.
Result unshift(AsyncBufferView::ID bufferID, Function< void(AsyncBufferView::ID)> &&cb)
Puts back a buffer at the top of the write queue.
Result write(AsyncBufferView &&bufferView, Function< void(AsyncBufferView::ID)> cb={})
Push a new buffer view to the queue, registering it with the allocator.
AsyncBuffersPool & getBuffersPool()
Obtains the buffers pool to access its data.
Event< MaxListeners > eventClose
Emitted when no more data can be written.
Definition AsyncStreams.h:383
constexpr void setWriteQueue(Span< Request > requests)
Sets the write queue for this writable stream.
Definition AsyncStreams.h:391