bt2: update object model
[babeltrace.git] / bindings / python / bt2 / bt2 / object.py
index 774027cbdc6685105b72bb1154d3992eb385fe5d..05c6deb75b63ac345aeabaa072ae63f836d83de5 100644 (file)
 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 # THE SOFTWARE.
 
-from bt2 import native_bt
-import abc
 
+class _BaseObject:
+    # Ensure that the object always has _ptr set, even if it throws during
+    # construction.
+
+    def __new__(cls, *args, **kwargs):
+        obj = super().__new__(cls)
+        obj._ptr = None
+        return obj
 
-class _Object:
     def __init__(self, ptr):
         self._ptr = ptr
 
@@ -32,50 +37,91 @@ class _Object:
     def addr(self):
         return int(self._ptr)
 
+    def __repr__(self):
+        return '<{}.{} object @ {}>'.format(self.__class__.__module__,
+                                            self.__class__.__name__,
+                                            hex(self.addr))
+
+    def __copy__(self):
+        raise NotImplementedError
+
+    def __deepcopy__(self, memo):
+        raise NotImplementedError
+
+
+# A Python object that is itself not refcounted, but is wholly owned by an
+# object that is itself refcounted (a _SharedObject).  A Babeltrace unique
+# object gets destroyed once its owner gets destroyed (its refcount drops to
+# 0).
+#
+# In the Python bindings, to avoid having to deal with issues with the lifetime
+# of unique objects, we make it so acquiring a reference on a unique object
+# acquires a reference on its owner.
+
+class _UniqueObject(_BaseObject):
+
+    # Create a _UniqueObject.
+    #
+    #   - ptr: SWIG Object, pointer to the unique object.
+    #   - owner_ptr: SWIG Object, pointer to the owner of the unique
+    #     object.  A new reference is acquired.
+    #   - owner_get_ref: Callback to get a reference on the owner
+    #   - owner_put_ref: Callback to put a reference on the owner.
+
     @classmethod
-    def _create_from_ptr(cls, ptr):
+    def _create_from_ptr_and_get_ref(cls, ptr, owner_ptr,
+                                     owner_get_ref, owner_put_ref):
         obj = cls.__new__(cls)
         obj._ptr = ptr
+        obj._owner_ptr = owner_ptr
+        obj._owner_put_ref = owner_put_ref
+        owner_get_ref(obj._owner_ptr)
         return obj
 
-    def _get(self):
-        native_bt.get(self._ptr)
-
     def __del__(self):
-        ptr = getattr(self, '_ptr', None)
-        native_bt.put(ptr)
-        self._ptr = None
+        self._owner_put_ref(self._owner_ptr)
 
-    def __repr__(self):
-        return '<{}.{} object @ {}>'.format(self.__class__.__module__,
-                                            self.__class__.__name__,
-                                            hex(self.addr))
 
+# Python object that owns a reference to a Babeltrace object.
+class _SharedObject(_BaseObject):
 
-class _PrivateObject:
-    def __del__(self):
-        pub_ptr = getattr(self, '_pub_ptr', None)
-        native_bt.put(pub_ptr)
-        self._pub_ptr = None
-        super().__del__()
+    # Get a new reference on ptr.
+    #
+    # This must be implemented by subclasses to work correctly with a pointer
+    # of the native type they wrap.
 
+    @staticmethod
+    def _get_ref(ptr):
+        raise NotImplementedError
 
-class _Freezable(metaclass=abc.ABCMeta):
-    @property
-    def is_frozen(self):
-        return self._is_frozen()
+    # Put a reference on ptr.
+    #
+    # This must be implemented by subclasses to work correctly with a pointer
+    # of the native type they wrap.
 
-    @property
-    def frozen(self):
-        return self.is_frozen
+    @staticmethod
+    def _put_ref(ptr):
+        raise NotImplementedError
 
-    def freeze(self):
-        self._freeze()
+    # Create a _SharedObject from an existing reference.
+    #
+    # This assumes that the caller owns a reference to the Babeltrace object
+    # and transfers this ownership to the newly created Python object.
 
-    @abc.abstractmethod
-    def _is_frozen(self):
-        pass
+    @classmethod
+    def _create_from_ptr(cls, ptr_owned):
+        obj = cls.__new__(cls)
+        obj._ptr = ptr_owned
+        return obj
 
-    @abc.abstractmethod
-    def _freeze(self):
-        pass
+    # Like _create_from_ptr, but acquire a new reference rather than
+    # stealing the caller's reference.
+
+    @classmethod
+    def _create_from_ptr_and_get_ref(cls, ptr):
+        obj = cls._create_from_ptr(ptr)
+        cls._get_ref(obj._ptr)
+        return obj
+
+    def __del__(self):
+        self._put_ref(self._ptr)
This page took 0.024953 seconds and 4 git commands to generate.