All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
pyNoticeWrapper.h
1//
2// Copyright 2016 Pixar
3//
4// Licensed under the terms set forth in the LICENSE.txt file available at
5// https://openusd.org/license.
6//
7#ifndef PXR_BASE_TF_PY_NOTICE_WRAPPER_H
8#define PXR_BASE_TF_PY_NOTICE_WRAPPER_H
9
10#include "pxr/pxr.h"
11#include "pxr/base/tf/notice.h"
14#include "pxr/base/tf/type.h"
15#include "pxr/base/tf/pyLock.h"
16#include "pxr/base/tf/pyObjectFinder.h"
17#include "pxr/base/tf/wrapTypeHelpers.h"
18
19#include "pxr/external/boost/python/bases.hpp"
20#include "pxr/external/boost/python/class.hpp"
21#include "pxr/external/boost/python/extract.hpp"
22#include "pxr/external/boost/python/handle.hpp"
23
24#include <type_traits>
25#include <map>
26#include <string>
27
28PXR_NAMESPACE_OPEN_SCOPE
29
30struct Tf_PyNoticeObjectGenerator {
31 typedef Tf_PyNoticeObjectGenerator This;
32 typedef pxr_boost::python::object (*MakeObjectFunc)(TfNotice const &);
33
34 // Register the generator for notice type T.
35 template <typename T>
36 static void Register() {
37 // XXX this stuff should be keyed directly off TfType now
38 (*_generators)[typeid(T).name()] = This::_Generate<T>;
39 }
40
41 // Produce a pxr_boost::python::object for the correct derived type of \a n.
42 TF_API static pxr_boost::python::object Invoke(TfNotice const &n);
43
44private:
45
46 template <typename T>
47 static pxr_boost::python::object _Generate(TfNotice const &n) {
48 // Python locking is left to the caller.
49 return pxr_boost::python::object(static_cast<T const &>(n));
50 }
51
52 static MakeObjectFunc _Lookup(TfNotice const &n);
53
55
56};
57
58struct TfPyNoticeWrapperBase : public TfType::PyPolymorphicBase {
59 TF_API virtual ~TfPyNoticeWrapperBase();
60 virtual pxr_boost::python::handle<> GetNoticePythonObject() const = 0;
61};
62
63template <class Notice>
64struct Tf_PyNoticeObjectFinder : public Tf_PyObjectFinderBase {
65 virtual ~Tf_PyNoticeObjectFinder() {}
66 virtual pxr_boost::python::object Find(void const *objPtr) const {
67 using namespace pxr_boost::python;
68 TfPyLock lock;
69 Notice const *wrapper = static_cast<Notice const *>(objPtr);
70 return wrapper ? object(wrapper->GetNoticePythonObject()) : object();
71 }
72};
73
74template <typename NoticeType, typename BaseType>
75struct TfPyNoticeWrapper : public NoticeType, public TfPyNoticeWrapperBase {
76private:
77 static_assert(std::is_base_of<TfNotice, NoticeType>::value
78 || std::is_same<TfNotice, NoticeType>::value,
79 "Notice type must be derived from or equal to TfNotice.");
80
81 static_assert(std::is_base_of<TfNotice, BaseType>::value
82 || std::is_same<TfNotice, BaseType>::value,
83 "BaseType type must be derived from or equal to TfNotice.");
84
85 static_assert(std::is_base_of<BaseType, NoticeType>::value
86 || (std::is_same<NoticeType, TfNotice>::value
87 && std::is_same<BaseType, TfNotice>::value),
88 "BaseType type must be a base of notice, unless both "
89 "BaseType and Notice type are equal to TfNotice.");
90
91public:
92
93 typedef TfPyNoticeWrapper<NoticeType, BaseType> This;
94
95 // If Notice is really TfNotice, then this is the root of the hierarchy and
96 // bases is empty, otherwise bases contains the base class.
97 using Bases = std::conditional_t<std::is_same<NoticeType, TfNotice>::value,
98 pxr_boost::python::bases<>,
99 pxr_boost::python::bases<BaseType>>;
100
101 typedef pxr_boost::python::class_<NoticeType, This, Bases> ClassType;
102
103 static ClassType Wrap(std::string const &name = std::string()) {
104 std::string wrappedName = name;
105 if (wrappedName.empty()) {
106 // Assume they want the last bit of a qualified name.
107 wrappedName = TfType::Find<NoticeType>().GetTypeName();
108 if (!TfStringGetSuffix(wrappedName, ':').empty())
109 wrappedName = TfStringGetSuffix(wrappedName, ':');
110 }
111 Tf_PyNoticeObjectGenerator::Register<NoticeType>();
112 Tf_RegisterPythonObjectFinderInternal
113 (typeid(TfPyNoticeWrapper),
114 new Tf_PyNoticeObjectFinder<TfPyNoticeWrapper>);
115 return ClassType(wrappedName.c_str(), pxr_boost::python::no_init)
116 .def(TfTypePythonClass());
117 }
118
119 // Implement the base class's virtual method.
120 virtual pxr_boost::python::handle<> GetNoticePythonObject() const {
121 TfPyLock lock;
122 return pxr_boost::python::handle<>(pxr_boost::python::borrowed(_self));
123 }
124
125 // Arbitrary argument constructor (with a leading PyObject *) which
126 // forwards to the base Notice class's constructor.
127 template <typename... Args>
128 TfPyNoticeWrapper(PyObject *self, Args... args)
129 : NoticeType(args...)
130 , _self(self) {}
131
132private:
133 PyObject *_self;
134
135};
136
137#define TF_INSTANTIATE_NOTICE_WRAPPER(T, Base) \
138TF_REGISTRY_FUNCTION(TfType) \
139{ \
140 TfType::Define< TfPyNoticeWrapper<T, Base>, \
141 TfType::Bases<Base> >(); \
142}
143
144PXR_NAMESPACE_CLOSE_SCOPE
145
146#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:77
Convenience class for accessing the Python Global Interpreter Lock.
Definition: pyLock.h:105
Create or return a previously created object instance of global data.
Definition: staticData.h:96
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...