The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
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.

257 lines
10KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2022 - Raw Material Software Limited
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 7 End-User License
  8. Agreement and JUCE Privacy Policy.
  9. End User License Agreement: www.juce.com/juce-7-licence
  10. Privacy Policy: www.juce.com/juce-privacy-policy
  11. Or: You may also use this code under the terms of the GPL v3 (see
  12. www.gnu.org/licenses).
  13. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  14. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  15. DISCLAIMED.
  16. ==============================================================================
  17. */
  18. namespace juce::midi_ci
  19. {
  20. struct PropertyDelegateDetail
  21. {
  22. /*
  23. Note: We don't use ToVar and FromVar here, because we want to omit fields that are using
  24. their default values.
  25. */
  26. template <typename Target>
  27. static Target parseTargetHeader (const var& v,
  28. const std::map<Identifier, void (*) (Target&, const var&)>& parsers)
  29. {
  30. Target target;
  31. if (auto* obj = v.getDynamicObject())
  32. {
  33. for (const auto& pair : obj->getProperties())
  34. {
  35. const auto parserIter = parsers.find (pair.name);
  36. if (parserIter != parsers.end())
  37. parserIter->second (target, pair.value);
  38. else
  39. target.extended[pair.name] = pair.value;
  40. }
  41. }
  42. return target;
  43. }
  44. static auto getParsersForPropertyReplyHeader()
  45. {
  46. using Target = PropertyReplyHeader;
  47. std::map<Identifier, void (*) (Target& header, const var& v)> map;
  48. map.emplace ("status", [] (Target& header, const var& v) { header.status = v; });
  49. map.emplace ("message", [] (Target& header, const var& v) { header.message = v; });
  50. map.emplace ("cacheTime", [] (Target& header, const var& v) { header.cacheTime = v; });
  51. map.emplace ("mediaType", [] (Target& header, const var& v) { header.mediaType = v; });
  52. map.emplace ("mutualEncoding", [] (Target& header, const var& v)
  53. {
  54. header.mutualEncoding = EncodingUtils::toEncoding (v.toString().toRawUTF8()).value_or (Encoding::ascii);
  55. });
  56. return map;
  57. }
  58. template <typename Target>
  59. static auto getParsersForGenericPropertyRequestHeader()
  60. {
  61. std::map<Identifier, void (*) (Target& header, const var& v)> map;
  62. map.emplace ("resource", [] (Target& header, const var& v) { header.resource = v; });
  63. map.emplace ("resId", [] (Target& header, const var& v) { header.resId = v; });
  64. map.emplace ("mediaType", [] (Target& header, const var& v) { header.mediaType = v; });
  65. map.emplace ("mutualEncoding", [] (Target& header, const var& v)
  66. {
  67. header.mutualEncoding = EncodingUtils::toEncoding (v.toString().toRawUTF8()).value_or (Encoding::ascii);
  68. });
  69. return map;
  70. }
  71. static auto getParsersForPropertyRequestHeader()
  72. {
  73. auto map = getParsersForGenericPropertyRequestHeader<PropertyRequestHeader>();
  74. map.emplace ("setPartial", [] (PropertyRequestHeader& header, const var& v) { header.setPartial = v; });
  75. map.emplace ("offset", [] (PropertyRequestHeader& header, const var& v)
  76. {
  77. if (! header.pagination.has_value())
  78. header.pagination = Pagination{};
  79. header.pagination->offset = v;
  80. });
  81. map.emplace ("limit", [] (PropertyRequestHeader& header, const var& v)
  82. {
  83. if (! header.pagination.has_value())
  84. header.pagination = Pagination{};
  85. header.pagination->limit = v;
  86. });
  87. return map;
  88. }
  89. static auto getParsersForPropertySubscriptionHeader()
  90. {
  91. auto map = getParsersForGenericPropertyRequestHeader<PropertySubscriptionHeader>();
  92. map.emplace ("subscribeId", [] (PropertySubscriptionHeader& header, const var& v) { header.subscribeId = v; });
  93. map.emplace ("command", [] (PropertySubscriptionHeader& header, const var& v)
  94. {
  95. header.command = [&]
  96. {
  97. if (v == "start")
  98. return PropertySubscriptionCommand::start;
  99. if (v == "partial")
  100. return PropertySubscriptionCommand::partial;
  101. if (v == "full")
  102. return PropertySubscriptionCommand::full;
  103. if (v == "notify")
  104. return PropertySubscriptionCommand::notify;
  105. if (v == "end")
  106. return PropertySubscriptionCommand::end;
  107. return PropertySubscriptionCommand::notify;
  108. }();
  109. });
  110. return map;
  111. }
  112. static auto getSetPartial (const PropertySubscriptionHeader&) { return false; }
  113. static auto getSetPartial (const PropertyRequestHeader& h) { return h.setPartial; }
  114. static auto getSetPartial (const PropertyReplyHeader&) { return false; }
  115. static auto getPagination (const PropertySubscriptionHeader&) { return std::optional<Pagination>{}; }
  116. static auto getPagination (const PropertyRequestHeader& h) { return h.pagination; }
  117. static auto getPagination (const PropertyReplyHeader&) { return std::optional<Pagination>{}; }
  118. static auto getCacheTime (const PropertySubscriptionHeader&) { return 0; }
  119. static auto getCacheTime (const PropertyRequestHeader&) { return 0; }
  120. static auto getCacheTime (const PropertyReplyHeader& h) { return h.cacheTime; }
  121. static auto getMessage (const PropertySubscriptionHeader&) { return String{}; }
  122. static auto getMessage (const PropertyRequestHeader&) { return String{}; }
  123. static auto getMessage (const PropertyReplyHeader& h) { return h.message; }
  124. static auto getResource (const PropertySubscriptionHeader& h) { return h.resource; }
  125. static auto getResource (const PropertyRequestHeader& h) { return h.resource; }
  126. static auto getResource (const PropertyReplyHeader&) { return String{}; }
  127. static auto getResId (const PropertySubscriptionHeader& h) { return h.resId; }
  128. static auto getResId (const PropertyRequestHeader& h) { return h.resId; }
  129. static auto getResId (const PropertyReplyHeader&) { return String{}; }
  130. static auto getCommand (const PropertySubscriptionHeader& h) { return h.command; }
  131. static auto getCommand (const PropertyRequestHeader&) { return PropertySubscriptionCommand{}; }
  132. static auto getCommand (const PropertyReplyHeader&) { return PropertySubscriptionCommand{}; }
  133. static auto getSubscribeId (const PropertySubscriptionHeader& h) { return h.subscribeId; }
  134. static auto getSubscribeId (const PropertyRequestHeader&) { return String{}; }
  135. static auto getSubscribeId (const PropertyReplyHeader&) { return String{}; }
  136. static std::optional<int> getStatus (const PropertySubscriptionHeader&) { return {}; }
  137. static std::optional<int> getStatus (const PropertyRequestHeader&) { return {}; }
  138. static std::optional<int> getStatus (const PropertyReplyHeader& h) { return h.status; }
  139. template <typename T>
  140. static auto toFieldsFromHeader (const T& t)
  141. {
  142. auto fields = t.extended;
  143. // Status shall always be included if it is present in the header
  144. if (const auto status = getStatus (t))
  145. fields["status"] = *status;
  146. if (getResource (t) != getResource (T()))
  147. fields["resource"] = getResource (t);
  148. if (getCommand (t) != getCommand (T()))
  149. fields["command"] = PropertySubscriptionCommandUtils::toString (getCommand (t));
  150. if (getSubscribeId (t) != getSubscribeId (T()))
  151. fields["subscribeId"] = getSubscribeId (t);
  152. if (getResId (t) != getResId (T()))
  153. fields["resId"] = getResId (t);
  154. if (t.mutualEncoding != T().mutualEncoding)
  155. fields["mutualEncoding"] = EncodingUtils::toString (t.mutualEncoding);
  156. if (t.mediaType != T().mediaType)
  157. fields["mediaType"] = t.mediaType;
  158. if (getSetPartial (t))
  159. fields["setPartial"] = true;
  160. if (getCacheTime (t) != getCacheTime (T()))
  161. fields["cacheTime"] = getCacheTime (t);
  162. if (getMessage (t) != getMessage (T()))
  163. fields["message"] = getMessage (t);
  164. if (const auto pagination = getPagination (t))
  165. {
  166. fields["offset"] = pagination->offset;
  167. fields["limit"] = pagination->limit;
  168. }
  169. return fields;
  170. }
  171. };
  172. //==============================================================================
  173. PropertySubscriptionHeader PropertySubscriptionHeader::parseCondensed (const var& v)
  174. {
  175. return PropertyDelegateDetail::parseTargetHeader (v, PropertyDelegateDetail::getParsersForPropertySubscriptionHeader());
  176. }
  177. var PropertySubscriptionHeader::toVarCondensed() const
  178. {
  179. return JSONUtils::makeObjectWithKeyFirst (PropertyDelegateDetail::toFieldsFromHeader (*this), "command");
  180. }
  181. PropertyRequestHeader PropertyRequestHeader::parseCondensed (const var& v)
  182. {
  183. return PropertyDelegateDetail::parseTargetHeader (v, PropertyDelegateDetail::getParsersForPropertyRequestHeader());
  184. }
  185. var PropertyRequestHeader::toVarCondensed() const
  186. {
  187. return JSONUtils::makeObjectWithKeyFirst (PropertyDelegateDetail::toFieldsFromHeader (*this), "resource");
  188. }
  189. PropertyReplyHeader PropertyReplyHeader::parseCondensed (const var& v)
  190. {
  191. return PropertyDelegateDetail::parseTargetHeader (v, PropertyDelegateDetail::getParsersForPropertyReplyHeader());
  192. }
  193. var PropertyReplyHeader::toVarCondensed() const
  194. {
  195. return JSONUtils::makeObjectWithKeyFirst (PropertyDelegateDetail::toFieldsFromHeader (*this), "status");
  196. }
  197. } // namespace juce::midi_ci