use pyo3::exceptions::{PyStopIteration, PyTypeError};
use pyo3::inspect::PyStaticExpr;
use pyo3::prelude::*;
use pyo3::types::{PyAny, PyString};
use pyo3::{Borrowed, FromPyObject, type_hint_identifier, type_hint_subscript, type_hint_union};
use crate::python_tree::{Entry, PythonAvlTree};
#[pymodule]
mod rs_avl {
use super::*;
const ANY: PyStaticExpr = type_hint_identifier!("typing", "Any");
const CALLABLE_ARGUMENTS: PyStaticExpr = PyStaticExpr::List { elts: &[ANY] };
const KEY_CALLABLE: PyStaticExpr = type_hint_subscript!(
type_hint_identifier!("typing", "Callable"),
CALLABLE_ARGUMENTS,
ANY
);
struct PythonValues(Vec<Py<PyAny>>);
impl<'a, 'py> FromPyObject<'a, 'py> for PythonValues {
type Error = PyErr;
const INPUT_TYPE: PyStaticExpr = type_hint_subscript!(
type_hint_identifier!("typing", "Iterable"),
type_hint_identifier!("typing", "Any")
);
fn extract(value: Borrowed<'a, 'py, PyAny>) -> PyResult<Self> {
let mut values = Vec::new();
for value in value.try_iter()? {
values.push(value?.unbind());
}
Ok(Self(values))
}
}
enum KeyExtractor {
Identity,
Attribute(String),
Callable(Py<PyAny>),
}
impl KeyExtractor {
fn extract(&self, py: Python<'_>, value: &Py<PyAny>) -> PyResult<Py<PyAny>> {
match self {
Self::Identity => Ok(value.clone_ref(py)),
Self::Attribute(name) => Ok(value.bind(py).getattr(name.as_str())?.unbind()),
Self::Callable(callable) => {
Ok(callable.bind(py).call1((value.bind(py),))?.unbind())
}
}
}
}
impl<'a, 'py> FromPyObject<'a, 'py> for KeyExtractor {
type Error = PyErr;
const INPUT_TYPE: PyStaticExpr =
type_hint_union!(type_hint_identifier!("builtins", "str"), KEY_CALLABLE);
fn extract(value: Borrowed<'a, 'py, PyAny>) -> PyResult<Self> {
if let Ok(name) = value.cast::<PyString>() {
return Ok(Self::Attribute(name.to_str()?.to_owned()));
}
if value.is_callable() {
return Ok(Self::Callable(value.to_owned().unbind()));
}
Err(PyTypeError::new_err(
"key must be an attribute name, a callable, or None",
))
}
}
#[pymodule_export]
#[expect(non_upper_case_globals)]
pub const __version__: &str = env!("CARGO_PKG_VERSION");
#[pymodule_export]
#[expect(non_upper_case_globals)]
pub const __all__: [&str; 2] = ["AVLTree", "__version__"];
#[pyclass(name = "AVLTree", module = "rs_avl")]
struct PyAVLTree {
inner: PythonAvlTree,
key: KeyExtractor,
}
#[pymethods]
impl PyAVLTree {
#[new]
#[pyo3(signature = (values = None, *, key = None))]
fn new(
py: Python<'_>,
values: Option<PythonValues>,
key: Option<KeyExtractor>,
) -> PyResult<Self> {
let key = key.unwrap_or(KeyExtractor::Identity);
let mut inner = PythonAvlTree::default();
if let Some(values) = values {
for value in values.0 {
let extracted = key.extract(py, &value)?;
inner.insert(py, Entry::new(value, extracted))?;
}
}
Ok(Self { inner, key })
}
fn insert(&mut self, py: Python<'_>, value: Py<PyAny>) -> PyResult<bool> {
let key = self.key.extract(py, &value)?;
self.inner.insert(py, Entry::new(value, key))
}
fn remove(&mut self, py: Python<'_>, value: Py<PyAny>) -> PyResult<bool> {
let key = self.key.extract(py, &value)?;
self.inner.remove(py, &key)
}
fn remove_key(&mut self, py: Python<'_>, key: Py<PyAny>) -> PyResult<bool> {
self.inner.remove(py, &key)
}
fn search(&self, py: Python<'_>, value: Py<PyAny>) -> PyResult<Option<Py<PyAny>>> {
let key = self.key.extract(py, &value)?;
self.inner.search(py, &key)
}
fn get(&self, py: Python<'_>, value: Py<PyAny>) -> PyResult<Option<Py<PyAny>>> {
self.search(py, value)
}
fn search_key(&self, py: Python<'_>, key: Py<PyAny>) -> PyResult<Option<Py<PyAny>>> {
self.inner.search(py, &key)
}
fn contains(&self, py: Python<'_>, value: Py<PyAny>) -> PyResult<bool> {
Ok(self.search(py, value)?.is_some())
}
fn has_node(&self, py: Python<'_>, value: Py<PyAny>) -> PyResult<bool> {
self.contains(py, value)
}
fn contains_key(&self, py: Python<'_>, key: Py<PyAny>) -> PyResult<bool> {
Ok(self.inner.search(py, &key)?.is_some())
}
fn clear(&mut self) {
self.inner.clear();
}
fn is_empty(&self) -> bool {
self.inner.is_empty()
}
#[getter]
fn height(&self) -> usize {
self.inner.height()
}
fn first(&self, py: Python<'_>) -> Option<Py<PyAny>> {
self.inner.first(py)
}
fn min(&self, py: Python<'_>) -> Option<Py<PyAny>> {
self.first(py)
}
fn last(&self, py: Python<'_>) -> Option<Py<PyAny>> {
self.inner.last(py)
}
fn max(&self, py: Python<'_>) -> Option<Py<PyAny>> {
self.last(py)
}
#[pyo3(signature = (start = None, end = None, *, include_start = true, include_end = false))]
fn range(
&self,
py: Python<'_>,
start: Option<Py<PyAny>>,
end: Option<Py<PyAny>>,
include_start: bool,
include_end: bool,
) -> PyResult<PyAVLTreeIterator> {
Ok(PyAVLTreeIterator::new(self.inner.range(
py,
start.as_ref(),
end.as_ref(),
include_start,
include_end,
)?))
}
fn in_order(&self, py: Python<'_>) -> PyAVLTreeIterator {
PyAVLTreeIterator::new(self.inner.in_order(py))
}
fn pre_order(&self, py: Python<'_>) -> PyAVLTreeIterator {
PyAVLTreeIterator::new(self.inner.pre_order(py))
}
fn post_order(&self, py: Python<'_>) -> PyAVLTreeIterator {
PyAVLTreeIterator::new(self.inner.post_order(py))
}
fn level_order(&self, py: Python<'_>) -> PyAVLTreeIterator {
PyAVLTreeIterator::new(self.inner.level_order(py))
}
fn __len__(&self) -> usize {
self.inner.len()
}
fn __bool__(&self) -> bool {
!self.inner.is_empty()
}
fn __contains__(&self, py: Python<'_>, value: Py<PyAny>) -> PyResult<bool> {
self.contains(py, value)
}
fn __iter__(&self, py: Python<'_>) -> PyAVLTreeIterator {
self.in_order(py)
}
fn __repr__(&self, py: Python<'_>) -> PyResult<String> {
let representations = self
.inner
.in_order(py)
.into_iter()
.map(|value| Ok(value.bind(py).repr()?.to_str()?.to_owned()))
.collect::<PyResult<Vec<_>>>()?;
Ok(format!("AVLTree([{}])", representations.join(", ")))
}
}
#[pyclass(name = "_AVLTreeIterator", module = "rs_avl")]
struct PyAVLTreeIterator {
values: std::vec::IntoIter<Py<PyAny>>,
}
impl PyAVLTreeIterator {
fn new(values: Vec<Py<PyAny>>) -> Self {
Self {
values: values.into_iter(),
}
}
}
#[pymethods]
impl PyAVLTreeIterator {
fn __iter__(slf: PyRef<'_, Self>) -> PyRef<'_, Self> {
slf
}
fn __next__(&mut self) -> PyResult<Py<PyAny>> {
self.values
.next()
.ok_or_else(|| PyStopIteration::new_err(()))
}
}
}