rust/hg-cpython/src/ancestors.rs
changeset 41053 d9f439fcdb4c
parent 40965 5532823e8c18
child 41114 b31a41f24864
equal deleted inserted replaced
41052:4c25038c112c 41053:d9f439fcdb4c
     5 // This software may be used and distributed according to the terms of the
     5 // This software may be used and distributed according to the terms of the
     6 // GNU General Public License version 2 or any later version.
     6 // GNU General Public License version 2 or any later version.
     7 
     7 
     8 //! Bindings for the hg::ancestors module provided by the
     8 //! Bindings for the hg::ancestors module provided by the
     9 //! `hg-core` crate. From Python, this will be seen as `rustext.ancestor`
     9 //! `hg-core` crate. From Python, this will be seen as `rustext.ancestor`
    10 use cpython::{PyDict, PyModule, PyResult, Python};
    10 use cindex::Index;
       
    11 use cpython::{
       
    12     ObjectProtocol, PyClone, PyDict, PyModule, PyObject, PyResult, Python,
       
    13 };
       
    14 use exceptions::GraphError;
       
    15 use hg;
       
    16 use hg::AncestorsIterator as CoreIterator;
       
    17 use hg::Revision;
       
    18 use std::cell::RefCell;
       
    19 
       
    20 /// Utility function to convert a Python iterable into a Vec<Revision>
       
    21 ///
       
    22 /// We need this to feed to AncestorIterators constructors because
       
    23 /// a PyErr can arise at each step of iteration, whereas our inner objects
       
    24 /// expect iterables over Revision, not over some Result<Revision, PyErr>
       
    25 fn reviter_to_revvec(py: Python, revs: PyObject) -> PyResult<Vec<Revision>> {
       
    26     revs.iter(py)?
       
    27         .map(|r| r.and_then(|o| o.extract::<Revision>(py)))
       
    28         .collect()
       
    29 }
       
    30 
       
    31 py_class!(class AncestorsIterator |py| {
       
    32     // TODO RW lock ?
       
    33     data inner: RefCell<Box<CoreIterator<Index>>>;
       
    34 
       
    35     def __next__(&self) -> PyResult<Option<Revision>> {
       
    36         match self.inner(py).borrow_mut().next() {
       
    37             Some(Err(e)) => Err(GraphError::pynew(py, e)),
       
    38             None => Ok(None),
       
    39             Some(Ok(r)) => Ok(Some(r)),
       
    40         }
       
    41     }
       
    42 
       
    43     def __contains__(&self, rev: Revision) -> PyResult<bool> {
       
    44         self.inner(py).borrow_mut().contains(rev).map_err(|e| GraphError::pynew(py, e))
       
    45     }
       
    46 
       
    47     def __iter__(&self) -> PyResult<Self> {
       
    48         Ok(self.clone_ref(py))
       
    49     }
       
    50 
       
    51     def __new__(_cls, index: PyObject, initrevs: PyObject, stoprev: Revision,
       
    52                 inclusive: bool) -> PyResult<AncestorsIterator> {
       
    53         let initvec = reviter_to_revvec(py, initrevs)?;
       
    54         let ait = match hg::AncestorsIterator::new(Index::new(py, index)?,
       
    55                                                    initvec, stoprev,
       
    56                                                    inclusive) {
       
    57             Ok(ait) => ait,
       
    58             Err(e) => {
       
    59                 return Err(GraphError::pynew(py, e));
       
    60             }
       
    61         };
       
    62         AncestorsIterator::from_inner(py, ait)
       
    63     }
       
    64 
       
    65 });
       
    66 
       
    67 impl AncestorsIterator {
       
    68     pub fn from_inner(py: Python, ait: CoreIterator<Index>) -> PyResult<Self> {
       
    69         Self::create_instance(py, RefCell::new(Box::new(ait)))
       
    70     }
       
    71 }
    11 
    72 
    12 /// Create the module, with __package__ given from parent
    73 /// Create the module, with __package__ given from parent
    13 pub fn init_module(py: Python, package: &str) -> PyResult<PyModule> {
    74 pub fn init_module(py: Python, package: &str) -> PyResult<PyModule> {
    14     let dotted_name = &format!("{}.ancestor", package);
    75     let dotted_name = &format!("{}.ancestor", package);
    15     let m = PyModule::new(py, dotted_name)?;
    76     let m = PyModule::new(py, dotted_name)?;
    17     m.add(
    78     m.add(
    18         py,
    79         py,
    19         "__doc__",
    80         "__doc__",
    20         "Generic DAG ancestor algorithms - Rust implementation",
    81         "Generic DAG ancestor algorithms - Rust implementation",
    21     )?;
    82     )?;
       
    83     m.add_class::<AncestorsIterator>(py)?;
    22 
    84 
    23     let sys = PyModule::import(py, "sys")?;
    85     let sys = PyModule::import(py, "sys")?;
    24     let sys_modules: PyDict = sys.get(py, "modules")?.extract(py)?;
    86     let sys_modules: PyDict = sys.get(py, "modules")?.extract(py)?;
    25     sys_modules.set_item(py, dotted_name, &m)?;
    87     sys_modules.set_item(py, dotted_name, &m)?;
    26     // Example C code (see pyexpat.c and import.c) will "give away the
    88     // Example C code (see pyexpat.c and import.c) will "give away the