// dirs_multiset.rs // // Copyright 2019 Raphaël Gomès // // This software may be used and distributed according to the terms of the // GNU General Public License version 2 or any later version. //! Bindings for the `hg::dirstate::dirs_multiset` file provided by the //! `hg-core` package. use std::cell::RefCell; use std::convert::TryInto; use cpython::{ exc, ObjectProtocol, PyBytes, PyClone, PyDict, PyErr, PyObject, PyResult, Python, }; use crate::{ dirstate::extract_dirstate, ref_sharing::{PySharedRefCell, PySharedState}, }; use hg::{ utils::hg_path::{HgPath, HgPathBuf}, DirsMultiset, DirsMultisetIter, DirstateMapError, DirstateParseError, EntryState, }; py_class!(pub class Dirs |py| { data inner: PySharedRefCell; data py_shared_state: PySharedState; // `map` is either a `dict` or a flat iterator (usually a `set`, sometimes // a `list`) def __new__( _cls, map: PyObject, skip: Option = None ) -> PyResult { let mut skip_state: Option = None; if let Some(skip) = skip { skip_state = Some( skip.extract::(py)?.data(py)[0] .try_into() .map_err(|e: DirstateParseError| { PyErr::new::(py, e.to_string()) })?, ); } let inner = if let Ok(map) = map.cast_as::(py) { let dirstate = extract_dirstate(py, &map)?; DirsMultiset::from_dirstate(&dirstate, skip_state) } else { let map: Result, PyErr> = map .iter(py)? .map(|o| { Ok(HgPathBuf::from_bytes( o?.extract::(py)?.data(py), )) }) .collect(); DirsMultiset::from_manifest(&map?) }; Self::create_instance( py, PySharedRefCell::new(inner), PySharedState::default() ) } def addpath(&self, path: PyObject) -> PyResult { self.borrow_mut(py)?.add_path( HgPath::new(path.extract::(py)?.data(py)), ); Ok(py.None()) } def delpath(&self, path: PyObject) -> PyResult { self.borrow_mut(py)?.delete_path( HgPath::new(path.extract::(py)?.data(py)), ) .and(Ok(py.None())) .or_else(|e| { match e { DirstateMapError::PathNotFound(_p) => { Err(PyErr::new::( py, "expected a value, found none".to_string(), )) } DirstateMapError::EmptyPath => { Ok(py.None()) } } }) } def __iter__(&self) -> PyResult { let (leak_handle, leaked_ref) = unsafe { self.leak_immutable(py)? }; DirsMultisetKeysIterator::from_inner( py, leak_handle, leaked_ref.iter(), ) } def __contains__(&self, item: PyObject) -> PyResult { Ok(self.inner(py).borrow().contains(HgPath::new( item.extract::(py)?.data(py).as_ref(), ))) } }); py_shared_ref!(Dirs, DirsMultiset, inner, DirsMultisetLeakedRef,); impl Dirs { pub fn from_inner(py: Python, d: DirsMultiset) -> PyResult { Self::create_instance( py, PySharedRefCell::new(d), PySharedState::default(), ) } fn translate_key( py: Python, res: &HgPathBuf, ) -> PyResult> { Ok(Some(PyBytes::new(py, res.as_ref()))) } } py_shared_iterator!( DirsMultisetKeysIterator, DirsMultisetLeakedRef, DirsMultisetIter<'static>, Dirs::translate_key, Option );