Loading...
Searching...
No Matches
pyNoticeWrapper.h
1//
2// Copyright 2016 Pixar
3//
4// Licensed under the Apache License, Version 2.0 (the "Apache License")
5// with the following modification; you may not use this file except in
6// compliance with the Apache License and the following modification to it:
7// Section 6. Trademarks. is deleted and replaced with:
8//
9// 6. Trademarks. This License does not grant permission to use the trade
10// names, trademarks, service marks, or product names of the Licensor
11// and its affiliates, except as required to comply with Section 4(c) of
12// the License and to reproduce the content of the NOTICE file.
13//
14// You may obtain a copy of the Apache License at
15//
16// http://www.apache.org/licenses/LICENSE-2.0
17//
18// Unless required by applicable law or agreed to in writing, software
19// distributed under the Apache License with the above modification is
20// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21// KIND, either express or implied. See the Apache License for the specific
22// language governing permissions and limitations under the Apache License.
23//
24#ifndef PXR_BASE_TF_PY_NOTICE_WRAPPER_H
25#define PXR_BASE_TF_PY_NOTICE_WRAPPER_H
26
27#include "pxr/pxr.h"
28#include "pxr/base/tf/notice.h"
31#include "pxr/base/tf/type.h"
32#include "pxr/base/tf/pyLock.h"
33#include "pxr/base/tf/pyObjectFinder.h"
34#include "pxr/base/tf/wrapTypeHelpers.h"
35
36#include <boost/python/bases.hpp>
37#include <boost/python/class.hpp>
38#include <boost/python/extract.hpp>
39#include <boost/python/handle.hpp>
40
41#include <type_traits>
42#include <map>
43#include <string>
44
45PXR_NAMESPACE_OPEN_SCOPE
46
47struct Tf_PyNoticeObjectGenerator {
48 typedef Tf_PyNoticeObjectGenerator This;
49 typedef boost::python::object (*MakeObjectFunc)(TfNotice const &);
50
51 // Register the generator for notice type T.
52 template <typename T>
53 static void Register() {
54 // XXX this stuff should be keyed directly off TfType now
55 (*_generators)[typeid(T).name()] = This::_Generate<T>;
56 }
57
58 // Produce a boost::python::object for the correct derived type of \a n.
59 TF_API static boost::python::object Invoke(TfNotice const &n);
60
61private:
62
63 template <typename T>
64 static boost::python::object _Generate(TfNotice const &n) {
65 // Python locking is left to the caller.
66 return boost::python::object(static_cast<T const &>(n));
67 }
68
69 static MakeObjectFunc _Lookup(TfNotice const &n);
70
72
73};
74
75struct TfPyNoticeWrapperBase : public TfType::PyPolymorphicBase {
76 TF_API virtual ~TfPyNoticeWrapperBase();
77 virtual boost::python::handle<> GetNoticePythonObject() const = 0;
78};
79
80template <class Notice>
81struct Tf_PyNoticeObjectFinder : public Tf_PyObjectFinderBase {
82 virtual ~Tf_PyNoticeObjectFinder() {}
83 virtual boost::python::object Find(void const *objPtr) const {
84 using namespace boost::python;
85 TfPyLock lock;
86 Notice const *wrapper = static_cast<Notice const *>(objPtr);
87 return wrapper ? object(wrapper->GetNoticePythonObject()) : object();
88 }
89};
90
91template <typename NoticeType, typename BaseType>
92struct TfPyNoticeWrapper : public NoticeType, public TfPyNoticeWrapperBase {
93private:
94 static_assert(std::is_base_of<TfNotice, NoticeType>::value
95 || std::is_same<TfNotice, NoticeType>::value,
96 "Notice type must be derived from or equal to TfNotice.");
97
98 static_assert(std::is_base_of<TfNotice, BaseType>::value
99 || std::is_same<TfNotice, BaseType>::value,
100 "BaseType type must be derived from or equal to TfNotice.");
101
102 static_assert(std::is_base_of<BaseType, NoticeType>::value
103 || (std::is_same<NoticeType, TfNotice>::value
104 && std::is_same<BaseType, TfNotice>::value),
105 "BaseType type must be a base of notice, unless both "
106 "BaseType and Notice type are equal to TfNotice.");
107
108public:
109
110 typedef TfPyNoticeWrapper<NoticeType, BaseType> This;
111
112 // If Notice is really TfNotice, then this is the root of the hierarchy and
113 // bases is empty, otherwise bases contains the base class.
114 using Bases = std::conditional_t<std::is_same<NoticeType, TfNotice>::value,
115 boost::python::bases<>,
116 boost::python::bases<BaseType>>;
117
118 typedef boost::python::class_<NoticeType, This, Bases> ClassType;
119
120 static ClassType Wrap(std::string const &name = std::string()) {
121 std::string wrappedName = name;
122 if (wrappedName.empty()) {
123 // Assume they want the last bit of a qualified name.
124 wrappedName = TfType::Find<NoticeType>().GetTypeName();
125 if (!TfStringGetSuffix(wrappedName, ':').empty())
126 wrappedName = TfStringGetSuffix(wrappedName, ':');
127 }
128 Tf_PyNoticeObjectGenerator::Register<NoticeType>();
129 Tf_RegisterPythonObjectFinderInternal
130 (typeid(TfPyNoticeWrapper),
131 new Tf_PyNoticeObjectFinder<TfPyNoticeWrapper>);
132 return ClassType(wrappedName.c_str(), boost::python::no_init)
133 .def(TfTypePythonClass());
134 }
135
136 // Implement the base class's virtual method.
137 virtual boost::python::handle<> GetNoticePythonObject() const {
138 TfPyLock lock;
139 return boost::python::handle<>(boost::python::borrowed(_self));
140 }
141
142 // Arbitrary argument constructor (with a leading PyObject *) which
143 // forwards to the base Notice class's constructor.
144 template <typename... Args>
145 TfPyNoticeWrapper(PyObject *self, Args... args)
146 : NoticeType(args...)
147 , _self(self) {}
148
149private:
150 PyObject *_self;
151
152};
153
154#define TF_INSTANTIATE_NOTICE_WRAPPER(T, Base) \
155TF_REGISTRY_FUNCTION(TfType) \
156{ \
157 TfType::Define< TfPyNoticeWrapper<T, Base>, \
158 TfType::Bases<Base> >(); \
159}
160
161PXR_NAMESPACE_CLOSE_SCOPE
162
163#endif // PXR_BASE_TF_PY_NOTICE_WRAPPER_H
The base class for objects used to notify interested parties (listeners) when events have occurred.
Definition: notice.h:93
Convenience class for accessing the Python Global Interpreter Lock.
Definition: pyLock.h:122
Create or return a previously created object instance of global data.
Definition: staticData.h:113
TF_API std::string TfStringGetSuffix(const std::string &name, char delimiter='.')
Returns the suffix of a string.
Definitions of basic string utilities in tf.
A boost.python visitor that associates the Python class object created by the wrapping with the TfTyp...