Mercurial > public > mercurial-scm > hg
view rust/hg-cpython/src/filepatterns.rs @ 42328:94f3a73b6672
rust-filepatterns: add `rust-cpython` bindings for `filepatterns`
This change adds the `rust-cpython` interface for top-level functions and
exceptions in the filepatterns module.
Contrary to the Python implementation, this tries to have finer-grained
exceptions to allow for better readability and flow control down the line.
Differential Revision: https://phab.mercurial-scm.org/D6272
author | Rapha?l Gom?s <rgomes@octobus.net> |
---|---|
date | Fri, 17 May 2019 09:36:29 -0400 |
parents | rust/hg-cpython/src/ancestors.rs@060c030c9993 |
children | 9609430d3625 |
line wrap: on
line source
// filepatterns.rs // // Copyright 2019, Georges Racinet <gracinet@anybox.fr>, // Raphaël Gomès <rgomes@octobus.net> // // 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::filepatterns` module provided by the //! `hg-core` crate. From Python, this will be seen as `rustext.filepatterns` //! and can be used as replacement for the the pure `filepatterns` Python module. //! use cpython::{ exc, PyDict, PyErr, PyModule, PyResult, PyString, PyTuple, Python, ToPyObject, }; use hg::{build_single_regex, read_pattern_file, PatternTuple}; use exceptions::{ PatternError, PatternFileError, }; /// Rust does not like functions with different return signatures. /// The 3-tuple version is always returned by the hg-core function, /// the (potential) conversion is handled at this level since it is not likely /// to have any measurable impact on performance. /// /// The Python implementation passes a function reference for `warn` instead /// of a boolean that is used to emit warnings while parsing. The Rust /// implementation chooses to accumulate the warnings and propagate them to /// Python upon completion. See the `readpatternfile` function in `match.py` /// for more details. fn read_pattern_file_wrapper( py: Python, file_path: String, warn: bool, source_info: bool, ) -> PyResult<PyTuple> { match read_pattern_file(file_path, warn) { Ok((patterns, warnings)) => { if source_info { return Ok((patterns, warnings).to_py_object(py)); } let itemgetter = |x: &PatternTuple| x.0.to_py_object(py); let results: Vec<PyString> = patterns.iter().map(itemgetter).collect(); Ok((results, warnings).to_py_object(py)) } Err(e) => Err(PatternFileError::pynew(py, e)), } } fn build_single_regex_wrapper( py: Python, kind: String, pat: String, globsuffix: String, ) -> PyResult<PyString> { match build_single_regex( kind.as_ref(), pat.as_bytes(), globsuffix.as_bytes(), ) { Ok(regex) => match String::from_utf8(regex) { Ok(regex) => Ok(regex.to_py_object(py)), Err(e) => Err(PyErr::new::<exc::UnicodeDecodeError, _>( py, e.to_string(), )), }, Err(e) => Err(PatternError::pynew(py, e)), } } pub fn init_module(py: Python, package: &str) -> PyResult<PyModule> { let dotted_name = &format!("{}.filepatterns", package); let m = PyModule::new(py, dotted_name)?; m.add(py, "__package__", package)?; m.add( py, "__doc__", "Patterns files parsing - Rust implementation", )?; m.add( py, "build_single_regex", py_fn!( py, build_single_regex_wrapper( kind: String, pat: String, globsuffix: String ) ), )?; m.add( py, "read_pattern_file", py_fn!( py, read_pattern_file_wrapper( file_path: String, warn: bool, source_info: bool ) ), )?; let sys = PyModule::import(py, "sys")?; let sys_modules: PyDict = sys.get(py, "modules")?.extract(py)?; sys_modules.set_item(py, dotted_name, &m)?; Ok(m) }