/* This file is part of the Arduino_RPClite library. Copyright (C) Arduino s.r.l. and/or its affiliated companies This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #pragma once #ifndef RPCLITE_UTILS_H #define RPCLITE_UTILS_H #include #include namespace RpcUtils { namespace detail { #define TYPE_ERROR (-1) #define WRONG_MSG (-2) #define NO_MSG (-1) #define CALL_MSG 0 #define RESP_MSG 1 #define NOTIFY_MSG 2 #define REQUEST_SIZE 4 #define RESPONSE_SIZE 4 #define NOTIFY_SIZE 3 /////////////////////////////////////// /// --- deserialization helpers --- /// /////////////////////////////////////// inline bool isValidRpc(int type, size_t size) { switch (type) { case CALL_MSG: return size == REQUEST_SIZE; case RESP_MSG: return size == RESPONSE_SIZE; case NOTIFY_MSG: return size == NOTIFY_SIZE; default: return false; } } inline bool unpackObject(MsgPack::Unpacker& unpacker); inline bool unpackTypedArray(MsgPack::Unpacker& unpacker, size_t& size, int& type) { MsgPack::arr_size_t sz; if (!unpacker.deserialize(sz)) return false; size = sz.size(); type = WRONG_MSG; for (size_t i = 0; i < sz.size(); i++) { if (i==0 && unpacker.deserialize(type)) { continue; } if (!unpackObject(unpacker)) return false; } return true; } inline bool unpackArray(MsgPack::Unpacker& unpacker, size_t& size) { if (!unpacker.isArray()) { return false; // Not an array } MsgPack::arr_size_t sz; unpacker.deserialize(sz); size = 0; for (size_t i=0; i bytes; return unpacker.deserialize(bytes); } if (unpacker.isArray()){ static size_t arr_sz; return unpackArray(unpacker, arr_sz); } if (unpacker.isMap()){ static size_t map_sz; return unpackMap(unpacker, map_sz); } if (unpacker.isFixExt() || unpacker.isExt()){ static MsgPack::object::ext e; return unpacker.deserialize(e); } if (unpacker.isTimestamp()){ static MsgPack::object::timespec t; return unpacker.deserialize(t); } return false; } template int deserialize_single(MsgPack::Unpacker& unpacker, T& value) { if (!unpacker.unpackable(value)) return TYPE_ERROR; unpacker.deserialize(value); return 0; } ///////////////////////////// /// --- tuple helpers --- /// ///////////////////////////// template typename std::enable_if::type deserialize_tuple(MsgPack::Unpacker&, std::tuple&) { return 0; } template typename std::enable_if::type deserialize_tuple(MsgPack::Unpacker& unpacker, std::tuple& out) { const int res = deserialize_single(unpacker, std::get(out)); if (res==TYPE_ERROR) return TYPE_ERROR-I; return deserialize_tuple(unpacker, out); } // Helper to invoke a function with a tuple of arguments template auto invoke_with_tuple(F&& f, Tuple&& t, arx::stdx::index_sequence) -> decltype(f(std::get(std::forward(t))...)) { return f(std::get(std::forward(t))...); } } // namespace detail } // namespace RpcUtils #endif //RPCLITE_UTILS_H