// // Created by erki on 27.03.21. // #ifndef SKULLC_MESSAGING_PARSER_HPP_ #define SKULLC_MESSAGING_PARSER_HPP_ #include #include #include namespace Messaging { template class Parser { public: using Packet = P; const std::size_t buffer_length = N; Parser() { reset(); } Parser(const Parser&) = delete; Parser(Parser&&) = delete; void reset() { state_ = State_::Preamble; expected_ = sizeof(P::preamble); current_pos_ = 0; current_offset_ = 0; } void pushByte(const std::uint8_t byte) { if (packetReady()) return; const std::uint32_t buffer_loc = current_offset_ + current_pos_; switch (state_) { case State_::Preamble: if (byte != P::preamble[current_pos_]) { reset(); return; } [[fallthrough]]; case State_::Length: case State_::Body: buffer_[buffer_loc] = byte; current_pos_++; break; default: break; } if (current_pos_ == expected_) { setupNextState_(); } } bool packetReady() const { return state_ == State_::Done; } bool getPacket(Packet& packet) const { return packet.deserialize(buffer_.data(), current_offset_); } private: enum class State_ : std::uint32_t { Preamble, Length, Body, Done }; std::array buffer_; State_ state_ = State_::Preamble; std::uint32_t current_pos_ = 0; std::uint32_t current_offset_ = 0; std::uint32_t expected_ = 0; template T deserializeLength_(const std::uint32_t offset) { std::uint8_t* begin = buffer_.data() + offset; T len(0); std::memcpy(&len, begin, sizeof(T)); return len; } void setupNextState_() { switch (state_) { case State_::Preamble: state_ = State_::Length; expected_ = sizeof(typename P::length_type); break; case State_::Length: state_ = State_::Body; expected_ = deserializeLength_(current_offset_); break; case State_::Body: state_ = State_::Done; break; default: break; } current_offset_ += current_pos_; current_pos_ = 0; } }; }// namespace Messaging #endif// SKULLC_MESSAGING_PARSER_HPP_