PythonMarshalComponent.h 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #pragma once
  9. #include <EditorPythonBindings/EditorPythonBindingsSymbols.h>
  10. #include <EditorPythonBindings/PythonCommon.h>
  11. #include <EditorPythonBindings/PythonUtility.h>
  12. #include <pybind11/pybind11.h>
  13. #include <AzCore/Component/Component.h>
  14. #include <AzCore/EBus/EBus.h>
  15. #include <AzCore/RTTI/AttributeReader.h>
  16. #include <AzCore/RTTI/BehaviorContext.h>
  17. #include <AzCore/std/functional.h>
  18. #include <AzCore/std/optional.h>
  19. #include <AzCore/std/string/string_view.h>
  20. namespace EditorPythonBindings
  21. {
  22. //! An abstract to marshal between Behavior and Python type values
  23. class PythonMarshalTypeRequests
  24. : public AZ::EBusTraits
  25. {
  26. public:
  27. //////////////////////////////////////////////////////////////////////////
  28. // EBusTraits overrides
  29. static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple;
  30. static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
  31. using BusIdType = AZ::TypeId;
  32. //////////////////////////////////////////////////////////////////////////
  33. using DeallocateFunction = Convert::VariableDeleter;
  34. using BehaviorTraits = AZ::BehaviorParameter::Traits;
  35. //! Marshals a Python value to a BehaviorArgument plus an optional function to deallocate it after usage
  36. //! @return returns a pair of a flag to indicate success and an function to deallocate
  37. using BehaviorValueResult = AZStd::pair<bool, DeallocateFunction>;
  38. virtual AZStd::optional<BehaviorValueResult> PythonToBehaviorValueParameter(BehaviorTraits traits, pybind11::object pyObj, AZ::BehaviorArgument& outValue) = 0;
  39. //! Marshals a BehaviorArgument to a Python value object
  40. //! @return returns a pair of a valid Python object and an optional function to deallocate after sent to Python
  41. using PythonValueResult = AZStd::pair<pybind11::object, DeallocateFunction>;
  42. virtual AZStd::optional<PythonValueResult> BehaviorValueParameterToPython(AZ::BehaviorArgument& behaviorValue) = 0;
  43. //! Validates that a particular Python object can convert into a Behavior value parameter type
  44. virtual bool CanConvertPythonToBehaviorValue(BehaviorTraits traits, pybind11::object pyObj) const = 0;
  45. };
  46. using PythonMarshalTypeRequestBus = AZ::EBus<PythonMarshalTypeRequests>;
  47. //! Handles marshaling of built-in Behavior types like numbers, strings, and lists
  48. class PythonMarshalComponent
  49. : public AZ::Component
  50. , protected PythonMarshalTypeRequestBus::MultiHandler
  51. {
  52. public:
  53. AZ_COMPONENT(PythonMarshalComponent, PythonMarshalComponentTypeId, AZ::Component);
  54. static void Reflect(AZ::ReflectContext* context);
  55. static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided);
  56. static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible);
  57. static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required);
  58. class TypeConverter
  59. {
  60. public:
  61. virtual AZStd::optional<PythonMarshalComponent::BehaviorValueResult> PythonToBehaviorValueParameter(PythonMarshalTypeRequests::BehaviorTraits traits, pybind11::object pyObj, AZ::BehaviorArgument& outValue) = 0;
  62. virtual AZStd::optional<PythonMarshalComponent::PythonValueResult> BehaviorValueParameterToPython(AZ::BehaviorArgument& behaviorValue) = 0;
  63. virtual bool CanConvertPythonToBehaviorValue(BehaviorTraits traits, pybind11::object pyObj) const = 0;
  64. virtual ~TypeConverter() = default;
  65. };
  66. using TypeConverterPointer = AZStd::shared_ptr<TypeConverter>;
  67. void RegisterTypeConverter(const AZ::TypeId& typeId, TypeConverterPointer typeConverterPointer);
  68. protected:
  69. ////////////////////////////////////////////////////////////////////////
  70. // AZ::Component interface implementation
  71. void Activate() override;
  72. void Deactivate() override;
  73. ////////////////////////////////////////////////////////////////////////
  74. // PythonMarshalTypeRequestBus interface implementation
  75. AZStd::optional<PythonMarshalTypeRequests::BehaviorValueResult> PythonToBehaviorValueParameter(PythonMarshalTypeRequests::BehaviorTraits traits, pybind11::object pyObj, AZ::BehaviorArgument& outValue) override;
  76. AZStd::optional<PythonMarshalTypeRequests::PythonValueResult> BehaviorValueParameterToPython(AZ::BehaviorArgument& behaviorValue) override;
  77. bool CanConvertPythonToBehaviorValue(BehaviorTraits traits, pybind11::object pyObj) const override;
  78. private:
  79. using TypeConverterMap = AZStd::unordered_map<AZ::TypeId, TypeConverterPointer>;
  80. TypeConverterMap m_typeConverterMap;
  81. };
  82. namespace Container
  83. {
  84. AZStd::optional<PythonMarshalTypeRequests::PythonValueResult> ProcessBehaviorObject(AZ::BehaviorObject& behaviorObject);
  85. AZStd::optional<PythonMarshalTypeRequests::BehaviorValueResult> ProcessPythonObject(
  86. PythonMarshalTypeRequests::BehaviorTraits traits,
  87. pybind11::object pythonObj,
  88. const AZ::TypeId& elementTypeId,
  89. AZ::BehaviorArgument& outValue);
  90. } // namespace Container
  91. }