Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Payload.hpp 7.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. /* Copyright 2016, Ableton AG, Berlin. All rights reserved.
  2. *
  3. * This program is free software: you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License as published by
  5. * the Free Software Foundation, either version 2 of the License, or
  6. * (at your option) any later version.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU General Public License
  14. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. *
  16. * If you would like to incorporate Link into a proprietary software application,
  17. * please contact <link-devs@ableton.com>.
  18. */
  19. #pragma once
  20. #include <ableton/discovery/NetworkByteStreamSerializable.hpp>
  21. #include <functional>
  22. #include <sstream>
  23. #include <unordered_map>
  24. namespace ableton
  25. {
  26. namespace discovery
  27. {
  28. struct PayloadEntryHeader
  29. {
  30. using Key = std::uint32_t;
  31. using Size = std::uint32_t;
  32. Key key;
  33. Size size;
  34. friend Size sizeInByteStream(const PayloadEntryHeader& header)
  35. {
  36. return sizeInByteStream(header.key) + sizeInByteStream(header.size);
  37. }
  38. template <typename It>
  39. friend It toNetworkByteStream(const PayloadEntryHeader& header, It out)
  40. {
  41. return toNetworkByteStream(
  42. header.size, toNetworkByteStream(header.key, std::move(out)));
  43. }
  44. template <typename It>
  45. static std::pair<PayloadEntryHeader, It> fromNetworkByteStream(It begin, const It end)
  46. {
  47. using namespace std;
  48. Key key;
  49. Size size;
  50. tie(key, begin) = Deserialize<Key>::fromNetworkByteStream(begin, end);
  51. tie(size, begin) = Deserialize<Size>::fromNetworkByteStream(begin, end);
  52. return make_pair(PayloadEntryHeader{move(key), move(size)}, move(begin));
  53. }
  54. };
  55. template <typename EntryType>
  56. struct PayloadEntry
  57. {
  58. PayloadEntry(EntryType entryVal)
  59. : value(std::move(entryVal))
  60. {
  61. header = {EntryType::key, sizeInByteStream(value)};
  62. }
  63. PayloadEntryHeader header;
  64. EntryType value;
  65. friend std::uint32_t sizeInByteStream(const PayloadEntry& entry)
  66. {
  67. return sizeInByteStream(entry.header) + sizeInByteStream(entry.value);
  68. }
  69. template <typename It>
  70. friend It toNetworkByteStream(const PayloadEntry& entry, It out)
  71. {
  72. return toNetworkByteStream(
  73. entry.value, toNetworkByteStream(entry.header, std::move(out)));
  74. }
  75. };
  76. namespace detail
  77. {
  78. template <typename It>
  79. using HandlerMap =
  80. std::unordered_map<typename PayloadEntryHeader::Key, std::function<void(It, It)>>;
  81. // Given an index of handlers and a byte range, parse the bytes as a
  82. // sequence of payload entries and invoke the appropriate handler for
  83. // each entry type. Entries that are encountered that do not have a
  84. // corresponding handler in the map are ignored. Throws
  85. // std::runtime_error if parsing fails for any entry. Note that if an
  86. // exception is thrown, some of the handlers may have already been called.
  87. template <typename It>
  88. void parseByteStream(HandlerMap<It>& map, It bsBegin, const It bsEnd)
  89. {
  90. using namespace std;
  91. while (bsBegin < bsEnd)
  92. {
  93. // Try to parse an entry header at this location in the byte stream
  94. PayloadEntryHeader header;
  95. It valueBegin;
  96. tie(header, valueBegin) =
  97. Deserialize<PayloadEntryHeader>::fromNetworkByteStream(bsBegin, bsEnd);
  98. // Ensure that the reported size of the entry does not exceed the
  99. // length of the byte stream
  100. It valueEnd = valueBegin + header.size;
  101. if (bsEnd < valueEnd)
  102. {
  103. throw range_error("Payload with incorrect size.");
  104. }
  105. // The next entry will start at the end of this one
  106. bsBegin = valueEnd;
  107. // Use the appropriate handler for this entry, if available
  108. auto handlerIt = map.find(header.key);
  109. if (handlerIt != end(map))
  110. {
  111. handlerIt->second(move(valueBegin), move(valueEnd));
  112. }
  113. }
  114. }
  115. } // namespace detail
  116. // Payload encoding
  117. template <typename... Entries>
  118. struct Payload;
  119. template <typename First, typename Rest>
  120. struct Payload<First, Rest>
  121. {
  122. Payload(First first, Rest rest)
  123. : mFirst(std::move(first))
  124. , mRest(std::move(rest))
  125. {
  126. }
  127. Payload(PayloadEntry<First> first, Rest rest)
  128. : mFirst(std::move(first))
  129. , mRest(std::move(rest))
  130. {
  131. }
  132. template <typename RhsFirst, typename RhsRest>
  133. using PayloadSum =
  134. Payload<First, typename Rest::template PayloadSum<RhsFirst, RhsRest>>;
  135. // Concatenate payloads together into a single payload
  136. template <typename RhsFirst, typename RhsRest>
  137. friend PayloadSum<RhsFirst, RhsRest> operator+(
  138. Payload lhs, Payload<RhsFirst, RhsRest> rhs)
  139. {
  140. return {std::move(lhs.mFirst), std::move(lhs.mRest) + std::move(rhs)};
  141. }
  142. friend std::size_t sizeInByteStream(const Payload& payload)
  143. {
  144. return sizeInByteStream(payload.mFirst) + sizeInByteStream(payload.mRest);
  145. }
  146. template <typename It>
  147. friend It toNetworkByteStream(const Payload& payload, It streamIt)
  148. {
  149. return toNetworkByteStream(
  150. payload.mRest, toNetworkByteStream(payload.mFirst, std::move(streamIt)));
  151. }
  152. PayloadEntry<First> mFirst;
  153. Rest mRest;
  154. };
  155. template <>
  156. struct Payload<>
  157. {
  158. template <typename RhsFirst, typename RhsRest>
  159. using PayloadSum = Payload<RhsFirst, RhsRest>;
  160. template <typename RhsFirst, typename RhsRest>
  161. friend PayloadSum<RhsFirst, RhsRest> operator+(Payload, Payload<RhsFirst, RhsRest> rhs)
  162. {
  163. return rhs;
  164. }
  165. friend std::size_t sizeInByteStream(const Payload&)
  166. {
  167. return 0;
  168. }
  169. template <typename It>
  170. friend It toNetworkByteStream(const Payload&, It streamIt)
  171. {
  172. return streamIt;
  173. }
  174. };
  175. template <typename... Entries>
  176. struct PayloadBuilder;
  177. // Payload factory function
  178. template <typename... Entries>
  179. auto makePayload(Entries... entries)
  180. -> decltype(PayloadBuilder<Entries...>{}(std::move(entries)...))
  181. {
  182. return PayloadBuilder<Entries...>{}(std::move(entries)...);
  183. }
  184. template <typename First, typename... Rest>
  185. struct PayloadBuilder<First, Rest...>
  186. {
  187. auto operator()(First first, Rest... rest)
  188. -> Payload<First, decltype(makePayload(std::move(rest)...))>
  189. {
  190. return {std::move(first), makePayload(std::move(rest)...)};
  191. }
  192. };
  193. template <>
  194. struct PayloadBuilder<>
  195. {
  196. Payload<> operator()()
  197. {
  198. return {};
  199. }
  200. };
  201. // Parse payloads to values
  202. template <typename... Entries>
  203. struct ParsePayload;
  204. template <typename First, typename... Rest>
  205. struct ParsePayload<First, Rest...>
  206. {
  207. template <typename It, typename... Handlers>
  208. static void parse(It begin, It end, Handlers... handlers)
  209. {
  210. detail::HandlerMap<It> map;
  211. collectHandlers(map, std::move(handlers)...);
  212. detail::parseByteStream(map, std::move(begin), std::move(end));
  213. }
  214. template <typename It, typename FirstHandler, typename... RestHandlers>
  215. static void collectHandlers(
  216. detail::HandlerMap<It>& map, FirstHandler handler, RestHandlers... rest)
  217. {
  218. using namespace std;
  219. map[First::key] = [handler](const It begin, const It end) {
  220. const auto res = First::fromNetworkByteStream(begin, end);
  221. if (res.second != end)
  222. {
  223. std::ostringstream stringStream;
  224. stringStream << "Parsing payload entry " << First::key
  225. << " did not consume the expected number of bytes. "
  226. << " Expected: " << distance(begin, end)
  227. << ", Actual: " << distance(begin, res.second);
  228. throw range_error(stringStream.str());
  229. }
  230. handler(res.first);
  231. };
  232. ParsePayload<Rest...>::collectHandlers(map, std::move(rest)...);
  233. }
  234. };
  235. template <>
  236. struct ParsePayload<>
  237. {
  238. template <typename It>
  239. static void collectHandlers(detail::HandlerMap<It>&)
  240. {
  241. }
  242. };
  243. template <typename... Entries, typename It, typename... Handlers>
  244. void parsePayload(It begin, It end, Handlers... handlers)
  245. {
  246. using namespace std;
  247. ParsePayload<Entries...>::parse(move(begin), move(end), move(handlers)...);
  248. }
  249. } // namespace discovery
  250. } // namespace ableton