All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
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 TF_PYNOTICEWRAPPER_H
25 #define TF_PYNOTICEWRAPPER_H
26 
27 #include "pxr/pxr.h"
28 #include "pxr/base/tf/notice.h"
29 #include "pxr/base/tf/stringUtils.h"
30 #include "pxr/base/tf/staticData.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/mpl/and.hpp>
37 #include <boost/mpl/if.hpp>
38 #include <boost/mpl/or.hpp>
39 #include <boost/python/bases.hpp>
40 #include <boost/python/class.hpp>
41 #include <boost/python/extract.hpp>
42 #include <boost/python/handle.hpp>
43 
44 #include <type_traits>
45 #include <map>
46 #include <string>
47 
48 PXR_NAMESPACE_OPEN_SCOPE
49 
50 struct Tf_PyNoticeObjectGenerator {
51  typedef Tf_PyNoticeObjectGenerator This;
52  typedef boost::python::object (*MakeObjectFunc)(TfNotice const &);
53 
54  // Register the generator for notice type T.
55  template <typename T>
56  static void Register() {
57  // XXX this stuff should be keyed directly off TfType now
58  (*_generators)[typeid(T).name()] = This::_Generate<T>;
59  }
60 
61  // Produce a boost::python::object for the correct derived type of \a n.
62  TF_API static boost::python::object Invoke(TfNotice const &n);
63 
64 private:
65 
66  template <typename T>
67  static boost::python::object _Generate(TfNotice const &n) {
68  // Python locking is left to the caller.
69  return boost::python::object(static_cast<T const &>(n));
70  }
71 
72  static MakeObjectFunc _Lookup(TfNotice const &n);
73 
74  TF_API static TfStaticData<std::map<std::string, MakeObjectFunc> > _generators;
75 
76 };
77 
78 struct TfPyNoticeWrapperBase : public TfType::PyPolymorphicBase {
79  TF_API virtual ~TfPyNoticeWrapperBase();
80  virtual boost::python::handle<> GetNoticePythonObject() const = 0;
81 };
82 
83 template <class Notice>
84 struct Tf_PyNoticeObjectFinder : public Tf_PyObjectFinderBase {
85  virtual ~Tf_PyNoticeObjectFinder() {}
86  virtual boost::python::object Find(void const *objPtr) const {
87  using namespace boost::python;
88  TfPyLock lock;
89  Notice const *wrapper = static_cast<Notice const *>(objPtr);
90  return wrapper ? object(wrapper->GetNoticePythonObject()) : object();
91  }
92 };
93 
94 template <typename NoticeType, typename BaseType>
95 struct TfPyNoticeWrapper : public NoticeType, public TfPyNoticeWrapperBase {
96 private:
97  static_assert(std::is_base_of<TfNotice, NoticeType>::value
98  || std::is_same<TfNotice, NoticeType>::value,
99  "Notice type must be derived from or equal to TfNotice.");
100 
101  static_assert(std::is_base_of<TfNotice, BaseType>::value
102  || std::is_same<TfNotice, BaseType>::value,
103  "BaseType type must be derived from or equal to TfNotice.");
104 
105  static_assert(std::is_base_of<BaseType, NoticeType>::value
106  || (std::is_same<NoticeType, TfNotice>::value
107  && std::is_same<BaseType, TfNotice>::value),
108  "BaseType type must be a base of notice, unless both "
109  "BaseType and Notice type are equal to TfNotice.");
110 
111 public:
112 
113  typedef TfPyNoticeWrapper<NoticeType, BaseType> This;
114 
115  // If Notice is really TfNotice, then this is the root of the hierarchy and
116  // bases is empty, otherwise bases contains the base class.
117  typedef typename boost::mpl::if_<
118  boost::is_same<NoticeType, TfNotice>
119  , boost::python::bases<>, boost::python::bases<BaseType> >::type Bases;
120 
121  typedef boost::python::class_<NoticeType, This, Bases> ClassType;
122 
123  static ClassType Wrap(std::string const &name = std::string()) {
124  std::string wrappedName = name;
125  if (wrappedName.empty()) {
126  // Assume they want the last bit of a qualified name.
127  wrappedName = TfType::Find<NoticeType>().GetTypeName();
128  if (!TfStringGetSuffix(wrappedName, ':').empty())
129  wrappedName = TfStringGetSuffix(wrappedName, ':');
130  }
131  Tf_PyNoticeObjectGenerator::Register<NoticeType>();
132  Tf_RegisterPythonObjectFinderInternal
133  (typeid(TfPyNoticeWrapper),
134  new Tf_PyNoticeObjectFinder<TfPyNoticeWrapper>);
135  return ClassType(wrappedName.c_str(), boost::python::no_init)
136  .def(TfTypePythonClass());
137  }
138 
139  // Implement the base class's virtual method.
140  virtual boost::python::handle<> GetNoticePythonObject() const {
141  TfPyLock lock;
142  return boost::python::handle<>(boost::python::borrowed(_self));
143  }
144 
145  // Arbitrary argument constructor (with a leading PyObject *) which
146  // forwards to the base Notice class's constructor.
147  template <typename... Args>
148  TfPyNoticeWrapper(PyObject *self, Args... args)
149  : NoticeType(args...)
150  , _self(self) {}
151 
152 private:
153  PyObject *_self;
154 
155 };
156 
157 #define TF_INSTANTIATE_NOTICE_WRAPPER(T, Base) \
158 TF_REGISTRY_FUNCTION(TfType) \
159 { \
160  TfType::Define< TfPyNoticeWrapper<T, Base>, \
161  TfType::Bases<Base> >(); \
162 }
163 
164 PXR_NAMESPACE_CLOSE_SCOPE
165 
166 #endif // TF_PYNOTICEWRAPPER_H
The base class for objects used to notify interested parties (listeners) when events have occurred...
Definition: notice.h:93
TF_API std::string TfStringGetSuffix(const std::string &name, char delimiter= '.')
Returns the suffix of a string.
A boost.python visitor that associates the Python class object created by the wrapping with the TfTyp...
Create or return a previously created object instance of global data.
Definition: staticData.h:113