rust/hg-cpython/src/discovery.rs
changeset 42179 13b64247f48f
child 42180 1b0be75cb61f
equal deleted inserted replaced
42178:10b465d61556 42179:13b64247f48f
       
     1 // discovery.rs
       
     2 //
       
     3 // Copyright 2018 Georges Racinet <gracinet@anybox.fr>
       
     4 //
       
     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.
       
     7 
       
     8 //! Bindings for the `hg::discovery` module provided by the
       
     9 //! `hg-core` crate. From Python, this will be seen as `rustext.discovery`
       
    10 //!
       
    11 //! # Classes visible from Python:
       
    12 //! - [`PartialDiscover`] is the Rust implementation of
       
    13 //!   `mercurial.setdiscovery.partialdiscovery`.
       
    14 
       
    15 use crate::conversion::{py_set, rev_pyiter_collect};
       
    16 use cindex::Index;
       
    17 use cpython::{ObjectProtocol, PyDict, PyModule, PyObject, PyResult, Python};
       
    18 use exceptions::GraphError;
       
    19 use hg::discovery::PartialDiscovery as CorePartialDiscovery;
       
    20 use hg::Revision;
       
    21 
       
    22 use std::cell::RefCell;
       
    23 
       
    24 py_class!(pub class PartialDiscovery |py| {
       
    25     data inner: RefCell<Box<CorePartialDiscovery<Index>>>;
       
    26 
       
    27     def __new__(
       
    28         _cls,
       
    29         index: PyObject,
       
    30         targetheads: PyObject
       
    31     ) -> PyResult<PartialDiscovery> {
       
    32         Self::create_instance(
       
    33             py,
       
    34             RefCell::new(Box::new(CorePartialDiscovery::new(
       
    35                 Index::new(py, index)?,
       
    36                 rev_pyiter_collect(py, &targetheads)?,
       
    37             )))
       
    38         )
       
    39     }
       
    40 
       
    41     def addcommons(&self, commons: PyObject) -> PyResult<PyObject> {
       
    42         let mut inner = self.inner(py).borrow_mut();
       
    43         let commons_vec: Vec<Revision> = rev_pyiter_collect(py, &commons)?;
       
    44         inner.add_common_revisions(commons_vec)
       
    45             .map_err(|e| GraphError::pynew(py, e))?;
       
    46         Ok(py.None())
       
    47     }
       
    48 
       
    49     def addmissings(&self, missings: PyObject) -> PyResult<PyObject> {
       
    50         let mut inner = self.inner(py).borrow_mut();
       
    51         let missings_vec: Vec<Revision> = rev_pyiter_collect(py, &missings)?;
       
    52         inner.add_missing_revisions(missings_vec)
       
    53             .map_err(|e| GraphError::pynew(py, e))?;
       
    54         Ok(py.None())
       
    55     }
       
    56 
       
    57     def addinfo(&self, sample: PyObject) -> PyResult<PyObject> {
       
    58         let mut missing: Vec<Revision> = Vec::new();
       
    59         let mut common: Vec<Revision> = Vec::new();
       
    60         for info in sample.iter(py)? { // info is a pair (Revision, bool)
       
    61             let mut revknown = info?.iter(py)?;
       
    62             let rev: Revision = revknown.next().unwrap()?.extract(py)?;
       
    63             let known: bool = revknown.next().unwrap()?.extract(py)?;
       
    64             if known {
       
    65                 common.push(rev);
       
    66             } else {
       
    67                 missing.push(rev);
       
    68             }
       
    69         }
       
    70         let mut inner = self.inner(py).borrow_mut();
       
    71         inner.add_common_revisions(common)
       
    72             .map_err(|e| GraphError::pynew(py, e))?;
       
    73         inner.add_missing_revisions(missing)
       
    74             .map_err(|e| GraphError::pynew(py, e))?;
       
    75         Ok(py.None())
       
    76     }
       
    77 
       
    78     def hasinfo(&self) -> PyResult<bool> {
       
    79         Ok(self.inner(py).borrow().has_info())
       
    80     }
       
    81 
       
    82     def iscomplete(&self) -> PyResult<bool> {
       
    83         Ok(self.inner(py).borrow().is_complete())
       
    84     }
       
    85 
       
    86     def commonheads(&self) -> PyResult<PyObject> {
       
    87         py_set(
       
    88             py,
       
    89             &self.inner(py).borrow().common_heads()
       
    90                 .map_err(|e| GraphError::pynew(py, e))?
       
    91         )
       
    92     }
       
    93 });
       
    94 
       
    95 /// Create the module, with __package__ given from parent
       
    96 pub fn init_module(py: Python, package: &str) -> PyResult<PyModule> {
       
    97     let dotted_name = &format!("{}.discovery", package);
       
    98     let m = PyModule::new(py, dotted_name)?;
       
    99     m.add(py, "__package__", package)?;
       
   100     m.add(
       
   101         py,
       
   102         "__doc__",
       
   103         "Discovery of common node sets - Rust implementation",
       
   104     )?;
       
   105     m.add_class::<PartialDiscovery>(py)?;
       
   106 
       
   107     let sys = PyModule::import(py, "sys")?;
       
   108     let sys_modules: PyDict = sys.get(py, "modules")?.extract(py)?;
       
   109     sys_modules.set_item(py, dotted_name, &m)?;
       
   110     // Example C code (see pyexpat.c and import.c) will "give away the
       
   111     // reference", but we won't because it will be consumed once the
       
   112     // Rust PyObject is dropped.
       
   113     Ok(m)
       
   114 }