/* * Copyright (c) 2020, Andreas Kling * Copyright (c) 2023, Tim Flynn * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace IPC { template inline ErrorOr decode(Decoder&) { static_assert(DependentFalse, "Base IPC::decoder() instantiated"); VERIFY_NOT_REACHED(); } class Decoder { public: Decoder(Stream& stream, Core::LocalSocket& socket) : m_stream(stream) , m_socket(socket) { } template ErrorOr decode(); template ErrorOr decode_into(T& value) { value = TRY(m_stream.read_value()); return {}; } ErrorOr decode_into(Bytes bytes) { TRY(m_stream.read_until_filled(bytes)); return {}; } ErrorOr decode_size(); Stream& stream() { return m_stream; } Core::LocalSocket& socket() { return m_socket; } private: Stream& m_stream; Core::LocalSocket& m_socket; }; template ErrorOr decode(Decoder& decoder) { T value { 0 }; TRY(decoder.decode_into(value)); return value; } template ErrorOr decode(Decoder& decoder) { auto value = TRY(decoder.decode>()); return static_cast(value); } template<> ErrorOr decode(Decoder&); template<> ErrorOr decode(Decoder&); template<> ErrorOr decode(Decoder&); template<> ErrorOr decode(Decoder&); template<> ErrorOr decode(Decoder&); template<> ErrorOr decode(Decoder&); template<> ErrorOr decode(Decoder&); template<> ErrorOr decode(Decoder&); template<> ErrorOr decode(Decoder&); template ErrorOr decode(Decoder& decoder) { T array {}; auto size = TRY(decoder.decode_size()); if (size != array.size()) return Error::from_string_literal("Array size mismatch"); for (size_t i = 0; i < array.size(); ++i) array[i] = TRY(decoder.decode()); return array; } template ErrorOr decode(Decoder& decoder) { T vector; auto size = TRY(decoder.decode_size()); TRY(vector.try_ensure_capacity(size)); for (size_t i = 0; i < size; ++i) { auto value = TRY(decoder.decode()); vector.template unchecked_append(move(value)); } return vector; } template ErrorOr decode(Decoder& decoder) { T hashmap; auto size = TRY(decoder.decode_size()); TRY(hashmap.try_ensure_capacity(size)); for (size_t i = 0; i < size; ++i) { auto key = TRY(decoder.decode()); auto value = TRY(decoder.decode()); TRY(hashmap.try_set(move(key), move(value))); } return hashmap; } template ErrorOr decode(Decoder& decoder) { auto anon_file = TRY(decoder.decode()); return T::create(anon_file.take_fd()); } template ErrorOr decode(Decoder& decoder) { if (auto has_value = TRY(decoder.decode()); !has_value) return T {}; return T { TRY(decoder.decode()) }; } namespace Detail { template ErrorOr decode_variant(Decoder& decoder, size_t index) { using ElementList = TypeList; if constexpr (Index < ElementList::size) { if (index == Index) { using ElementType = typename ElementList::template Type; return T { TRY(decoder.decode()) }; } return decode_variant(decoder, index); } else { VERIFY_NOT_REACHED(); } } } template ErrorOr decode(Decoder& decoder) { auto index = TRY(decoder.decode()); return Detail::decode_variant(decoder, index); } // This must be last so that it knows about the above specializations. template ErrorOr Decoder::decode() { return IPC::decode(*this); } }