Skip to content

Commit

Permalink
Use the threadsafe rpds structures by default.
Browse files Browse the repository at this point in the history
We should probably have separate APIs to expose each (of course there
are already lots of things missing from these bindings) but for now
doing this doesn't seem to have a huge performance impact from simple
microbenchmarks, whereas without this, you can't share a global Python
HashTrieMap across multiple threads at all.
  • Loading branch information
Julian committed Mar 20, 2023
1 parent 4471c4c commit 91fac5b
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 27 deletions.
14 changes: 12 additions & 2 deletions Cargo.lock

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

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "rpds-py"
version = "0.6.1"
version = "0.7.0"
edition = "2021"

[lib]
Expand All @@ -9,6 +9,7 @@ crate-type = ["cdylib"]

[dependencies]
rpds = "0.12.0"
archery = "0.5.0"

[dependencies.pyo3]
version = "0.18.1"
Expand Down
50 changes: 26 additions & 24 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use pyo3::pyclass::CompareOp;
use pyo3::types::{PyDict, PyIterator, PyTuple, PyType};
use pyo3::{exceptions::PyKeyError, types::PyMapping};
use pyo3::{prelude::*, AsPyPointer};
use rpds::{HashTrieMap, HashTrieSet, List};
use rpds::{HashTrieMap, HashTrieMapSync, HashTrieSet, HashTrieSetSync, List, ListSync};

#[derive(Clone, Debug)]
struct Key {
Expand Down Expand Up @@ -55,20 +55,20 @@ impl<'source> FromPyObject<'source> for Key {
}

#[repr(transparent)]
#[pyclass(name = "HashTrieMap", module = "rpds", frozen, mapping, unsendable)]
#[pyclass(name = "HashTrieMap", module = "rpds", frozen, mapping)]
struct HashTrieMapPy {
inner: HashTrieMap<Key, PyObject>,
inner: HashTrieMapSync<Key, PyObject>,
}

impl From<HashTrieMap<Key, PyObject>> for HashTrieMapPy {
fn from(map: HashTrieMap<Key, PyObject>) -> Self {
impl From<HashTrieMapSync<Key, PyObject>> for HashTrieMapPy {
fn from(map: HashTrieMapSync<Key, PyObject>) -> Self {
HashTrieMapPy { inner: map }
}
}

impl<'source> FromPyObject<'source> for HashTrieMapPy {
fn extract(ob: &'source PyAny) -> PyResult<Self> {
let mut ret = HashTrieMap::new();
let mut ret = HashTrieMap::new_sync();
if let Ok(mapping) = ob.downcast::<PyMapping>() {
for each in mapping.items()?.iter()? {
let (k, v): (Key, PyObject) = each?.extract()?;
Expand All @@ -94,7 +94,7 @@ impl HashTrieMapPy {
map = value;
} else {
map = HashTrieMapPy {
inner: HashTrieMap::new(),
inner: HashTrieMap::new_sync(),
};
}
if let Some(kwds) = kwds {
Expand Down Expand Up @@ -239,7 +239,7 @@ impl HashTrieMapPy {
}
}

#[pyclass(module = "rpds", unsendable)]
#[pyclass(module = "rpds")]
struct KeyIterator {
inner: IntoIter<Key>,
}
Expand All @@ -256,14 +256,14 @@ impl KeyIterator {
}

#[repr(transparent)]
#[pyclass(name = "HashTrieSet", module = "rpds", frozen, unsendable)]
#[pyclass(name = "HashTrieSet", module = "rpds", frozen)]
struct HashTrieSetPy {
inner: HashTrieSet<Key>,
inner: HashTrieSetSync<Key>,
}

impl<'source> FromPyObject<'source> for HashTrieSetPy {
fn extract(ob: &'source PyAny) -> PyResult<Self> {
let mut ret = HashTrieSet::new();
let mut ret = HashTrieSet::new_sync();
for each in ob.iter()? {
let k: Key = each?.extract()?;
ret.insert_mut(k);
Expand All @@ -272,7 +272,7 @@ impl<'source> FromPyObject<'source> for HashTrieSetPy {
}
}

fn is_subset(one: &HashTrieSet<Key>, two: &HashTrieSet<Key>) -> bool {
fn is_subset(one: &HashTrieSetSync<Key>, two: &HashTrieSetSync<Key>) -> bool {
one.iter().all(|v| two.contains(v))
}

Expand All @@ -284,7 +284,7 @@ impl HashTrieSetPy {
value
} else {
HashTrieSetPy {
inner: HashTrieSet::new(),
inner: HashTrieSet::new_sync(),
}
}
}
Expand Down Expand Up @@ -383,8 +383,8 @@ impl HashTrieSetPy {
}

fn intersection(&self, other: &Self) -> HashTrieSetPy {
let mut inner: HashTrieSet<Key> = HashTrieSet::new();
let larger: &HashTrieSet<Key>;
let mut inner: HashTrieSetSync<Key> = HashTrieSet::new_sync();
let larger: &HashTrieSetSync<Key>;
let iter;
if self.inner.size() > other.inner.size() {
larger = &self.inner;
Expand All @@ -402,7 +402,7 @@ impl HashTrieSetPy {
}

fn symmetric_difference(&self, other: &Self) -> HashTrieSetPy {
let mut inner: HashTrieSet<Key>;
let mut inner: HashTrieSetSync<Key>;
let iter;
if self.inner.size() > other.inner.size() {
inner = self.inner.clone();
Expand All @@ -422,7 +422,7 @@ impl HashTrieSetPy {
}

fn union(&self, other: &Self) -> HashTrieSetPy {
let mut inner: HashTrieSet<Key>;
let mut inner: HashTrieSetSync<Key>;
let iter;
if self.inner.size() > other.inner.size() {
inner = self.inner.clone();
Expand Down Expand Up @@ -451,20 +451,20 @@ impl HashTrieSetPy {
}

#[repr(transparent)]
#[pyclass(name = "List", module = "rpds", frozen, sequence, unsendable)]
#[pyclass(name = "List", module = "rpds", frozen, sequence)]
struct ListPy {
inner: List<PyObject>,
inner: ListSync<PyObject>,
}

impl From<List<PyObject>> for ListPy {
fn from(elements: List<PyObject>) -> Self {
impl From<ListSync<PyObject>> for ListPy {
fn from(elements: ListSync<PyObject>) -> Self {
ListPy { inner: elements }
}
}

impl<'source> FromPyObject<'source> for ListPy {
fn extract(ob: &'source PyAny) -> PyResult<Self> {
let mut ret = List::new();
let mut ret = List::new_sync();
let reversed = PyModule::import(ob.py(), "builtins")?.getattr("reversed")?;
let rob: &PyIterator = reversed.call1((ob,))?.iter()?;
for each in rob {
Expand All @@ -483,7 +483,9 @@ impl ListPy {
if elements.len() == 1 {
ret = elements.get_item(0)?.extract()?;
} else {
ret = ListPy { inner: List::new() };
ret = ListPy {
inner: List::new_sync(),
};
if elements.len() > 1 {
for each in (0..elements.len()).rev() {
ret.inner
Expand Down Expand Up @@ -567,7 +569,7 @@ impl ListPy {
}
}

#[pyclass(module = "rpds", unsendable)]
#[pyclass(module = "rpds")]
struct ListIterator {
inner: IntoIter<PyObject>,
}
Expand Down

0 comments on commit 91fac5b

Please sign in to comment.