Convert.cpp 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. // Copyright (c) 2013-2017 Josh Blum
  2. // SPDX-License-Identifier: BSL-1.0
  3. #include <Pothos/Proxy/Environment.hpp>
  4. #include <Pothos/Proxy/Handle.hpp>
  5. #include <Pothos/Proxy/Exception.hpp>
  6. #include <Pothos/Util/SpinLockRW.hpp>
  7. #include <Pothos/Util/TypeInfo.hpp>
  8. #include <Pothos/Callable.hpp>
  9. #include <Pothos/Plugin.hpp>
  10. #include <Poco/Logger.h>
  11. #include <Poco/Hash.h>
  12. #include <iostream>
  13. #include <cassert>
  14. #include <mutex>
  15. #include <map>
  16. /***********************************************************************
  17. * Global map structure for conversions
  18. **********************************************************************/
  19. static Pothos::Util::SpinLockRW &getMapToLocalMutex(void)
  20. {
  21. static Pothos::Util::SpinLockRW lock;
  22. return lock;
  23. }
  24. static Pothos::Util::SpinLockRW &getMapToProxyMutex(void)
  25. {
  26. static Pothos::Util::SpinLockRW lock;
  27. return lock;
  28. }
  29. typedef std::map<size_t, Pothos::Plugin> ConvertMapType;
  30. static ConvertMapType &getConvertToLocalMap(void)
  31. {
  32. static ConvertMapType map;
  33. return map;
  34. }
  35. static ConvertMapType &getConvertToProxyMap(void)
  36. {
  37. static ConvertMapType map;
  38. return map;
  39. }
  40. /***********************************************************************
  41. * hash functions
  42. **********************************************************************/
  43. static size_t hashIt(const std::string &name, const std::type_info &type)
  44. {
  45. return type.hash_code() ^ Poco::hash(name);
  46. }
  47. static size_t hashIt(const std::string &name, const std::string &type)
  48. {
  49. return Poco::hash(type) ^ Poco::hash(name);
  50. }
  51. /***********************************************************************
  52. * Validate registry entries
  53. **********************************************************************/
  54. static bool isConvertToLocal(const Pothos::Plugin &plugin)
  55. {
  56. if (plugin.getObject().type() != typeid(Pothos::ProxyConvertPair)) return false;
  57. const auto &pair = plugin.getObject().extract<Pothos::ProxyConvertPair>();
  58. const auto &callable = pair.second;
  59. if (callable.getNumArgs() != 1) return false;
  60. if (callable.type(0) != typeid(Pothos::Proxy)) return false;
  61. return true;
  62. }
  63. static bool isConvertToProxy(const Pothos::Plugin &plugin)
  64. {
  65. if (plugin.getObject().type() != typeid(Pothos::Callable)) return false;
  66. const auto &callable = plugin.getObject().extract<Pothos::Callable>();
  67. if (callable.getNumArgs() != 2) return false;
  68. if (callable.type(-1) != typeid(Pothos::Proxy)) return false;
  69. if (callable.type(0) != typeid(Pothos::ProxyEnvironment::Sptr)) return false;
  70. return true;
  71. }
  72. /***********************************************************************
  73. * Conversion registration handling
  74. **********************************************************************/
  75. static void handlePluginEvent(const Pothos::Plugin &plugin, const std::string &event)
  76. {
  77. poco_debug_f2(Poco::Logger::get("Pothos.Proxy.handlePluginEvent"), "plugin %s, event %s", plugin.toString(), event);
  78. const auto &nodes = plugin.getPath().listNodes();
  79. assert(nodes.size() > 2);
  80. assert(nodes[0] == "proxy");
  81. assert(nodes[1] == "converters");
  82. const auto &name = nodes[2];
  83. POTHOS_EXCEPTION_TRY
  84. {
  85. if (isConvertToLocal(plugin))
  86. {
  87. const auto &pair = plugin.getObject().extract<Pothos::ProxyConvertPair>();
  88. std::lock_guard<Pothos::Util::SpinLockRW> lock(getMapToLocalMutex());
  89. if (event == "add")
  90. {
  91. getConvertToLocalMap()[hashIt(name, pair.first)] = plugin;
  92. }
  93. if (event == "remove")
  94. {
  95. getConvertToLocalMap()[hashIt(name, pair.first)] = Pothos::Plugin();
  96. }
  97. }
  98. else if (isConvertToProxy(plugin))
  99. {
  100. const auto &callable = plugin.getObject().extract<Pothos::Callable>();
  101. std::lock_guard<Pothos::Util::SpinLockRW> lock(getMapToProxyMutex());
  102. if (event == "add")
  103. {
  104. getConvertToProxyMap()[hashIt(name, callable.type(1))] = plugin;
  105. }
  106. if (event == "remove")
  107. {
  108. getConvertToProxyMap()[hashIt(name, callable.type(1))] = Pothos::Plugin();
  109. }
  110. }
  111. else
  112. {
  113. throw Pothos::Exception("unknown format for plugin");
  114. }
  115. }
  116. POTHOS_EXCEPTION_CATCH(const Pothos::Exception &ex)
  117. {
  118. poco_error_f3(Poco::Logger::get("Pothos.Proxy.handlePluginEvent"),
  119. "exception %s, plugin %s, event %s", ex.displayText(), plugin.toString(), event);
  120. }
  121. }
  122. /***********************************************************************
  123. * Register event handler
  124. **********************************************************************/
  125. pothos_static_block(pothosProxyConvertRegister)
  126. {
  127. Pothos::PluginRegistry::addCall("/proxy/converters", &handlePluginEvent);
  128. }
  129. /***********************************************************************
  130. * The conversion implementation
  131. **********************************************************************/
  132. Pothos::Proxy Pothos::ProxyEnvironment::convertObjectToProxy(const Pothos::Object &local)
  133. {
  134. //find the plugin in the map, it will be null if not found
  135. Pothos::Util::SpinLockRW::SharedLock lock(getMapToProxyMutex());
  136. const size_t h = hashIt(this->getName(), local.type());
  137. auto it = getConvertToProxyMap().find(h);
  138. //thow an error when the conversion is not supported
  139. if (it == getConvertToProxyMap().end()) throw Pothos::ProxyEnvironmentConvertError(
  140. "Pothos::ProxyEnvironment::convertObjectToProxy()",
  141. Poco::format("doesnt support Object of type %s to %s environment",
  142. local.getTypeString(), this->getName()));
  143. const auto &callable = it->second.getObject().extract<Pothos::Callable>();
  144. Pothos::Object args[2];
  145. args[0] = Pothos::Object(this->shared_from_this());
  146. args[1] = local;
  147. return std::move(callable.opaqueCall(args, 2).ref<Pothos::Proxy>());
  148. }
  149. Pothos::Object Pothos::ProxyEnvironment::convertProxyToObject(const Pothos::Proxy &proxy_)
  150. {
  151. //make sure proxy is in this environment
  152. Pothos::Proxy proxy = proxy_;
  153. if (proxy.getEnvironment() != this->shared_from_this())
  154. {
  155. proxy = this->convertObjectToProxy(proxy.toObject());
  156. }
  157. //find the plugin in the map, it will be null if not found
  158. Pothos::Util::SpinLockRW::SharedLock lock(getMapToLocalMutex());
  159. const size_t h = hashIt(this->getName(), proxy.getHandle()->getClassName());
  160. auto it = getConvertToLocalMap().find(h);
  161. //thow an error when the conversion is not supported
  162. if (it == getConvertToLocalMap().end()) throw Pothos::ProxyEnvironmentConvertError(
  163. "Pothos::ProxyEnvironment::convertProxyToObject()",
  164. Poco::format("doesnt support environment %s type %s to Object",
  165. this->getName(), std::string(proxy.getHandle()->getClassName())));
  166. const auto &callable = it->second.getObject().extract<Pothos::ProxyConvertPair>().second;
  167. Pothos::Object args[1];
  168. args[0] = Pothos::Object(proxy);
  169. return callable.opaqueCall(args, 1);
  170. }