Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
target: s390x
- runner: ubuntu-22.04
target: ppc64le
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14", "3.15"]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
Expand Down Expand Up @@ -63,7 +63,7 @@ jobs:
target: aarch64
- runner: ubuntu-22.04
target: armv7
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14", "3.15"]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
Expand Down Expand Up @@ -91,7 +91,7 @@ jobs:
target: x64
- runner: windows-latest
target: x86
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14", "3.15"]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
Expand Down Expand Up @@ -119,7 +119,7 @@ jobs:
target: x86_64
- runner: macos-15
target: aarch64
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14", "3.15"]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
Expand Down
49 changes: 12 additions & 37 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,5 @@ crate-type = ["cdylib"]
[dependencies]
loro = { version = "1.16.2", features = ["counter", "jsonpath"] }
rustc-hash = "2.1.1"
pyo3 = { version = "0.26.0" }
pyo3 = { version = "0.29" }
serde_json = "1"
8 changes: 4 additions & 4 deletions src/awareness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,19 +138,19 @@ impl EphemeralStore {
self.0.keys()
}

pub fn subscribe_local_updates(&self, callback: PyObject) -> Subscription {
pub fn subscribe_local_updates(&self, callback: Py<PyAny>) -> Subscription {
let subscription = self.0.subscribe_local_updates(Box::new(move |updates| {
Python::with_gil(|py| {
Python::attach(|py| {
let b = callback.call1(py, (updates,)).unwrap();
b.extract::<bool>(py).unwrap()
})
}));
subscription.into()
}

pub fn subscribe(&self, callback: PyObject) -> Subscription {
pub fn subscribe(&self, callback: Py<PyAny>) -> Subscription {
let subscription = self.0.subscribe(Box::new(move |updates| {
Python::with_gil(|py| {
Python::attach(|py| {
let b = callback
.call1(
py,
Expand Down
2 changes: 1 addition & 1 deletion src/container/counter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ impl LoroCounter {
}
}

#[pyclass(frozen)]
#[pyclass(frozen, from_py_object)]
#[derive(Debug, Clone, Default)]
pub struct LoroCounter(pub LoroCounterInner);

Expand Down
2 changes: 1 addition & 1 deletion src/container/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use crate::{

use super::{Container, Cursor, Side};

#[pyclass(frozen, sequence)]
#[pyclass(frozen, sequence, from_py_object)]
#[derive(Debug, Clone, Default)]
pub struct LoroList(pub LoroListInner);

Expand Down
2 changes: 1 addition & 1 deletion src/container/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ pub fn register_class(m: &Bound<'_, PyModule>) -> PyResult<()> {
Ok(())
}

#[pyclass(frozen, mapping)]
#[pyclass(frozen, mapping, from_py_object)]
#[derive(Debug, Clone, Default)]
pub struct LoroMap(pub LoroMapInner);

Expand Down
2 changes: 1 addition & 1 deletion src/container/movable_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use pyo3::{

use super::{Container, Cursor, Side};

#[pyclass(frozen, sequence)]
#[pyclass(frozen, sequence, from_py_object)]
#[derive(Debug, Clone, Default)]
pub struct LoroMovableList(pub LoroMovableListInner);

Expand Down
10 changes: 5 additions & 5 deletions src/container/text.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ pub fn register_class(m: &Bound<'_, PyModule>) -> PyResult<()> {
Ok(())
}

#[pyclass(frozen)]
#[pyclass(frozen, from_py_object)]
#[derive(Debug, Clone, Default)]
pub struct LoroText(pub LoroTextInner);

Expand Down Expand Up @@ -177,7 +177,7 @@ impl LoroText {
let mut buf = [0u8; 4];
let as_str = ch.encode_utf8(&mut buf);
Ok(PyString::new(py, as_str).into_any())
} else if let Ok(slice) = key.downcast::<PySlice>() {
} else if let Ok(slice) = key.cast::<PySlice>() {
let text = self.0.to_string();
let py_str = PyString::new(py, &text);
py_str.get_item(slice)
Expand Down Expand Up @@ -504,15 +504,15 @@ impl LoroText {
}
}

#[pyclass(eq, eq_int)]
#[pyclass(eq, eq_int, from_py_object)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Side {
Left = -1,
Middle = 0,
Right = 1,
}

#[pyclass(eq, eq_int)]
#[pyclass(eq, eq_int, from_py_object)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum PositionType {
Bytes,
Expand All @@ -534,7 +534,7 @@ impl From<PositionType> for PosType {
}
}

#[pyclass(str, frozen)]
#[pyclass(str, frozen, from_py_object)]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Cursor(pub loro::cursor::Cursor);

Expand Down
4 changes: 2 additions & 2 deletions src/container/tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ pub fn register_class(m: &Bound<'_, PyModule>) -> PyResult<()> {
Ok(())
}

#[pyclass(frozen)]
#[pyclass(frozen, from_py_object)]
#[derive(Debug, Clone, Default)]
pub struct LoroTree(pub LoroTreeInner);

Expand Down Expand Up @@ -373,7 +373,7 @@ impl LoroTree {
}

/// A tree node in the [LoroTree].
#[pyclass(str, get_all, set_all)]
#[pyclass(str, get_all, set_all, from_py_object)]
#[derive(Debug, Clone)]
pub struct TreeNode {
/// ID of the tree node.
Expand Down
2 changes: 1 addition & 1 deletion src/container/unknown.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use pyo3::prelude::*;

use crate::{doc::LoroDoc, value::ContainerID};

#[pyclass(frozen)]
#[pyclass(frozen, from_py_object)]
#[derive(Debug, Clone)]
pub struct LoroUnknown(pub LoroUnknownInner);

Expand Down
2 changes: 1 addition & 1 deletion src/container/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ pub enum SliceOrInt<'py> {

pub fn py_any_to_loro_values(obj: &Bound<'_, PyAny>) -> PyResult<Vec<CoreLoroValue>> {
let sequence = obj
.downcast::<PySequence>()
.cast::<PySequence>()
.map_err(|_| PyTypeError::new_err("can only assign an iterable to a slice"))?;

let length = sequence.len()?;
Expand Down
20 changes: 10 additions & 10 deletions src/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,10 @@ pub fn pyobject_to_container_id(
obj: &Bound<'_, PyAny>,
ty: ContainerType,
) -> PyResult<loro::ContainerID> {
if let Ok(value) = obj.downcast::<PyString>() {
if let Ok(value) = obj.cast::<PyString>() {
return Ok(loro::ContainerID::new_root(value.to_str()?, ty.into()));
}
if let Ok(value) = obj.downcast::<ContainerID>() {
if let Ok(value) = obj.cast::<ContainerID>() {
return Ok(loro::ContainerID::from(value.get()));
}

Expand All @@ -73,27 +73,27 @@ pub fn pyobject_to_loro_value(obj: &Bound<'_, PyAny>) -> PyResult<loro::LoroValu
if let Ok(value) = obj.extract::<f64>() {
return Ok(loro::LoroValue::Double(value));
}
if let Ok(value) = obj.downcast::<PyBytes>() {
if let Ok(value) = obj.cast::<PyBytes>() {
return Ok(loro::LoroValue::Binary(loro::LoroBinaryValue::from(
value.as_bytes().to_vec(),
)));
}
if let Ok(value) = obj.downcast::<PyString>() {
if let Ok(value) = obj.cast::<PyString>() {
return Ok(loro::LoroValue::String(loro::LoroStringValue::from(
value.to_string(),
)));
}
if let Ok(value) = obj.downcast::<PyList>() {
if let Ok(value) = obj.cast::<PyList>() {
let mut list = Vec::with_capacity(value.len());
for item in value.iter() {
list.push(pyobject_to_loro_value(&item)?);
}
return Ok(loro::LoroValue::List(loro::LoroListValue::from(list)));
}
if let Ok(value) = obj.downcast::<PyDict>() {
if let Ok(value) = obj.cast::<PyDict>() {
let mut map = FxHashMap::default();
for (key, value) in value.iter() {
if key.downcast::<PyString>().is_ok() {
if key.cast::<PyString>().is_ok() {
map.insert(key.to_string(), pyobject_to_loro_value(&value)?);
} else {
return Err(PyTypeError::new_err(
Expand All @@ -103,10 +103,10 @@ pub fn pyobject_to_loro_value(obj: &Bound<'_, PyAny>) -> PyResult<loro::LoroValu
}
return Ok(loro::LoroValue::Map(loro::LoroMapValue::from(map)));
}
if let Ok(value) = obj.downcast::<PyMapping>() {
if let Ok(value) = obj.cast::<PyMapping>() {
let mut map = FxHashMap::default();
for key in value.keys()? {
if key.downcast::<PyString>().is_ok() {
if key.cast::<PyString>().is_ok() {
map.insert(
key.to_string(),
pyobject_to_loro_value(&value.get_item(key).unwrap())?,
Expand All @@ -119,7 +119,7 @@ pub fn pyobject_to_loro_value(obj: &Bound<'_, PyAny>) -> PyResult<loro::LoroValu
}
return Ok(loro::LoroValue::Map(loro::LoroMapValue::from(map)));
}
if let Ok(value) = obj.downcast::<ContainerID>() {
if let Ok(value) = obj.cast::<ContainerID>() {
return Ok(loro::LoroValue::Container(value.get().clone().into()));
}
Err(PyTypeError::new_err("Invalid LoroValue"))
Expand Down
Loading