Encoder.h 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. /*
  2. * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
  3. * Copyright (c) 2023, Tim Flynn <trflynn89@serenityos.org>
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #pragma once
  8. #include <AK/Concepts.h>
  9. #include <AK/HashMap.h>
  10. #include <AK/StdLibExtras.h>
  11. #include <AK/Variant.h>
  12. #include <LibCore/SharedCircularQueue.h>
  13. #include <LibIPC/Concepts.h>
  14. #include <LibIPC/Forward.h>
  15. #include <LibIPC/Message.h>
  16. namespace IPC {
  17. template<typename T>
  18. ErrorOr<void> encode(Encoder&, T const&)
  19. {
  20. static_assert(DependentFalse<T>, "Base IPC::encode() was instantiated");
  21. VERIFY_NOT_REACHED();
  22. }
  23. class Encoder {
  24. public:
  25. explicit Encoder(MessageBuffer& buffer)
  26. : m_buffer(buffer)
  27. {
  28. }
  29. template<typename T>
  30. ErrorOr<void> encode(T const& value);
  31. ErrorOr<void> extend_capacity(size_t capacity)
  32. {
  33. TRY(m_buffer.extend_data_capacity(capacity));
  34. return {};
  35. }
  36. ErrorOr<void> append(u8 const* values, size_t count)
  37. {
  38. TRY(m_buffer.append_data(values, count));
  39. return {};
  40. }
  41. ErrorOr<void> append_file_descriptor(int fd)
  42. {
  43. TRY(m_buffer.append_file_descriptor(fd));
  44. return {};
  45. }
  46. ErrorOr<void> encode_size(size_t size);
  47. private:
  48. MessageBuffer& m_buffer;
  49. };
  50. template<Arithmetic T>
  51. ErrorOr<void> encode(Encoder& encoder, T const& value)
  52. {
  53. TRY(encoder.append(reinterpret_cast<u8 const*>(&value), sizeof(value)));
  54. return {};
  55. }
  56. template<Enum T>
  57. ErrorOr<void> encode(Encoder& encoder, T const& value)
  58. {
  59. return encoder.encode(to_underlying(value));
  60. }
  61. template<>
  62. ErrorOr<void> encode(Encoder&, float const&);
  63. template<>
  64. ErrorOr<void> encode(Encoder&, double const&);
  65. template<>
  66. ErrorOr<void> encode(Encoder&, String const&);
  67. template<>
  68. ErrorOr<void> encode(Encoder&, StringView const&);
  69. template<>
  70. ErrorOr<void> encode(Encoder&, ByteString const&);
  71. template<>
  72. ErrorOr<void> encode(Encoder&, ByteBuffer const&);
  73. template<>
  74. ErrorOr<void> encode(Encoder&, JsonValue const&);
  75. template<>
  76. ErrorOr<void> encode(Encoder&, Duration const&);
  77. template<>
  78. ErrorOr<void> encode(Encoder&, UnixDateTime const&);
  79. template<>
  80. ErrorOr<void> encode(Encoder&, URL const&);
  81. template<>
  82. ErrorOr<void> encode(Encoder&, File const&);
  83. template<>
  84. ErrorOr<void> encode(Encoder&, Empty const&);
  85. template<Concepts::Vector T>
  86. ErrorOr<void> encode(Encoder& encoder, T const& vector)
  87. {
  88. // NOTE: Do not change this encoding without also updating LibC/netdb.cpp.
  89. TRY(encoder.encode_size(vector.size()));
  90. for (auto const& value : vector)
  91. TRY(encoder.encode(value));
  92. return {};
  93. }
  94. template<Concepts::HashMap T>
  95. ErrorOr<void> encode(Encoder& encoder, T const& hashmap)
  96. {
  97. TRY(encoder.encode_size(hashmap.size()));
  98. for (auto it : hashmap) {
  99. TRY(encoder.encode(it.key));
  100. TRY(encoder.encode(it.value));
  101. }
  102. return {};
  103. }
  104. template<Concepts::SharedSingleProducerCircularQueue T>
  105. ErrorOr<void> encode(Encoder& encoder, T const& queue)
  106. {
  107. return encoder.encode(IPC::File { queue.fd() });
  108. }
  109. template<Concepts::Optional T>
  110. ErrorOr<void> encode(Encoder& encoder, T const& optional)
  111. {
  112. TRY(encoder.encode(optional.has_value()));
  113. if (optional.has_value())
  114. TRY(encoder.encode(optional.value()));
  115. return {};
  116. }
  117. template<Concepts::Variant T>
  118. ErrorOr<void> encode(Encoder& encoder, T const& variant)
  119. {
  120. TRY(encoder.encode(variant.index()));
  121. return variant.visit([&](auto const& value) {
  122. return encoder.encode(value);
  123. });
  124. }
  125. // This must be last so that it knows about the above specializations.
  126. template<typename T>
  127. ErrorOr<void> Encoder::encode(T const& value)
  128. {
  129. return IPC::encode(*this, value);
  130. }
  131. }