Add helpers and visibility for the upcoming Event port

Small prerequisites for porting the Python EventBase hierarchy to Rust:

- duration: make `from_milliseconds` const and add an `IntoPyObject` impl
  for owned `SynapseDuration`, so the new Rust `Event.sticky_duration()`
  can return one directly to Python.
- internal_metadata: rename `copy()` to `deep_copy()` (matching the new
  naming used by the rest of the events module) and make `new()` callable
  from sibling modules.
- json_object: expose `object` as a `pub` field and add a `get_field`
  helper so the new Event class can read from it without going through
  Python.
- signatures, unsigned: add `deep_copy()` methods so the new Event class
  can implement its own deep-copy.
This commit is contained in:
Erik Johnston
2026-05-09 13:48:02 +01:00
parent f1705f2399
commit c81eead9e8
5 changed files with 41 additions and 6 deletions
+14 -1
View File
@@ -35,13 +35,26 @@ pub struct SynapseDuration {
impl SynapseDuration {
/// For now we only need to create durations from milliseconds.
pub fn from_milliseconds(milliseconds: u64) -> Self {
pub const fn from_milliseconds(milliseconds: u64) -> Self {
Self {
microseconds: milliseconds * 1_000,
}
}
}
impl<'py> IntoPyObject<'py> for SynapseDuration {
type Target = PyAny;
type Output = Bound<'py, Self::Target>;
type Error = PyErr;
fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
let duration_module = duration_module(py)?;
let kwargs = [("microseconds", self.microseconds)].into_py_dict(py)?;
let duration_instance = duration_module.call_method("Duration", (), Some(&kwargs))?;
Ok(duration_instance.into_bound())
}
}
impl<'py> IntoPyObject<'py> for &SynapseDuration {
type Target = PyAny;
type Output = Bound<'py, Self::Target>;
+2 -2
View File
@@ -510,7 +510,7 @@ fn attr_err<T>(val: Option<T>, name: &str) -> PyResult<T> {
#[pymethods]
impl EventInternalMetadata {
#[new]
fn new(dict: &Bound<'_, PyDict>) -> PyResult<Self> {
pub fn new(dict: &Bound<'_, PyDict>) -> PyResult<Self> {
let mut data = Vec::with_capacity(dict.len());
for (key, value) in dict.iter() {
@@ -536,7 +536,7 @@ impl EventInternalMetadata {
})
}
fn copy(&self) -> PyResult<Self> {
pub fn deep_copy(&self) -> PyResult<Self> {
let guard = self.read_inner()?;
Ok(EventInternalMetadata {
inner: Arc::new(RwLock::new(guard.clone())),
+7 -1
View File
@@ -37,7 +37,7 @@ use serde::{Deserialize, Serialize};
#[pyclass(mapping, frozen)]
#[serde(transparent)]
pub struct JsonObject {
object: Arc<BTreeMap<Box<str>, serde_json::Value>>,
pub object: Arc<BTreeMap<Box<str>, serde_json::Value>>,
}
#[pymethods]
@@ -193,6 +193,12 @@ impl JsonObject {
}
}
impl JsonObject {
pub fn get_field(&self, key: &str) -> Option<&serde_json::Value> {
self.object.get(key)
}
}
/// Helper class returned by `JsonObject.keys()` to act as a view into the keys
/// of the object.
///
+10
View File
@@ -36,6 +36,16 @@ pub struct Signatures {
inner: Arc<RwLock<HashMap<String, HashMap<String, String>>>>,
}
impl Signatures {
pub fn deep_copy(&self) -> Self {
let signatures = self.inner.read().expect("lock poisoned").clone(); // Deep copy the inner map
Self {
inner: Arc::new(RwLock::new(signatures)),
}
}
}
#[pymethods]
impl Signatures {
#[new]
+8 -2
View File
@@ -100,6 +100,12 @@ impl Unsigned {
.write()
.map_err(|_| PyRuntimeError::new_err("Unsigned lock poisoned"))
}
pub fn deep_copy(&self) -> Self {
Self {
inner: Arc::new(RwLock::new(self.py_read().expect("lock poisoned").clone())),
}
}
}
#[pymethods]
@@ -264,11 +270,11 @@ impl Unsigned {
}
}
fn for_persistence<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyAny>> {
pub fn for_persistence<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyAny>> {
Ok(pythonize(py, &self.py_read()?.persisted_fields)?)
}
fn for_event<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyAny>> {
pub fn for_event<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyAny>> {
Ok(pythonize(py, &*self.py_read()?)?)
}
}