1 /* 2 * Copyright (C) 2017 Open Source Robotics Foundation 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 */ 17 18 19 #ifndef IGNITION_PLUGIN_PLUGIN_HH_ 20 #define IGNITION_PLUGIN_PLUGIN_HH_ 21 22 #include <memory> 23 #include <map> 24 #include <string> 25 26 #include <ignition/utilities/SuppressWarning.hh> 27 28 #include <ignition/plugin/Export.hh> 29 #include <ignition/plugin/Info.hh> 30 31 namespace ignition 32 { 33 namespace plugin 34 { 35 // Forward declaration 36 namespace detail { template <class, class> class ComposePlugin; } 37 class EnablePluginFromThis; 38 class WeakPluginPtr; 39 40 class IGNITION_PLUGIN_VISIBLE Plugin 41 { 42 // -------------------- Public API --------------------- 43 44 /// \brief Get an interface of the specified type, if it is provided by 45 /// this plugin. 46 /// 47 /// Note that the interface pointer you receive is owned by the Plugin 48 /// object. You MUST NOT ever try to deallocate it yourself. Moreover, the 49 /// pointer will be invalidated once all Plugin objects that refer to the 50 /// same Plugin instance are destructed. Use the QueryInterfaceSharedPtr 51 /// function in order to get a reference-counting pointer to an interface 52 /// of this Plugin object. The pointer will remain valid as long as the 53 /// std::shared_ptr provided by QueryInterfaceSharedPtr is alive. 54 /// 55 /// \return A raw pointer to the specified interface. If the requested 56 /// _interfaceName is not provided by this Plugin, this returns a nullptr. 57 /// This pointer is invalidated when the reference count of the plugin 58 /// instance drops to zero. 59 public: template <class Interface> 60 Interface *QueryInterface(); 61 62 /// \brief const-qualified version of QueryInterface<Interface>() 63 public: template <class Interface> 64 const Interface *QueryInterface() const; 65 66 /// \brief This function has been deprecated in favor of the version of 67 /// QueryInterface which does not take a std::string argument. 68 public: template <class Interface> 69 IGN_DEPRECATED(0.0) 70 Interface *QueryInterface(const std::string &/*_interfaceName*/); 71 72 /// \brief const-qualified version of 73 /// QueryInterface<Interface>(std::string) 74 public: template <class Interface> 75 IGN_DEPRECATED(0.0) 76 const Interface *QueryInterface( 77 const std::string &/*_interfaceName*/) const; 78 79 /// \brief Get the requested interface as a std::shared_ptr. The template 80 /// argument Interface must exactly match the underlying type associated 81 /// with _interfaceName, or else the behavior of this function is 82 /// undefined. 83 /// 84 /// This std::shared_ptr and the interface+plugin that it refers to will 85 /// remain valid, even if all Plugin objects which refer to the plugin 86 /// instance are destructed. 87 /// 88 /// You MUST NOT attempt to pass a QueryInterface pointer into a 89 /// std::shared_ptr yourself; that will result in double-delete memory 90 /// errors. You must always call QueryInterfaceSharedPtr for a reference- 91 /// counting pointer to an interface. 92 /// 93 /// \param[in] _interfaceName The name of the desired interface, as a 94 /// string. 95 /// \return A reference-counting pointer to the specified interface. This 96 /// will keep the interface valid and the plugin instance alive, even if 97 /// all Plugin objects that refer to this plugin instance are destructed. 98 public: template <class Interface> 99 std::shared_ptr<Interface> QueryInterfaceSharedPtr(); 100 101 /// \brief Same as QueryInterfaceSharedPtr<Interface>(), but it returns a 102 /// std::shared_ptr to a const-qualified Interface. 103 public: template <class Interface> 104 std::shared_ptr<const Interface> QueryInterfaceSharedPtr() const; 105 106 /// \brief This version of QueryInterfaceSharedPtr has been deprecated in 107 /// favor of the version that does not take a std::string argument. 108 public: template <class Interface> 109 IGN_DEPRECATED(0.0) 110 std::shared_ptr<Interface> QueryInterfaceSharedPtr( 111 const std::string &/*_interfaceName*/); 112 113 /// \brief Same as QueryInterfaceSharedPtr<Interface>(std::string), but 114 /// it returns a std::shared_ptr to a const-qualified Interface. 115 public: template <class Interface> 116 IGN_DEPRECATED(0.0) 117 std::shared_ptr<const Interface> QueryInterfaceSharedPtr( 118 const std::string &/*_interfaceName*/) const; 119 120 /// \brief Returns true if this Plugin has the specified type of 121 /// interface. 122 public: template <class Interface> 123 bool HasInterface() const; 124 125 /// \brief Returns true if this Plugin has the specified type of 126 /// interface, otherwise returns false. 127 /// 128 /// By default, we expect you to pass in a demangled version of the 129 /// interface name. If you want to use a mangled version of the name, 130 /// set the `demangled` argument to false. 131 /// 132 /// \param[in] _interfaceName The name of the desired interface, as a 133 /// std::string. Note that this expects the name to be mangled. 134 /// \param[in] _demangled If _interfaceName is demangled, set this to 135 /// true. If you are instead using the raw mangled name that gets provided 136 /// by typeid(T).name(), then set _demangled to false. 137 public: bool HasInterface(const std::string &_interfaceName, 138 const bool _demangled = true) const; 139 140 141 // -------------------- Private API ----------------------- 142 143 template <class> friend class TemplatePluginPtr; 144 template <class...> friend class SpecializedPlugin; 145 template <class, class> friend class detail::ComposePlugin; 146 friend class EnablePluginFromThis; 147 friend class WeakPluginPtr; 148 149 /// \brief Default constructor. This is kept private to ensure that 150 /// Plugins are always managed by a PluginPtr object. 151 private: Plugin(); 152 153 /// \brief Type-agnostic retriever for interfaces 154 private: void *PrivateQueryInterface( 155 const std::string &_interfaceName) const; 156 157 /// \brief Copy the plugin instance from another Plugin object 158 private: void PrivateCopyPluginInstance(const Plugin &_other) const; 159 160 /// \brief Copy an existing plugin instance into this plugin 161 /// \param[in] _info 162 /// Pointer to the Info for this plugin 163 /// \param[in] _instancePtr 164 /// Pointer to an already-existing abstract plugin instance pointer 165 private: void PrivateCopyPluginInstance( 166 const ConstInfoPtr &_info, 167 const std::shared_ptr<void> &_instancePtr) const; 168 169 /// \brief Create a new plugin instance based on the info provided 170 /// \param[in] _info 171 /// Pointer to the Info for this plugin 172 /// \param[in] _dlHandlePtr 173 /// Reference counter for the dl handle of this Plugin 174 private: void PrivateCreatePluginInstance( 175 const ConstInfoPtr &_info, 176 const std::shared_ptr<void> &_dlHandlePtr) const; 177 178 /// \brief Get a reference to the abstract instance being managed by this 179 /// wrapper 180 private: const std::shared_ptr<void> &PrivateGetInstancePtr() const; 181 182 /// \brief Get a reference to the Info being used by this wrapper 183 private: const ConstInfoPtr &PrivateGetInfoPtr() const; 184 185 /// \brief The InterfaceMap type needs to get used in several places, like 186 /// Plugin::Implementation and SpecializedPlugin<T>. We make the typedef 187 /// public so that those other classes can use it without needing to be 188 /// friends of Plugin. End-users should not have any need for this 189 /// typedef. 190 public: using InterfaceMap = std::map<std::string, void*>; 191 192 /// \brief Get or create an iterator to the std::map that holds pointers 193 /// to the various interfaces provided by this plugin instance. 194 private: InterfaceMap::iterator PrivateGetOrCreateIterator( 195 const std::string &_interfaceName); 196 197 class Implementation; 198 IGN_UTILS_WARN_IGNORE__DLL_INTERFACE_MISSING 199 /// \brief PIMPL pointer to the implementation of this class. 200 private: const std::unique_ptr<Implementation> dataPtr; 201 IGN_UTILS_WARN_RESUME__DLL_INTERFACE_MISSING 202 203 /// \brief Virtual destructor 204 public: virtual ~Plugin(); 205 }; 206 } 207 } 208 209 #include "ignition/plugin/detail/Plugin.hh" 210 211 #endif 212