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_ANNOTATED_BOOL_RESULT_H 25 #define PXR_BASE_TF_PY_ANNOTATED_BOOL_RESULT_H 26 27 #include "pxr/pxr.h" 28 29 #include "pxr/base/tf/py3Compat.h" 30 #include "pxr/base/tf/pyLock.h" 31 #include "pxr/base/tf/pyUtils.h" 32 33 #include <boost/operators.hpp> 34 #include <boost/python/class.hpp> 35 #include <boost/python/operators.hpp> 36 #include <boost/python/return_by_value.hpp> 37 38 #include <string> 39 40 PXR_NAMESPACE_OPEN_SCOPE 41 42 template <class Annotation> 43 struct TfPyAnnotatedBoolResult : 44 boost::equality_comparable<TfPyAnnotatedBoolResult<Annotation>, bool> 45 { TfPyAnnotatedBoolResultTfPyAnnotatedBoolResult46 TfPyAnnotatedBoolResult() {} 47 TfPyAnnotatedBoolResultTfPyAnnotatedBoolResult48 TfPyAnnotatedBoolResult(bool val, Annotation const &annotation) : 49 _val(val), _annotation(annotation) {} 50 GetValueTfPyAnnotatedBoolResult51 bool GetValue() const { 52 return _val; 53 } 54 GetAnnotationTfPyAnnotatedBoolResult55 Annotation const &GetAnnotation() const { 56 return _annotation; 57 } 58 GetReprTfPyAnnotatedBoolResult59 std::string GetRepr() const { 60 return GetValue() ? "True" : 61 "(False, " + TfPyRepr(GetAnnotation()) + ")"; 62 } 63 64 /// Returns \c true if the result is the same as \p rhs. 65 bool operator==(bool rhs) const { 66 return _val == rhs; 67 } 68 69 template <class Derived> 70 static boost::python::class_<Derived> WrapTfPyAnnotatedBoolResult71 Wrap(char const *name, char const *annotationName) { 72 typedef TfPyAnnotatedBoolResult<Annotation> This; 73 using namespace boost::python; 74 TfPyLock lock; 75 return class_<Derived>(name, no_init) 76 .def(TfPyBoolBuiltinFuncName, &Derived::GetValue) 77 .def("__repr__", &Derived::GetRepr) 78 .def(self == bool()) 79 .def(self != bool()) 80 .def(bool() == self) 81 .def(bool() != self) 82 // Use a helper function. We'd like to def_readonly the 83 // _annotation member but there are two problems with that. 84 // First, we can't control the return_value_policy and if the 85 // Annotation type has a custom to-Python converter then the 86 // def_readonly return_value_policy of return_internal_reference 87 // won't work since the object needs conversion. Second, if we 88 // try to use GetAnnotation() with add_property then we'll get 89 // a failure at runtime because Python has a Derived but 90 // GetAnnotation takes a TfPyAnnotatedBoolResult<Annotation> 91 // and boost python doesn't know the former is-a latter because 92 // TfPyAnnotatedBoolResult<Annotation> is not wrapped. 93 // 94 // So we provide a templated static method that takes a Derived 95 // and returns Annotation by value. We can add_property that 96 // with no problem. 97 .add_property(annotationName, &This::_GetAnnotation<Derived>) 98 .def("__getitem__", &This::_GetItem<Derived>) 99 ; 100 } 101 102 using AnnotationType = Annotation; 103 104 private: 105 // Helper function for wrapper. 106 template <class Derived> _GetAnnotationTfPyAnnotatedBoolResult107 static Annotation _GetAnnotation(const Derived& x) 108 { 109 return x.GetAnnotation(); 110 } 111 112 template <class Derived> _GetItemTfPyAnnotatedBoolResult113 static boost::python::object _GetItem(const Derived& x, int i) 114 { 115 if (i == 0) { 116 return boost::python::object(x._val); 117 } 118 if (i == 1) { 119 return boost::python::object(x._annotation); 120 } 121 122 PyErr_SetString(PyExc_IndexError, "Index must be 0 or 1."); 123 boost::python::throw_error_already_set(); 124 125 return boost::python::object(); 126 } 127 128 private: 129 bool _val; 130 Annotation _annotation; 131 132 }; 133 134 /// Returns \c true if the result of \p lhs is the same as \p rhs. 135 template <class Annotation> 136 bool operator==(bool lhs, TfPyAnnotatedBoolResult<Annotation>& rhs) 137 { 138 return rhs == lhs; 139 } 140 141 /// Returns \c false if the result of \p lhs is the same as \p rhs. 142 template <class Annotation> 143 bool operator!=(bool lhs, TfPyAnnotatedBoolResult<Annotation>& rhs) 144 { 145 return rhs != lhs; 146 } 147 148 PXR_NAMESPACE_CLOSE_SCOPE 149 150 #endif // PXR_BASE_TF_PY_ANNOTATED_BOOL_RESULT_H 151