|
@@ -9,6 +9,7 @@
|
|
|
#include <AK/Concepts.h>
|
|
|
#include <AK/DeprecatedString.h>
|
|
|
#include <AK/Forward.h>
|
|
|
+#include <AK/MemoryStream.h>
|
|
|
#include <AK/NumericLimits.h>
|
|
|
#include <AK/StdLibExtras.h>
|
|
|
#include <AK/Try.h>
|
|
@@ -16,6 +17,7 @@
|
|
|
#include <AK/Variant.h>
|
|
|
#include <LibCore/SharedCircularQueue.h>
|
|
|
#include <LibCore/Stream.h>
|
|
|
+#include <LibIPC/Concepts.h>
|
|
|
#include <LibIPC/File.h>
|
|
|
#include <LibIPC/Forward.h>
|
|
|
#include <LibIPC/Message.h>
|
|
@@ -23,7 +25,7 @@
|
|
|
namespace IPC {
|
|
|
|
|
|
template<typename T>
|
|
|
-inline ErrorOr<void> decode(Decoder&, T&)
|
|
|
+inline ErrorOr<T> decode(Decoder&)
|
|
|
{
|
|
|
static_assert(DependentFalse<T>, "Base IPC::decoder() instantiated");
|
|
|
VERIFY_NOT_REACHED();
|
|
@@ -37,151 +39,144 @@ public:
|
|
|
{
|
|
|
}
|
|
|
|
|
|
- ErrorOr<void> decode(bool&);
|
|
|
- ErrorOr<void> decode(u8&);
|
|
|
- ErrorOr<void> decode(u16&);
|
|
|
- ErrorOr<void> decode(unsigned&);
|
|
|
- ErrorOr<void> decode(unsigned long&);
|
|
|
- ErrorOr<void> decode(unsigned long long&);
|
|
|
- ErrorOr<void> decode(i8&);
|
|
|
- ErrorOr<void> decode(i16&);
|
|
|
- ErrorOr<void> decode(i32&);
|
|
|
- ErrorOr<void> decode(i64&);
|
|
|
- ErrorOr<void> decode(float&);
|
|
|
- ErrorOr<void> decode(double&);
|
|
|
- ErrorOr<void> decode(DeprecatedString&);
|
|
|
- ErrorOr<void> decode(ByteBuffer&);
|
|
|
- ErrorOr<void> decode(JsonValue&);
|
|
|
- ErrorOr<void> decode(URL&);
|
|
|
- ErrorOr<void> decode(Dictionary&);
|
|
|
- ErrorOr<void> decode(File&);
|
|
|
- ErrorOr<void> decode(AK::Empty&);
|
|
|
- template<typename K, typename V>
|
|
|
- ErrorOr<void> decode(HashMap<K, V>& hashmap)
|
|
|
- {
|
|
|
- u32 size;
|
|
|
- TRY(decode(size));
|
|
|
- if (size > NumericLimits<i32>::max())
|
|
|
- return Error::from_string_literal("IPC: Invalid HashMap size");
|
|
|
-
|
|
|
- for (size_t i = 0; i < size; ++i) {
|
|
|
- K key;
|
|
|
- TRY(decode(key));
|
|
|
- V value;
|
|
|
- TRY(decode(value));
|
|
|
- TRY(hashmap.try_set(move(key), move(value)));
|
|
|
- }
|
|
|
- return {};
|
|
|
- }
|
|
|
+ template<typename T>
|
|
|
+ ErrorOr<T> decode();
|
|
|
|
|
|
- template<typename K, typename V>
|
|
|
- ErrorOr<void> decode(OrderedHashMap<K, V>& hashmap)
|
|
|
+ template<typename T>
|
|
|
+ ErrorOr<void> decode_into(T& value)
|
|
|
{
|
|
|
- u32 size;
|
|
|
- TRY(decode(size));
|
|
|
- if (size > NumericLimits<i32>::max())
|
|
|
- return Error::from_string_literal("IPC: Invalid HashMap size");
|
|
|
-
|
|
|
- for (size_t i = 0; i < size; ++i) {
|
|
|
- K key;
|
|
|
- TRY(decode(key));
|
|
|
- V value;
|
|
|
- TRY(decode(value));
|
|
|
- TRY(hashmap.try_set(move(key), move(value)));
|
|
|
- }
|
|
|
+ m_stream >> value;
|
|
|
+ TRY(m_stream.try_handle_any_error());
|
|
|
return {};
|
|
|
}
|
|
|
|
|
|
- template<Enum T>
|
|
|
- ErrorOr<void> decode(T& enum_value)
|
|
|
- {
|
|
|
- UnderlyingType<T> inner_value;
|
|
|
- TRY(decode(inner_value));
|
|
|
- enum_value = T(inner_value);
|
|
|
- return {};
|
|
|
- }
|
|
|
+ Core::Stream::LocalSocket& socket() { return m_socket; }
|
|
|
|
|
|
- template<typename T>
|
|
|
- ErrorOr<void> decode(T& value)
|
|
|
- {
|
|
|
- return IPC::decode(*this, value);
|
|
|
- }
|
|
|
+private:
|
|
|
+ InputMemoryStream& m_stream;
|
|
|
+ Core::Stream::LocalSocket& m_socket;
|
|
|
+};
|
|
|
|
|
|
- template<typename T>
|
|
|
- ErrorOr<void> decode(Vector<T>& vector)
|
|
|
- {
|
|
|
- u64 size;
|
|
|
- TRY(decode(size));
|
|
|
- if (size > NumericLimits<i32>::max())
|
|
|
- return Error::from_string_literal("IPC: Invalid Vector size");
|
|
|
- VERIFY(vector.is_empty());
|
|
|
- TRY(vector.try_ensure_capacity(size));
|
|
|
- for (size_t i = 0; i < size; ++i) {
|
|
|
- T value;
|
|
|
- TRY(decode(value));
|
|
|
- vector.template unchecked_append(move(value));
|
|
|
- }
|
|
|
- return {};
|
|
|
- }
|
|
|
+template<Arithmetic T>
|
|
|
+ErrorOr<T> decode(Decoder& decoder)
|
|
|
+{
|
|
|
+ T value { 0 };
|
|
|
+ TRY(decoder.decode_into(value));
|
|
|
+ return value;
|
|
|
+}
|
|
|
|
|
|
- template<typename T, size_t Size>
|
|
|
- ErrorOr<void> decode(Core::SharedSingleProducerCircularQueue<T, Size>& queue)
|
|
|
- {
|
|
|
- // FIXME: We don't support decoding into valid queues.
|
|
|
- VERIFY(!queue.is_valid());
|
|
|
+template<Enum T>
|
|
|
+ErrorOr<T> decode(Decoder& decoder)
|
|
|
+{
|
|
|
+ auto value = TRY(decoder.decode<UnderlyingType<T>>());
|
|
|
+ return static_cast<T>(value);
|
|
|
+}
|
|
|
|
|
|
- IPC::File anon_file;
|
|
|
- TRY(decode(anon_file));
|
|
|
- queue = TRY((Core::SharedSingleProducerCircularQueue<T, Size>::try_create(anon_file.take_fd())));
|
|
|
- return {};
|
|
|
- }
|
|
|
+template<>
|
|
|
+ErrorOr<DeprecatedString> decode(Decoder&);
|
|
|
|
|
|
- template<typename... VariantTypes>
|
|
|
- ErrorOr<void> decode(Variant<VariantTypes...>& variant)
|
|
|
- {
|
|
|
- typename AK::Variant<VariantTypes...>::IndexType type_index;
|
|
|
- TRY(decode(type_index));
|
|
|
- if (type_index >= sizeof...(VariantTypes))
|
|
|
- return Error::from_string_literal("IPC: Invalid variant index");
|
|
|
+template<>
|
|
|
+ErrorOr<ByteBuffer> decode(Decoder&);
|
|
|
|
|
|
- TRY((decode_variant<0, sizeof...(VariantTypes), VariantTypes...>(type_index, variant)));
|
|
|
- return {};
|
|
|
+template<>
|
|
|
+ErrorOr<JsonValue> decode(Decoder&);
|
|
|
+
|
|
|
+template<>
|
|
|
+ErrorOr<URL> decode(Decoder&);
|
|
|
+
|
|
|
+template<>
|
|
|
+ErrorOr<Dictionary> decode(Decoder&);
|
|
|
+
|
|
|
+template<>
|
|
|
+ErrorOr<File> decode(Decoder&);
|
|
|
+
|
|
|
+template<>
|
|
|
+ErrorOr<Empty> decode(Decoder&);
|
|
|
+
|
|
|
+template<Concepts::Vector T>
|
|
|
+ErrorOr<T> decode(Decoder& decoder)
|
|
|
+{
|
|
|
+ auto size = TRY(decoder.decode<u64>());
|
|
|
+ if (size > NumericLimits<i32>::max())
|
|
|
+ return Error::from_string_literal("IPC: Invalid Vector size");
|
|
|
+
|
|
|
+ T vector;
|
|
|
+ TRY(vector.try_ensure_capacity(size));
|
|
|
+
|
|
|
+ for (size_t i = 0; i < size; ++i) {
|
|
|
+ auto value = TRY(decoder.decode<typename T::ValueType>());
|
|
|
+ vector.template unchecked_append(move(value));
|
|
|
}
|
|
|
|
|
|
- template<typename T>
|
|
|
- ErrorOr<void> decode(Optional<T>& optional)
|
|
|
- {
|
|
|
- bool has_value;
|
|
|
- TRY(decode(has_value));
|
|
|
- if (!has_value) {
|
|
|
- optional = {};
|
|
|
- return {};
|
|
|
- }
|
|
|
- T value;
|
|
|
- TRY(decode(value));
|
|
|
- optional = move(value);
|
|
|
- return {};
|
|
|
+ return vector;
|
|
|
+}
|
|
|
+
|
|
|
+template<Concepts::HashMap T>
|
|
|
+ErrorOr<T> decode(Decoder& decoder)
|
|
|
+{
|
|
|
+ auto size = TRY(decoder.decode<u32>());
|
|
|
+ if (size > NumericLimits<i32>::max())
|
|
|
+ return Error::from_string_literal("IPC: Invalid HashMap size");
|
|
|
+
|
|
|
+ T hashmap;
|
|
|
+
|
|
|
+ for (size_t i = 0; i < size; ++i) {
|
|
|
+ auto key = TRY(decoder.decode<typename T::KeyType>());
|
|
|
+ auto value = TRY(decoder.decode<typename T::ValueType>());
|
|
|
+ TRY(hashmap.try_set(move(key), move(value)));
|
|
|
}
|
|
|
|
|
|
-private:
|
|
|
- template<size_t CurrentIndex, size_t Max, typename... VariantTypes>
|
|
|
- ErrorOr<void> decode_variant(size_t index, Variant<VariantTypes...>& variant)
|
|
|
- {
|
|
|
- if constexpr (CurrentIndex < Max) {
|
|
|
- if (index == CurrentIndex) {
|
|
|
- typename TypeList<VariantTypes...>::template Type<CurrentIndex> element;
|
|
|
- TRY(decode(element));
|
|
|
- variant.set(move(element));
|
|
|
- return {};
|
|
|
- }
|
|
|
- return decode_variant<CurrentIndex + 1, Max, VariantTypes...>(index, variant);
|
|
|
- } else {
|
|
|
- VERIFY_NOT_REACHED();
|
|
|
+ return hashmap;
|
|
|
+}
|
|
|
+
|
|
|
+template<Concepts::SharedSingleProducerCircularQueue T>
|
|
|
+ErrorOr<T> decode(Decoder& decoder)
|
|
|
+{
|
|
|
+ auto anon_file = TRY(decoder.decode<IPC::File>());
|
|
|
+ return T::try_create(anon_file.take_fd());
|
|
|
+}
|
|
|
+
|
|
|
+template<Concepts::Optional T>
|
|
|
+ErrorOr<T> decode(Decoder& decoder)
|
|
|
+{
|
|
|
+ if (auto has_value = TRY(decoder.decode<bool>()); !has_value)
|
|
|
+ return T {};
|
|
|
+ return T { TRY(decoder.decode<typename T::ValueType>()) };
|
|
|
+}
|
|
|
+
|
|
|
+namespace Detail {
|
|
|
+
|
|
|
+template<Concepts::Variant T, size_t Index = 0>
|
|
|
+ErrorOr<T> decode_variant(Decoder& decoder, size_t index)
|
|
|
+{
|
|
|
+ using ElementList = TypeList<T>;
|
|
|
+
|
|
|
+ if constexpr (Index < ElementList::size) {
|
|
|
+ if (index == Index) {
|
|
|
+ using ElementType = typename ElementList::template Type<Index>;
|
|
|
+ return T { TRY(decoder.decode<ElementType>()) };
|
|
|
}
|
|
|
+
|
|
|
+ return decode_variant<T, Index + 1>(decoder, index);
|
|
|
+ } else {
|
|
|
+ VERIFY_NOT_REACHED();
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
- InputMemoryStream& m_stream;
|
|
|
- Core::Stream::LocalSocket& m_socket;
|
|
|
-};
|
|
|
+}
|
|
|
+
|
|
|
+template<Concepts::Variant T>
|
|
|
+ErrorOr<T> decode(Decoder& decoder)
|
|
|
+{
|
|
|
+ auto index = TRY(decoder.decode<typename T::IndexType>());
|
|
|
+ return Detail::decode_variant<T>(decoder, index);
|
|
|
+}
|
|
|
+
|
|
|
+// This must be last so that it knows about the above specializations.
|
|
|
+template<typename T>
|
|
|
+ErrorOr<T> Decoder::decode()
|
|
|
+{
|
|
|
+ return IPC::decode<T>(*this);
|
|
|
+}
|
|
|
|
|
|
}
|