impl PreKeySignalMessage {
#[staticmethod]
pub fn try_from(data: &[u8]) -> PyResult<Py<PreKeySignalMessage>> {
let upstream_data = match libsignal_protocol_rust::PreKeySignalMessage::try_from(data) {
Ok(data) => data,
Err(err) => return Err(SignalProtocolError::new_err(err)),
};
let ciphertext =
libsignal_protocol_rust::CiphertextMessage::PreKeySignalMessage(upstream_data.clone());
// Workaround to allow two constructors with pyclass inheritence
let gil = Python::acquire_gil();
let py = gil.python();
Py::new(
py,
(
PreKeySignalMessage {
data: upstream_data,
},
CiphertextMessage { data: ciphertext },
),
)
}Python is brought into scope by the Pyo3 prelude. By calling acquire_gil, we are ensuring Python's Global Interpreter Lock is held. The return type of this method acquire_gil is GILGuard. By calling python() on that object, we get access to the Python runtime. On this py object, we could run arbitrary python code e.g. import a Python module.
What we're then doing is creating a Python object directly (in the Py::new invokation). This is done via the Py struct. The Py struct (again brought into scope by the pyo3 prelude) represents any Python object of type T (where T: PyClass). When we call new, we pass in our Python GIL token, and then our tuple (T, U) where U is the baseclass of T. The behavior of Py::new is to allocate a new instance of Py<T> on the python heap. It calls Into<PyClassInitializer<T>> to do this.
See also the subclass/base class logic in PyClassInitializer: https://docs.rs/pyo3/0.12.4/src/pyo3/pyclass_init.rs.html#172-183