mirror of https://github.com/borgbackup/borg.git
item: item.to_optr(), Item.from_optr()
This commit is contained in:
parent
5abfa0b266
commit
d286d753cb
|
@ -0,0 +1,41 @@
|
||||||
|
#include "Python.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is not quite as dark magic as it looks. We just convert the address of (pointer to)
|
||||||
|
* a PyObject into a bytes object in _wrap_object, and convert these bytes back to the
|
||||||
|
* pointer to the original object.
|
||||||
|
*
|
||||||
|
* This mainly looks a bit confusing due to our mental special-casing of "char*" from other
|
||||||
|
* pointers.
|
||||||
|
*
|
||||||
|
* The big upside to this is that this neither does *any* serialization (beyond creating tiny
|
||||||
|
* bytes objects as "stand-ins"), nor has to copy the entire object that's passed around.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
_object_to_optr(PyObject *obj)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Create a temporary reference to the object being passed around so it does not vanish.
|
||||||
|
* Note that we never decref this one in _unwrap_object, since we just transfer that reference
|
||||||
|
* there, i.e. there is an elided "Py_INCREF(x); Py_DECREF(x)".
|
||||||
|
* Since the reference is transferred, calls to _wrap_object and _unwrap_object must be symmetric.
|
||||||
|
*/
|
||||||
|
Py_INCREF(obj);
|
||||||
|
return PyBytes_FromStringAndSize((const char*) &obj, sizeof(void*));
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
_optr_to_object(PyObject *bytes)
|
||||||
|
{
|
||||||
|
if(!PyBytes_Check(bytes)) {
|
||||||
|
PyErr_SetString(PyExc_TypeError, "Cannot unwrap non-bytes object");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if(PyBytes_Size(bytes) != sizeof(void*)) {
|
||||||
|
PyErr_SetString(PyExc_TypeError, "Invalid length of bytes object");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
PyObject *object = * (PyObject **) PyBytes_AsString(bytes);
|
||||||
|
return object;
|
||||||
|
}
|
|
@ -141,7 +141,7 @@ def check_extension_modules():
|
||||||
raise ExtensionModuleError
|
raise ExtensionModuleError
|
||||||
if platform.API_VERSION != platform.OS_API_VERSION != '1.1_01':
|
if platform.API_VERSION != platform.OS_API_VERSION != '1.1_01':
|
||||||
raise ExtensionModuleError
|
raise ExtensionModuleError
|
||||||
if item.API_VERSION != '1.1_02':
|
if item.API_VERSION != '1.1_03':
|
||||||
raise ExtensionModuleError
|
raise ExtensionModuleError
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,12 @@ from .helpers import safe_encode, safe_decode
|
||||||
from .helpers import bigint_to_int, int_to_bigint
|
from .helpers import bigint_to_int, int_to_bigint
|
||||||
from .helpers import StableDict
|
from .helpers import StableDict
|
||||||
|
|
||||||
API_VERSION = '1.1_02'
|
cdef extern from "_item.c":
|
||||||
|
object _object_to_optr(object obj)
|
||||||
|
object _optr_to_object(object bytes)
|
||||||
|
|
||||||
|
|
||||||
|
API_VERSION = '1.1_03'
|
||||||
|
|
||||||
|
|
||||||
class PropDict:
|
class PropDict:
|
||||||
|
@ -227,6 +232,26 @@ class Item(PropDict):
|
||||||
setattr(self, attr, size)
|
setattr(self, attr, size)
|
||||||
return size
|
return size
|
||||||
|
|
||||||
|
def to_optr(self):
|
||||||
|
"""
|
||||||
|
Return an "object pointer" (optr), an opaque bag of bytes.
|
||||||
|
The return value is effectively a reference to this object
|
||||||
|
that can be passed exactly once to Item.from_optr to get this
|
||||||
|
object back.
|
||||||
|
|
||||||
|
to_optr/from_optr must be used symmetrically,
|
||||||
|
don't call from_optr multiple times.
|
||||||
|
|
||||||
|
This object can't be deallocated after a call to to_optr()
|
||||||
|
until from_optr() is called.
|
||||||
|
"""
|
||||||
|
return _object_to_optr(self)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_optr(self, optr):
|
||||||
|
return _optr_to_object(optr)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class EncryptedKey(PropDict):
|
class EncryptedKey(PropDict):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -164,3 +164,8 @@ def test_item_file_size():
|
||||||
def test_item_file_size_no_chunks():
|
def test_item_file_size_no_chunks():
|
||||||
item = Item(mode=0o100666)
|
item = Item(mode=0o100666)
|
||||||
assert item.get_size() == 0
|
assert item.get_size() == 0
|
||||||
|
|
||||||
|
|
||||||
|
def test_item_optr():
|
||||||
|
item = Item()
|
||||||
|
assert Item.from_optr(item.to_optr()) is item
|
||||||
|
|
Loading…
Reference in New Issue