/*** 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 * Warning: AppendInterceptorEx is preferred * @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. * Warning: AppendInterceptorEx is preferred * @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 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 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 to us. * Such paradigm contrasts the default unframed/raw stream behaviour where the processor is responsible for consuming all * available data. * 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 following interceptor * (this is a problem when the frame does not contain a length prefix and the next interceptor is a frame processor) * 2) only reads a portion of pReadInByteBuffer * (the current interceptor can only process a frame of data per tick) * * This function sets an internal flag that indicates re-ticks from the root single frame processor are to be expected * in order to complete a single ::DoTick tick. With this flag enabled, multiple tick may occur as opposed to a single * callback per ::DoTick(). * @param pInterceptorEx * @return */ virtual AuSPtr AppendSingleFrameProcessor(const AuSPtr &pInterceptorEx) = 0; /** * @brief * @param pInterceptorEx * @return */ virtual AuSPtr PrependSingleFrameProcessor(const AuSPtr &pInterceptorEx) = 0; /** * @brief See: AppendSingleFrameProcessor * @param pInterceptorEx * @return */ virtual AuSPtr AppendSingleFrameProcessorEx(const AuSPtr &pInterceptorEx, AuUInt uOutputBufferSize) = 0; /** * @brief * @param pInterceptorEx * @param uOutputBufferSize * @return */ virtual AuSPtr PrependSingleFrameProcessorEx(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. * @return The error state of the top-most interceptor */ virtual bool DoTick() = 0; /** * @brief */ virtual void Destroy() = 0; /** * @brief * @return */ virtual AuList> GetArrayOfInterceptors() = 0; /** * @brief * @param uIndex * @return */ virtual AuSPtr GetInterceptorAtIndex(AuUInt32 uIndex) = 0; AURT_ADD_USR_DATA; }; /** * @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. * @param pWork * @return */ AUKN_SYM AuSPtr NewProtocolStackFromPipe(const AuSPtr &pWork, bool bAutoTick = true, bool bKillPipeOnFirstRootLevelFalse = true); }