// // 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; } }; } #endif //SKULLC_MESSAGING_PARSER_HPP