forked from pydantic/pydantic-core
-
Notifications
You must be signed in to change notification settings - Fork 0
/
py_gc.rs
78 lines (69 loc) · 2.24 KB
/
py_gc.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
use std::sync::Arc;
use ahash::AHashMap;
use enum_dispatch::enum_dispatch;
use pyo3::{AsPyPointer, Py, PyTraverseError, PyVisit};
/// Trait implemented by types which can be traversed by the Python GC.
#[enum_dispatch]
pub trait PyGcTraverse {
fn py_gc_traverse(&self, visit: &PyVisit<'_>) -> Result<(), PyTraverseError>;
}
impl<T> PyGcTraverse for Py<T>
where
Py<T>: AsPyPointer,
{
fn py_gc_traverse(&self, visit: &PyVisit<'_>) -> Result<(), PyTraverseError> {
visit.call(self)
}
}
impl<T: PyGcTraverse> PyGcTraverse for Vec<T> {
fn py_gc_traverse(&self, visit: &PyVisit<'_>) -> Result<(), PyTraverseError> {
for item in self {
item.py_gc_traverse(visit)?;
}
Ok(())
}
}
impl<T: PyGcTraverse> PyGcTraverse for AHashMap<String, T> {
fn py_gc_traverse(&self, visit: &PyVisit<'_>) -> Result<(), PyTraverseError> {
for item in self.values() {
item.py_gc_traverse(visit)?;
}
Ok(())
}
}
impl<T: PyGcTraverse> PyGcTraverse for Arc<T> {
fn py_gc_traverse(&self, visit: &PyVisit<'_>) -> Result<(), PyTraverseError> {
T::py_gc_traverse(self, visit)
}
}
impl<T: PyGcTraverse> PyGcTraverse for Box<T> {
fn py_gc_traverse(&self, visit: &PyVisit<'_>) -> Result<(), PyTraverseError> {
T::py_gc_traverse(self, visit)
}
}
impl<T: PyGcTraverse> PyGcTraverse for Option<T> {
fn py_gc_traverse(&self, visit: &PyVisit<'_>) -> Result<(), PyTraverseError> {
match self {
Some(item) => T::py_gc_traverse(item, visit),
None => Ok(()),
}
}
}
/// A crude alternative to a "derive" macro to help with building PyGcTraverse implementations
macro_rules! impl_py_gc_traverse {
($name:ty { }) => {
impl crate::py_gc::PyGcTraverse for $name {
fn py_gc_traverse(&self, _visit: &pyo3::PyVisit<'_>) -> Result<(), pyo3::PyTraverseError> {
Ok(())
}
}
};
($name:ty { $($fields:ident),* }) => {
impl crate::py_gc::PyGcTraverse for $name {
fn py_gc_traverse(&self, visit: &pyo3::PyVisit<'_>) -> Result<(), pyo3::PyTraverseError> {
$(self.$fields.py_gc_traverse(visit)?;)*
Ok(())
}
}
};
}