diff --git a/CMakeLists.txt b/CMakeLists.txt index b40feba..1070bf9 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,7 +12,7 @@ set(CMAKE_C_COMPILER "clang") set(CMAKE_EXPORT_COMPILE_COMMANDS ON) cmake_minimum_required(VERSION 3.18) project(${PROJ_NAME} LANGUAGES C CXX) -set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD 23) file(STRINGS "./other/build.nr" BUILD_NUMBER) #----------------------------------------------------------------------------------------- diff --git a/other/build.nr b/other/build.nr index cf7d7d1..c4970c4 100644 --- a/other/build.nr +++ b/other/build.nr @@ -1 +1 @@ -2087 +2090 diff --git a/src/ostd/data/BaseObject.hpp b/src/ostd/data/BaseObject.hpp index edce197..550a8c6 100755 --- a/src/ostd/data/BaseObject.hpp +++ b/src/ostd/data/BaseObject.hpp @@ -20,14 +20,14 @@ #pragma once -#include +#include #include namespace ostd { class OutputHandlerBase; struct Signal; - class BaseObject : public __i_stringeable + class BaseObject : public __i_stringeable, public __i_serializable { public: using SignalCallback = std::function; public: @@ -60,9 +60,11 @@ namespace ostd virtual inline String toString(void) const override { return getObjectHeaderString(); }; virtual void print(bool newLine = true, OutputHandlerBase* __destination = nullptr) const; + virtual inline Serial::Stream serialize(void) const override { return { 0 }; }; + virtual inline bool deserialize(const Serial::Stream& data) override { return false; }; + virtual inline void handleSignal(Signal& signal) { } void connectSignal(u32 signal_id); - void __handle_signal(Signal& signal); protected: diff --git a/src/ostd/data/Types.hpp b/src/ostd/data/Types.hpp index 519029f..8b0e0c9 100755 --- a/src/ostd/data/Types.hpp +++ b/src/ostd/data/Types.hpp @@ -97,6 +97,17 @@ namespace ostd static inline const u8 ADDR = 4; static inline const u8 FLOAT = 4; static inline const u8 DOUBLE = 8; + + static inline const u8 INT8 = 1; + static inline const u8 UINT8 = 1; + static inline const u8 INT16 = 2; + static inline const u8 UINT16 = 2; + static inline const u8 INT32 = 4; + static inline const u8 UINT32 = 4; + static inline const u8 INT64 = 8; + static inline const u8 UINT64 = 8; + static inline const u8 FLOAT32 = 4; + static inline const u8 FLOAT64 = 8; }; typedef stdvec ByteStream; diff --git a/src/ostd/io/Serial.cpp b/src/ostd/io/Serial.cpp index bdf7b6b..44123a9 100755 --- a/src/ostd/io/Serial.cpp +++ b/src/ostd/io/Serial.cpp @@ -3,6 +3,496 @@ namespace ostd { + bool Serial::isValidAddress(u64 addr, u32 size) + { + if (addr == 0) return false; + if (size == 0) return false; + if (addr > u64Range::max() - size) return false; // u64 overflow check + return (addr + size - 1) < s_openStream.size(); + } + + Serial::ReadResult Serial::read::int8(u64 addr) + { + if (!isStreamAttached()) return { 0, true }; + managed_address_check(addr); + if (!isValidAddress(addr, tTypeSize::INT8)) return { 0, true }; + i8 val = s_openStream[addr]; + s_addr += tTypeSize::INT8; + return { val, false }; + } + + Serial::ReadResult Serial::read::uint8(u64 addr) + { + auto res = int8(addr); + return { cast(res.value), res.error }; + } + + Serial::ReadResult Serial::read::int16(u64 addr) + { + if (!isStreamAttached()) return { 0, true }; + managed_address_check(addr); + if (!isValidAddress(addr, tTypeSize::INT16)) return { 0, true }; + i16 val = 0; + if (isLittleEndian()) + { + val = ((s_openStream[addr + 0] ) & 0x00FFU) + | ((s_openStream[addr + 1] << 8) & 0xFF00U); + } + else if (isBigEndian()) + { + val = ((s_openStream[addr + 0] << 8) & 0xFF00U) + | ( s_openStream[addr + 1] & 0x00FFU); + } + else return { 0, true }; + s_addr += tTypeSize::INT16; + return { val, false }; + } + + Serial::ReadResult Serial::read::uint16(u64 addr) + { + auto res = int16(addr); + return { cast(res.value), res.error }; + } + + Serial::ReadResult Serial::read::int32(u64 addr) + { + if (!isStreamAttached()) return { 0, true }; + managed_address_check(addr); + if (!isValidAddress(addr, tTypeSize::INT32)) return { 0, true }; + i32 val = 0; + if (isLittleEndian()) + { + val = ((s_openStream[addr + 0] ) & 0x000000FF) + | ((s_openStream[addr + 1] << 8) & 0x0000FF00) + | ((s_openStream[addr + 2] << 16) & 0x00FF0000) + | ((s_openStream[addr + 3] << 24) & 0xFF000000); + } + else if (isBigEndian()) + { + val = ((s_openStream[addr + 0] << 24) & 0xFF000000U) + | ((s_openStream[addr + 1] << 16) & 0x00FF0000U) + | ((s_openStream[addr + 2] << 8) & 0x0000FF00U) + | ( s_openStream[addr + 3] & 0x000000FFU); + } + else return { 0, true }; + s_addr += tTypeSize::INT32; + return { val, false }; + } + + Serial::ReadResult Serial::read::uint32(u64 addr) + { + auto res = int32(addr); + return { cast(res.value), res.error }; + } + + Serial::ReadResult Serial::read::int64(u64 addr) + { + if (!isStreamAttached()) return { 0, true }; + managed_address_check(addr); + if (!isValidAddress(addr, tTypeSize::INT64)) return { 0, true }; + i64 val = 0; + if (isLittleEndian()) + { + val = ( s_openStream[addr + 7] & 0x00000000000000FFU) + | (( s_openStream[addr + 6] << 8) & 0x000000000000FF00U) + | (( s_openStream[addr + 5] << 16) & 0x0000000000FF0000U) + | (( s_openStream[addr + 4] << 24) & 0x00000000FF000000U) + | (((i64)s_openStream[addr + 3] << 32) & 0x000000FF00000000U) + | (((i64)s_openStream[addr + 2] << 40) & 0x0000FF0000000000U) + | (((i64)s_openStream[addr + 1] << 48) & 0x00FF000000000000U) + | (((i64)s_openStream[addr + 0] << 56) & 0xFF00000000000000U); + } + else if (isBigEndian()) + { + val = (((i64)s_openStream[addr + 0] << 56) & 0xFF00000000000000U) + | (((i64)s_openStream[addr + 1] << 48) & 0x00FF000000000000U) + | (((i64)s_openStream[addr + 2] << 40) & 0x0000FF0000000000U) + | (((i64)s_openStream[addr + 3] << 32) & 0x000000FF00000000U) + | (( s_openStream[addr + 4] << 24) & 0x00000000FF000000U) + | (( s_openStream[addr + 5] << 16) & 0x0000000000FF0000U) + | (( s_openStream[addr + 6] << 8) & 0x000000000000FF00U) + | ( s_openStream[addr + 7] & 0x00000000000000FFU); + } + else return { 0, true }; + s_addr += tTypeSize::INT64; + return { val, false }; + } + + Serial::ReadResult Serial::read::uint64(u64 addr) + { + auto res = int64(addr); + return { cast(res.value), res.error }; + } + + Serial::ReadResult Serial::read::float32(u64 addr) + { + if (!isStreamAttached()) return { 0, true }; + managed_address_check(addr); + if (!isValidAddress(addr, tTypeSize::FLOAT32)) return { 0, true }; + __float_parser fp; + if (isLittleEndian()) + { + fp.data[3] = s_openStream[addr + 0]; + fp.data[2] = s_openStream[addr + 1]; + fp.data[1] = s_openStream[addr + 2]; + fp.data[0] = s_openStream[addr + 3]; + } + else if (isBigEndian()) + { + fp.data[0] = s_openStream[addr + 0]; + fp.data[1] = s_openStream[addr + 1]; + fp.data[2] = s_openStream[addr + 2]; + fp.data[3] = s_openStream[addr + 3]; + } + else return { 0, true }; + s_addr += tTypeSize::FLOAT32; + return { fp.val, false }; + } + + Serial::ReadResult Serial::read::float64(u64 addr) + { + if (!isStreamAttached()) return { 0, true }; + managed_address_check(addr); + if (!isValidAddress(addr, tTypeSize::FLOAT64)) return { 0, true }; + __double_parser dp; + if (isLittleEndian()) + { + dp.data[7] = s_openStream[addr++]; + dp.data[6] = s_openStream[addr++]; + dp.data[5] = s_openStream[addr++]; + dp.data[4] = s_openStream[addr++]; + dp.data[3] = s_openStream[addr++]; + dp.data[2] = s_openStream[addr++]; + dp.data[1] = s_openStream[addr++]; + dp.data[0] = s_openStream[addr ]; + } + else if (isBigEndian()) + { + dp.data[0] = s_openStream[addr++]; + dp.data[1] = s_openStream[addr++]; + dp.data[2] = s_openStream[addr++]; + dp.data[3] = s_openStream[addr++]; + dp.data[4] = s_openStream[addr++]; + dp.data[5] = s_openStream[addr++]; + dp.data[6] = s_openStream[addr++]; + dp.data[7] = s_openStream[addr ]; + } + else return { 0, true }; + s_addr += tTypeSize::FLOAT64; + return { dp.val, false }; + } + + bool Serial::read::stream(Stream& outStream, u64 addr, bool sizeStored, u32 size_if_not_stored) + { + if (!isStreamAttached()) return false; + managed_address_check(addr); + if (!sizeStored && size_if_not_stored < 1) return false; + u32 size = size_if_not_stored; + if (sizeStored) + { + auto tmp = uint32(addr); + if (tmp.error) return false; + addr += tTypeSize::UINT32; + size = tmp.value; + } + Endianness endianness; + { + auto tmp = uint8(addr); + if (tmp.error) return false; + addr += tTypeSize::UINT8; + if (tmp.value == cast(Endianness::LittleEndian)) + endianness = Endianness::LittleEndian; + else if (tmp.value == cast(Endianness::BigEndian)) + endianness = Endianness::BigEndian; + else return false; + } + if (!isValidAddress(addr, size)) return false; + Serial::Stream data = { size, endianness }; + StreamEdit edit = data.data(); + std::copy_n(s_openStream.begin() + addr, size, edit.begin()); + outStream = std::move(data); + s_addr = addr + size; + return true; + } + + bool Serial::read::string(String& outString, u64 addr, bool sizeStored, u32 size_if_not_stored, bool null_terminated) + { + if (!isStreamAttached()) return false; + managed_address_check(addr); + if (!null_terminated || sizeStored) // I want null_terminated to have the lowest priority + { + if (!sizeStored && size_if_not_stored < 1) return false; + u32 size = size_if_not_stored; + if (sizeStored) + { + auto tmp = uint32(addr); + if (tmp.error) return false; + addr += tTypeSize::UINT32; + size = tmp.value; + } + if (!isValidAddress(addr, size)) return false; + for (u64 i = addr; i < (addr + size); i++) + { + outString += cast(s_openStream[i]); + } + s_addr = addr + size; + return true; + } + else + { + String out = ""; + auto tmp = int8(addr); + if (tmp.error) return false; + addr += tTypeSize::INT8; + while (tmp.value != '\0') + { + out += cast(tmp.value); + tmp = int8(addr); + if (tmp.error) return false; + addr += tTypeSize::INT8; + } + outString = out; + s_addr = addr; + return true; + } + } + + bool Serial::read::object(__i_serializable& outObject, u64 addr) + { + Serial::Stream objData(0); + if (!stream(objData, addr, true, 0)) + return false; + return outObject.deserialize(objData); + } + + + + bool Serial::write::int8(u64 addr, i8 value) + { + if (!isStreamAttached()) return false; + managed_address_check(addr); + if (!isValidAddress(addr, tTypeSize::INT8)) return false; + s_openStream[addr] = value; + s_addr += tTypeSize::INT8; + return true; + } + + bool Serial::write::uint8(u64 addr, u8 value) + { + return int8(addr, cast(value)); + } + + bool Serial::write::int16(u64 addr, i16 value) + { + if (!isStreamAttached()) return false; + managed_address_check(addr); + if (!isValidAddress(addr, tTypeSize::INT16)) return false; + if (isLittleEndian()) + { + s_openStream[addr + 0] = value & 0xFF; + s_openStream[addr + 1] = (value >> 8) & 0xFF; + } + else if (isBigEndian()) + { + s_openStream[addr + 0] = (value >> 8) & 0xFF; + s_openStream[addr + 1] = value & 0xFF; + } + else return false; + s_addr += tTypeSize::INT16; + return true; + } + + bool Serial::write::uint16(u64 addr, u16 value) + { + return int16(addr, cast(value)); + } + + bool Serial::write::int32(u64 addr, i32 value) + { + if (!isStreamAttached()) return false; + managed_address_check(addr); + if (!isValidAddress(addr, tTypeSize::INT32)) return false; + if (isLittleEndian()) + { + s_openStream[addr + 0] = value & 0xFF; + s_openStream[addr + 1] = (value >> 8) & 0xFF; + s_openStream[addr + 2] = (value >> 16) & 0xFF; + s_openStream[addr + 3] = (value >> 24) & 0xFF; + } + else if (isBigEndian()) + { + s_openStream[addr + 0] = (value >> 24) & 0xFF; + s_openStream[addr + 1] = (value >> 16) & 0xFF; + s_openStream[addr + 2] = (value >> 8) & 0xFF; + s_openStream[addr + 3] = value & 0xFF; + } + else return false; + s_addr += tTypeSize::INT32; + return true; + } + + bool Serial::write::uint32(u64 addr, u32 value) + { + return int32(addr, cast(value)); + } + + bool Serial::write::int64(u64 addr, i64 value) + { + if (!isStreamAttached()) return false; + managed_address_check(addr); + if (!isValidAddress(addr, tTypeSize::INT64)) return false; + if (isLittleEndian()) + { + s_openStream[addr + 0] = value & 0xFF; + s_openStream[addr + 1] = (value >> 8) & 0xFF; + s_openStream[addr + 2] = (value >> 16) & 0xFF; + s_openStream[addr + 3] = (value >> 24) & 0xFF; + s_openStream[addr + 4] = (value >> 32) & 0xFF; + s_openStream[addr + 5] = (value >> 40) & 0xFF; + s_openStream[addr + 6] = (value >> 48) & 0xFF; + s_openStream[addr + 7] = (value >> 56) & 0xFF; + } + else if (isBigEndian()) + { + s_openStream[addr + 0] = (value >> 56) & 0xFF; + s_openStream[addr + 1] = (value >> 48) & 0xFF; + s_openStream[addr + 2] = (value >> 40) & 0xFF; + s_openStream[addr + 3] = (value >> 32) & 0xFF; + s_openStream[addr + 4] = (value >> 24) & 0xFF; + s_openStream[addr + 5] = (value >> 16) & 0xFF; + s_openStream[addr + 6] = (value >> 8) & 0xFF; + s_openStream[addr + 7] = value & 0xFF; + } + else return false; + s_addr += tTypeSize::INT64; + return true; + } + + bool Serial::write::uint64(u64 addr, u64 value) + { + if (!isStreamAttached()) return false; + if (!isValidAddress(addr, tTypeSize::UINT64)) return false; + return int64(addr, cast(value)); + } + + bool Serial::write::float32(u64 addr, f32 value) + { + if (!isStreamAttached()) return false; + managed_address_check(addr); + if (!isValidAddress(addr, tTypeSize::FLOAT32)) return false; + __float_parser fp; + fp.val = value; + if (isLittleEndian()) + { + s_openStream[addr + 0] = fp.data[3]; + s_openStream[addr + 1] = fp.data[2]; + s_openStream[addr + 2] = fp.data[1]; + s_openStream[addr + 3] = fp.data[0]; + } + else if (isBigEndian()) + { + s_openStream[addr + 0] = fp.data[0]; + s_openStream[addr + 1] = fp.data[1]; + s_openStream[addr + 2] = fp.data[2]; + s_openStream[addr + 3] = fp.data[3]; + } + else return false; + s_addr += tTypeSize::FLOAT32; + return true; + } + + bool Serial::write::float64(u64 addr, f64 value) + { + if (!isStreamAttached()) return false; + managed_address_check(addr); + if (!isValidAddress(addr, tTypeSize::FLOAT64)) return false; + __double_parser dp; + dp.val = value; + if (isLittleEndian()) + { + s_openStream[addr++] = dp.data[7]; + s_openStream[addr++] = dp.data[6]; + s_openStream[addr++] = dp.data[5]; + s_openStream[addr++] = dp.data[4]; + s_openStream[addr++] = dp.data[3]; + s_openStream[addr++] = dp.data[2]; + s_openStream[addr++] = dp.data[1]; + s_openStream[addr ] = dp.data[0]; + } + else if (isBigEndian()) + { + s_openStream[addr++] = dp.data[0]; + s_openStream[addr++] = dp.data[1]; + s_openStream[addr++] = dp.data[2]; + s_openStream[addr++] = dp.data[3]; + s_openStream[addr++] = dp.data[4]; + s_openStream[addr++] = dp.data[5]; + s_openStream[addr++] = dp.data[6]; + s_openStream[addr ] = dp.data[7]; + } + else return false; + s_addr += tTypeSize::FLOAT64; + return true; + } + + bool Serial::write::stream(u64 addr, const Stream& value, bool storeSize) + { + if (!isStreamAttached()) return false; + managed_address_check(addr); + u32 size = value.size(); + if (size < 1) return false; + if (storeSize) + { + if (!uint32(addr, size)) return false; + addr += tTypeSize::UINT32; + } + if (!isValidAddress(addr, size)) return false; + StreamView view = value.data(); + for (u64 i = addr; i < addr + size; i++) + s_openStream[i] = view[i - addr]; + s_addr = addr + size; + return true; + } + + bool Serial::write::string(u64 addr, const String& value, bool storeSize, bool null_terminated) + { + if (!isStreamAttached()) return false; + managed_address_check(addr); + u32 size = value.len(); + if (size < 1) return false; + if (storeSize) + { + null_terminated = false; + if (!uint32(addr, value.len())) return false; + addr += tTypeSize::UINT32; + } + size += (null_terminated ? 1 : 0); + if (!isValidAddress(addr, size)) + return false; + for (u64 i = addr; i < addr + size; i++) + { + i8 c = cast(value[i - addr]); + if (null_terminated && i == addr + size - 1) + c = '\0'; + s_openStream[i] = c; + } + s_addr = addr + size; + return true; + } + + bool Serial::write::object(u64 addr, const __i_serializable& value) + { + if (!isStreamAttached()) return false; + const Serial::Stream data = value.serialize(); + if (data.size() < 1) return false; + return stream(addr, data, true); + } + + + + + + // =============================================== OLD VERSION =============================================== namespace serial { bool SerialIO::init(u64 size, u8 endianness) @@ -20,10 +510,10 @@ namespace ostd if (!is_validAddr(addr, tTypeSize::QWORD)) return false; if (isLittleEndian()) { - outVal = ( m_data[addr + 7] & 0x00000000000000FFU) - | (( m_data[addr + 6] << 8) & 0x000000000000FF00U) - | (( m_data[addr + 5] << 16) & 0x0000000000FF0000U) - | (( m_data[addr + 4] << 24) & 0x00000000FF000000U) + outVal = ( m_data[addr + 7] & 0x00000000000000FFU) + | (( m_data[addr + 6] << 8) & 0x000000000000FF00U) + | (( m_data[addr + 5] << 16) & 0x0000000000FF0000U) + | (( m_data[addr + 4] << 24) & 0x00000000FF000000U) | (((QWord)m_data[addr + 3] << 32) & 0x000000FF00000000U) | (((QWord)m_data[addr + 2] << 40) & 0x0000FF0000000000U) | (((QWord)m_data[addr + 1] << 48) & 0x00FF000000000000U) @@ -35,10 +525,10 @@ namespace ostd | (((QWord)m_data[addr + 1] << 48) & 0x00FF000000000000U) | (((QWord)m_data[addr + 2] << 40) & 0x0000FF0000000000U) | (((QWord)m_data[addr + 3] << 32) & 0x000000FF00000000U) - | (( m_data[addr + 4] << 24) & 0x00000000FF000000U) - | (( m_data[addr + 5] << 16) & 0x0000000000FF0000U) - | (( m_data[addr + 6] << 8) & 0x000000000000FF00U) - | ( m_data[addr + 7] & 0x00000000000000FFU); + | (( m_data[addr + 4] << 24) & 0x00000000FF000000U) + | (( m_data[addr + 5] << 16) & 0x0000000000FF0000U) + | (( m_data[addr + 6] << 8) & 0x000000000000FF00U) + | ( m_data[addr + 7] & 0x00000000000000FFU); } else return false; return true; diff --git a/src/ostd/io/Serial.hpp b/src/ostd/io/Serial.hpp index 3347e64..0348ba5 100755 --- a/src/ostd/io/Serial.hpp +++ b/src/ostd/io/Serial.hpp @@ -1,33 +1,209 @@ /* - OmniaFramework - A collection of useful functionality - Copyright (C) 2026 OmniaX-Dev + OmniaFramework - A collection of useful functionality + Copyright (C) 2026 OmniaX-Dev - This file is part of OmniaFramework. + This file is part of OmniaFramework. - OmniaFramework is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. + OmniaFramework is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. - OmniaFramework is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + OmniaFramework is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with OmniaFramework. If not, see . + You should have received a copy of the GNU General Public License + along with OmniaFramework. If not, see . */ #pragma once -#include -#include -#include +#include +#include namespace ostd { - class OutputHandlerBase; + class __i_serializable; + class Serial + { + public: template struct ReadResult { T value; bool error { false }; }; + public: enum class Endianness : u8 { LittleEndian = 0, BigEndian }; + public: using StreamEdit = std::span; + public: using StreamView = std::span; + public: class Stream + { + public: + Stream(const Stream&) = delete; + Stream& operator=(const Stream&) = delete; + inline Stream(u64 size, Endianness endianness = Endianness::LittleEndian, bool preInitialize = false, i8 initialValue = 0) { + if (size < 1) return; + if constexpr (sizeof(size_t) < sizeof(uint64_t)) + { + if (size > std::numeric_limits::max()) + throw "Serial::Stream size can't excede UINT32_MAX on a 32bit system."; + } + m_data = new i8[size]; + m_size = size; + m_endianness = endianness; + if (preInitialize) + { + for (u64 i = 0; i < size; i++) + m_data[i] = initialValue; + } + } + inline Stream(Stream&& other) noexcept : m_data(other.m_data), m_size(other.m_size) { + other.m_data = nullptr; + other.m_size = 0; + m_endianness = other.m_endianness; + } + inline Stream& operator=(Stream&& other) noexcept { + if (this != &other) { + delete[] m_data; + m_data = other.m_data; + m_size = other.m_size; + m_endianness = other.m_endianness; + other.m_data = nullptr; + other.m_size = 0; + } + return *this; + } + inline ~Stream(void) { + delete[] m_data; + m_data = nullptr; + } + inline bool isValid(void) const { return m_size > 0 && m_data != nullptr; } + inline u64 size(void) const { return isValid() ? m_size : 0; } + inline bool isLittleEndian(void) const { return m_endianness == Endianness::LittleEndian; } + inline bool isBigEndian(void) const { return m_endianness == Endianness::BigEndian; } + inline Endianness getEndianness(void) const { return m_endianness; } + inline StreamEdit data() { + if (isValid()) + return { m_data, cast(m_size) }; + return {}; + } + inline StreamView data() const { + if (isValid()) + return { m_data, cast(m_size) }; + return {}; + } + private: + i8* m_data { nullptr }; + u64 m_size { 0 }; + Endianness m_endianness { Endianness::LittleEndian }; + }; + + public: + inline static void attachStream(Stream& stream) { s_openStream = stream.data(); s_endianness = stream.getEndianness(); disableManagedAddress(); } + inline static void detachStrean(void) { s_openStream = {}; } + inline static bool setManagedAddress(u64 addr) { if (!isManagedAddressEnabled() || !isValidAddress(addr)) return false; s_addr = addr; return true; } + inline static bool isManagedAddressEnabled(void) { return s_managedAddress; } + inline static void enableManagedAddress(bool enable = true) { s_managedAddress = enable; s_addr = 0; } + inline static void disableManagedAddress(void) { enableManagedAddress(false); } + inline static bool isStreamAttached(void) { return !s_openStream.empty(); } + inline static bool isLittleEndian(void) { return s_endianness == Endianness::LittleEndian; } + inline static bool isBigEndian(void) { return s_endianness == Endianness::BigEndian; } + static bool isValidAddress(u64 addr, u32 size = 1); + + public: struct read + { + ReadResult int8(u64 addr = 0); + inline i8 int8d(u64 addr = 0, bool* outError = nullptr) { auto val = int8(addr); if (outError) *outError = val.error; return val.value; } + ReadResult uint8(u64 addr = 0); + inline u8 uint8d(u64 addr = 0, bool* outError = nullptr) { auto val = uint8(addr); if (outError) *outError = val.error; return val.value; } + + ReadResult int16(u64 addr = 0); + inline i16 int16d(u64 addr = 0, bool* outError = nullptr) { auto val = int16(addr); if (outError) *outError = val.error; return val.value; } + ReadResult uint16(u64 addr = 0); + inline u16 uint16d(u64 addr = 0, bool* outError = nullptr) { auto val = uint16(addr); if (outError) *outError = val.error; return val.value; } + + ReadResult int32(u64 addr = 0); + inline i32 int32d(u64 addr = 0, bool* outError = nullptr) { auto val = int32(addr); if (outError) *outError = val.error; return val.value; } + ReadResult uint32(u64 addr = 0); + inline u32 uint32d(u64 addr = 0, bool* outError = nullptr) { auto val = uint32(addr); if (outError) *outError = val.error; return val.value; } + + ReadResult int64(u64 addr = 0); + inline i64 int64d(u64 addr = 0, bool* outError = nullptr) { auto val = int64(addr); if (outError) *outError = val.error; return val.value; } + ReadResult uint64(u64 addr = 0); + inline u64 uint64d(u64 addr = 0, bool* outError = nullptr) { auto val = uint64(addr); if (outError) *outError = val.error; return val.value; } + + ReadResult float32(u64 addr = 0); + inline f32 float32d(u64 addr = 0, bool* outError = nullptr) { auto val = float32(addr); if (outError) *outError = val.error; return val.value; } + ReadResult float64(u64 addr = 0); + inline f64 float64d(u64 addr = 0, bool* outError = nullptr) { auto val = float64(addr); if (outError) *outError = val.error; return val.value; } + + bool stream(Stream& outStream, u64 addr = 0, bool sizeStored = true, u32 size_if_not_stored = 0); + bool string(String& outString, u64 addr = 0, bool sizeStored = true, u32 size_if_not_stored = 0, bool null_terminated = false); + bool object(__i_serializable& outObject, u64 addr = 0); + + private: + read(void) = default; + }; + + public: struct write + { + bool int8(u64 addr, i8 value); + inline bool int8(i8 value) { return int8(0, value); } + bool uint8(u64 addr, u8 value); + inline bool uint8(i8 value) { return uint8(0, value); } + + bool int16(u64 addr, i16 value); + inline bool int16(i8 value) { return int16(0, value); } + bool uint16(u64 addr, u16 value); + inline bool uint16(i8 value) { return uint16(0, value); } + + bool int32(u64 addr, i32 value); + inline bool int32(i8 value) { return int32(0, value); } + bool uint32(u64 addr, u32 value); + inline bool uint32(i8 value) { return uint32(0, value); } + + bool int64(u64 addr, i64 value); + inline bool int64(i8 value) { return int64(0, value); } + bool uint64(u64 addr, u64 value); + inline bool uint64(i8 value) { return uint64(0, value); } + + bool float32(u64 addr, f32 value); + inline bool float32(i8 value) { return float32(0, value); } + bool float64(u64 addr, f64 value); + inline bool float64(i8 value) { return float64(0, value); } + + bool stream(u64 addr, const Stream& value, bool storeSize = true); + inline bool stream(const Stream& value, bool storeSize = true) { return stream(0, value, storeSize); } + bool string(u64 addr, const String& value, bool storeSize = true, bool null_terminated = false); // if sizeStored, null_terminated will be ignored + inline bool string(const String& value, bool storeSize = true, bool null_terminated = false) { return string(0, value, storeSize, null_terminated); } + bool object(u64 addr, const __i_serializable& value); + inline bool object(const __i_serializable& value) { return object(0, value); } + + private: + write(void) = default; + }; + + private: + Serial(void) = default; + inline static void managed_address_check(u64& addr) { if (isManagedAddressEnabled()) addr = s_addr; } + + private: + inline static StreamEdit s_openStream { }; + inline static Endianness s_endianness { Endianness::LittleEndian }; + + inline static u64 s_addr { 0 }; + inline static bool s_managedAddress { false }; + }; + class __i_serializable + { + public: + virtual Serial::Stream serialize(void) const = 0; + virtual bool deserialize(const Serial::Stream& data) = 0; + }; + + + + + + // =============================================== OLD VERSION =============================================== + class OutputHandlerBase; namespace serial { class SerialIO