LUMIERA.clone/src/common/instancehandle.hpp

272 lines
8.1 KiB
C++
Raw Normal View History

/*
INSTANCEHANDLE.hpp - automatically handling interface lifecycle
2010-12-17 23:28:49 +01:00
Copyright: clarify and simplify the file headers * Lumiera source code always was copyrighted by individual contributors * there is no entity "Lumiera.org" which holds any copyrights * Lumiera source code is provided under the GPL Version 2+ == Explanations == Lumiera as a whole is distributed under Copyleft, GNU General Public License Version 2 or above. For this to become legally effective, the ''File COPYING in the root directory is sufficient.'' The licensing header in each file is not strictly necessary, yet considered good practice; attaching a licence notice increases the likeliness that this information is retained in case someone extracts individual code files. However, it is not by the presence of some text, that legally binding licensing terms become effective; rather the fact matters that a given piece of code was provably copyrighted and published under a license. Even reformatting the code, renaming some variables or deleting parts of the code will not alter this legal situation, but rather creates a derivative work, which is likewise covered by the GPL! The most relevant information in the file header is the notice regarding the time of the first individual copyright claim. By virtue of this initial copyright, the first author is entitled to choose the terms of licensing. All further modifications are permitted and covered by the License. The specific wording or format of the copyright header is not legally relevant, as long as the intention to publish under the GPL remains clear. The extended wording was based on a recommendation by the FSF. It can be shortened, because the full terms of the license are provided alongside the distribution, in the file COPYING.
2024-11-17 23:42:55 +01:00
Copyright (C)
2008, Hermann Vosseler <Ichthyostega@web.de>
2010-12-17 23:28:49 +01:00
Copyright: clarify and simplify the file headers * Lumiera source code always was copyrighted by individual contributors * there is no entity "Lumiera.org" which holds any copyrights * Lumiera source code is provided under the GPL Version 2+ == Explanations == Lumiera as a whole is distributed under Copyleft, GNU General Public License Version 2 or above. For this to become legally effective, the ''File COPYING in the root directory is sufficient.'' The licensing header in each file is not strictly necessary, yet considered good practice; attaching a licence notice increases the likeliness that this information is retained in case someone extracts individual code files. However, it is not by the presence of some text, that legally binding licensing terms become effective; rather the fact matters that a given piece of code was provably copyrighted and published under a license. Even reformatting the code, renaming some variables or deleting parts of the code will not alter this legal situation, but rather creates a derivative work, which is likewise covered by the GPL! The most relevant information in the file header is the notice regarding the time of the first individual copyright claim. By virtue of this initial copyright, the first author is entitled to choose the terms of licensing. All further modifications are permitted and covered by the License. The specific wording or format of the copyright header is not legally relevant, as long as the intention to publish under the GPL remains clear. The extended wording was based on a recommendation by the FSF. It can be shortened, because the full terms of the license are provided alongside the distribution, in the file COPYING.
2024-11-17 23:42:55 +01:00
  **Lumiera** is free software; you can redistribute it and/or modify it
  under the terms of the GNU General Public License as published by the
  Free Software Foundation; either version 2 of the License, or (at your
  option) any later version. See the file COPYING for further details.
2010-12-17 23:28:49 +01:00
*/
/** @file instancehandle.hpp
** A handle template for automatically dealing with interface and plugin
** registration and deregistration. By placing an instance of this template,
** parametrised with the appropriate interface type, the respective interface
** and instance is loaded and opened through the Lumiera Interface system.
** It will be closed and unregistered automatically when the handle goes
** out of scope. Additionally, access via an (existing) interface proxy
** may be enabled and disabled alongside with the loading and unloading.
**
** @see stage::GuiFacade usage example
** @see interface.h
2009-01-07 12:26:44 +01:00
** @see interfaceproxy.hpp (more explanations)
** @see session-command-interface-proxy.cpp (Proxy implementation example)
2009-01-07 12:26:44 +01:00
**
*/
#ifndef LUMIERA_INSTANCEHANDLE_H
#define LUMIERA_INSTANCEHANDLE_H
#include "include/logging.h"
#include "lib/error.hpp"
#include "lib/nocopy.hpp"
#include "lib/depend-inject.hpp"
extern "C" {
#include "common/interface.h"
#include "common/interfaceregistry.h"
}
#include <string>
namespace lumiera {
using std::string;
2009-01-07 12:26:44 +01:00
template<class I, class FA>
class InstanceHandle;
namespace { // implementation details
inline void
throwIfError()
{
if (lumiera_error_peek())
throw lumiera::error::Config("failed to open interface or plugin.",lumiera_error());
}
/** takes a (single) instance definitions, as typically created
* when defining interfaces for external use, and registers it
* with the InterfaceSystem. Then uses the data found in the
* \em given instance descriptor to open an instance handle.
* @throws error::Config when the registration process fails
*/
inline LumieraInterface
register_and_open (LumieraInterface descriptor)
{
if (!descriptor) return NULL;
lumiera_interfaceregistry_register_interface (descriptor, NULL);
throwIfError();
return lumiera_interface_open (descriptor->interface,
descriptor->version,
descriptor->size,
descriptor->name);
}
/** do a lookup within the interfaceregistry
* using the name/version found within the interface
* handle, to ensure it is still valid and registered */
inline bool
verify_validity (LumieraInterface ifa)
{
REQUIRE (ifa);
return (ifa == lumiera_interfaceregistry_interface_find (ifa->interface,
ifa->version,
ifa->name));
}
} // (End) impl details
namespace facade {
/**
* to be specialised and implemented for each
* individual interface and facade interface.
* The actual proxy implements the facade interface
* and reroutes each call to the corresponding function
* on the CL-Interface for the Lumiera interface system.
*/
template<class IHA>
class Proxy;
/** The ServiceHandle automatically creates and manages the Proxy instance */
template<class I, class FA>
using ServiceHandle = lib::DependInject<FA>::template ServiceInstance<Proxy<InstanceHandle<I,FA>>>;
2009-01-07 12:26:44 +01:00
/**
* @internal Helper/Adapter for establishing a link
* between an InstanceHandle and a facade interface,
* which is going to be implemented through the given
* interface/plugin. This way, creating the InstanceHandle
* automatically creates a lumiera::facade::Proxy, to route
* any facade calls through the interface/plugin. Similarly,
* when destroying the InstanceHandle, the proxy will be closed.
*/
template<class I, class FA>
struct Link
: ServiceHandle<I,FA>
2009-01-07 12:26:44 +01:00
{
using IH = InstanceHandle<I,FA>;
2009-01-07 12:26:44 +01:00
Link (IH const& iha);
~Link ();
2009-01-07 12:26:44 +01:00
FA* operator->() const;
2009-01-07 12:26:44 +01:00
};
/**
* @internal when the InstanceHandle isn't associated with a
* facade interface, then this specialisation switches
* the facade::Link into "NOP" mode.
2009-01-07 12:26:44 +01:00
*/
template<class I>
struct Link<I,I>
: util::NonCopyable
2009-01-07 12:26:44 +01:00
{
using IH = InstanceHandle<I,I>;
IH& ih_;
Link(IH& ih)
: ih_{ih}
{ }
2009-01-07 12:26:44 +01:00
I*
operator->() const
2009-01-07 12:26:44 +01:00
{
return & ih_.get();
2009-01-07 12:26:44 +01:00
}
};
} // namespace facade (impl details)
2009-01-07 12:26:44 +01:00
/**
* Handle tracking the registration of an interface, deregistering it on deletion.
* Depending on which flavour of the ctor is used, either (bulk) registration of interfaces
* or plugin loading is triggered. The interface type is defined by type parameter.
2009-01-07 12:26:44 +01:00
* Additionally, choosing a facade interface as second type parameter causes installation
* of a proxy, which implements the facade by routing calls through the basic interface
* represented by this handle. This proxy will be "closed" automatically when this
* InstanceHandle goes out of scope. Of course, the proxy needs to be implemented
* somewhere, typically in interfaceproxy.cpp
*/
template< class I ///< fully mangled name of the interface type
, class FA = I ///< facade interface type to be used by clients
>
class InstanceHandle
: util::NonCopyable
{
LumieraInterface desc_;
2009-02-06 22:51:39 +01:00
I* instance_;
facade::Link<I,FA> facadeLink_;
public:
/** Set up an InstanceHandle representing a plugin.
2011-05-24 03:46:32 +02:00
* Should be placed at the client side.
* @param iName unmangled name of the interface
* @param version major version
* @param minminor minimum acceptable minor version number
* @param impName unmangled name of the instance (implementation)
*/
InstanceHandle (string const& iName, uint version, size_t minminor, string const& impName)
2009-01-07 12:26:44 +01:00
: desc_(0)
, instance_(reinterpret_cast<I*>
(lumiera_interface_open (iName.c_str(), version, minminor, impName.c_str())))
2009-01-07 12:26:44 +01:00
, facadeLink_(*this)
{
throwIfError();
}
/** Set up an InstanceHandle managing the
* registration and deregistration of interface(s).
* Should be placed at the service providing side.
* @param descriptor a (single) interface descriptor, which can be created with
2011-05-24 03:46:32 +02:00
* LUMIERA_INTERFACE_INSTANCE and referred to by LUMIERA_INTERFACE_REF
*/
InstanceHandle (LumieraInterface descriptor)
: desc_(descriptor)
2009-01-07 12:26:44 +01:00
, instance_(reinterpret_cast<I*> (register_and_open (desc_)))
, facadeLink_(*this)
{
throwIfError();
}
~InstanceHandle()
{
lumiera_interface_close (&instance_->interface_header_);
if (desc_)
lumiera_interfaceregistry_remove_interface (desc_);
}
/** act as smart pointer to allow access through the facade.
* @note we don't provide `operator*`
*/
FA*
operator->() const
{
return facadeLink_.operator ->();
}
/** directly access the instance via the CL interface */
I&
get() const
{
ENSURE(instance_);
return *instance_;
}
explicit
operator bool() const
{
return isValid();
}
bool
operator!() const
{
return not isValid();
}
private:
bool
isValid() const
{
return instance_
and verify_validity (&instance_->interface_header_);
}
};
} // namespace lumiera
#endif /*LUMIERA_INSTANCEHANDLE_H*/