/*** Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: IProtocolStack.hpp Date: 2022-8-24 Author: Reece ***/ #pragma once namespace Aurora::IO::Protocol { struct IProtocolStack : IProtocolBaseReader, IProtocolBaseWriter { /** * @brief * @param pInterceptor * @param uOutputBufferSize When 0, a hopefully not stupid default is used. * @return */ virtual AuSPtr AppendInterceptor(const AuSPtr &pInterceptor, AuUInt uOutputBufferSize) = 0; /** * @brief Inserts the interceptor at the bottom of the protocol stack * @param pInterceptor * @param uOutputBufferSize When 0, a hopefully not stupid default is used. * @return */ virtual AuSPtr PrependInterceptor(const AuSPtr &pInterceptor, AuUInt uOutputBufferSize) = 0; /** * @brief * @param pInterceptorEx * @param uOutputBufferSize When 0, a hopefully not stupid default is used. * @return */ virtual AuSPtr AppendInterceptorEx(const AuSPtr &pInterceptorEx, AuUInt uOutputBufferSize) = 0; /** * @brief Same as AppendInterceptor, except that DoTick will repeat until the input is fully consumed. * This allows us to tick processors under our frame, followed by a retick if there is more data available. * Such paradigm contrasts the default stream-specific/non-framing behaviour where the processor is * responsible for consuming all non-segmented data (ala everything except the start of the final unfinished frame). * With such limitations, it's impossible to build a protocol where a piece in the middle * 1) can/should only flush 1 frame to the next processor * 2) reads only a portion of pReadInByteBuffer * This function sets an internal flag that indicates re-ticks from the root are to be expected to complete * a tick. Otherwise, the read head of the inbound frame of a persumed stream may only skip back to frame zero * on error OR frame +1 on success. With this flag, frame current to frame end will be ticked. * @param pInterceptorEx * @return */ virtual AuSPtr AppendSingleFrameProcessor(const AuSPtr &pInterceptorEx) = 0; /** * @brief See: AppendSingleFrameProcessor * @param pInterceptorEx * @return */ virtual AuSPtr AppendSingleFrameProcessorEx(const AuSPtr &pInterceptorEx, AuUInt uOutputBufferSize) = 0; /** * @brief Inserts the interceptor at the bottom of the protocol stack * @param pInterceptorEx * @param uOutputBufferSize When 0, a hopefully not stupid default is used. * @return */ virtual AuSPtr PrependInterceptorEx(const AuSPtr &pInterceptorEx, AuUInt uOutputBufferSize) = 0; /** * @brief * @param pInterceptor * @return */ virtual AuSPtr AddEndInterceptor(const AuSPtr &pInterceptor) = 0; /** * @brief Sends one tick down the protocol stack, regardless of how much data is written into the * next piece/interceptor, and regardless of if another read tick is required. * Latterly, you are responsible for consuming all available bytes in your non-framed * (~AppendSingleFrameProcessor[Ex]) interceptors. */ virtual void DoTick() = 0; /** * @brief */ virtual void Destroy() = 0; }; /** * @brief Allocates a new protocol stack with a buffered input stream of uLength bytes * @param uLength * @return */ AUKN_SYM AuSPtr NewBufferedProtocolStack(AuUInt uLength); /** * @brief Creates a protocol stack backed by the memory of a pipe. * DoTick must be called each time the pipe has data. * @param pWork * @return */ AUKN_SYM AuSPtr NewProtocolStackFromPipe(const AuSPtr &pWork, bool bAutoTick = true); }