# gc.rs - source
Source of the Rust file `/home/runner/.cargo/registry/src/github.com-1ecc6299db9ec823/pyo3-0.13.2/src/class/gc.rs`.
Keywords: rust, rustlang, rust-lang

     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
    79
    80
    81
    82
    83
    84
    85
    86

    // Copyright (c) 2017-present PyO3 Project and Contributors

    //! Python GC support
    //!

    use crate::{ffi, AsPyPointer, PyCell, PyClass, Python};
    use std::os::raw::{c_int, c_void};

    #[repr(transparent)]
    pub struct PyTraverseError(c_int);

    /// GC support
    pub trait PyGCProtocol<'p>: PyClass {
        fn __traverse__(&'p self, visit: PyVisit) -> Result<(), PyTraverseError>;
        fn __clear__(&'p mut self);
    }

    pub trait PyGCTraverseProtocol<'p>: PyGCProtocol<'p> {}
    pub trait PyGCClearProtocol<'p>: PyGCProtocol<'p> {}

    #[doc(hidden)]
    pub unsafe extern "C" fn traverse<T>(
        slf: *mut ffi::PyObject,
        visit: ffi::visitproc,
        arg: *mut c_void,
    ) -> c_int
    where
        T: for<'p> PyGCTraverseProtocol<'p>,
    {
        let pool = crate::GILPool::new();
        let py = pool.python();
        let slf = py.from_borrowed_ptr::<PyCell<T>>(slf);

        let visit = PyVisit {
            visit,
            arg,
            _py: py,
        };
        let borrow = slf.try_borrow();
        if let Ok(borrow) = borrow {
            match borrow.__traverse__(visit) {
                Ok(()) => 0,
                Err(PyTraverseError(code)) => code,
            }
        } else {
            0
        }
    }

    #[doc(hidden)]
    pub unsafe extern "C" fn clear<T>(slf: *mut ffi::PyObject) -> c_int
    where
        T: for<'p> PyGCClearProtocol<'p>,
    {
        let pool = crate::GILPool::new();
        let slf = pool.python().from_borrowed_ptr::<PyCell<T>>(slf);

        slf.borrow_mut().__clear__();
        0
    }

    /// Object visitor for GC.
    #[derive(Clone)]
    pub struct PyVisit<'p> {
        visit: ffi::visitproc,
        arg: *mut c_void,
        /// VisitProc contains a Python instance to ensure that
        /// 1) it is cannot be moved out of the traverse() call
        /// 2) it cannot be sent to other threads
        _py: Python<'p>,
    }

    impl<'p> PyVisit<'p> {
        /// Visit `obj`.
        pub fn call<T>(&self, obj: &T) -> Result<(), PyTraverseError>
        where
            T: AsPyPointer,
        {
            let r = unsafe { (self.visit)(obj.as_ptr(), self.arg) };
            if r == 0 {
                Ok(())
            } else {
                Err(PyTraverseError(r))
            }
        }
    }