comparison rust/hg-cpython/src/filepatterns.rs @ 42437:9609430d3625

rust-filepatterns: use bytes instead of String In my initial patch, I introduced an unnecessary hard constraint on UTF-8 filenames and patterns which I forgot to remove. Although the performance penalty for using String might be negligible, we don't want to break compatibility with non-UTF-8 encodings for no reason. Moreover, this change allows for a cleaner Rust core API. This patch introduces a new utils module that is used with this fix. Finally, PatternError was not put inside the Python module generated by Rust, which would have raised a NameError. Differential Revision: https://phab.mercurial-scm.org/D6485
author Rapha?l Gom?s <rgomes@octobus.net>
date Thu, 06 Jun 2019 15:30:56 +0200
parents 94f3a73b6672
children 326fdce22fb2
comparison
equal deleted inserted replaced
42436:dc5bd66a8270 42437:9609430d3625
9 //! Bindings for the `hg::filepatterns` module provided by the 9 //! Bindings for the `hg::filepatterns` module provided by the
10 //! `hg-core` crate. From Python, this will be seen as `rustext.filepatterns` 10 //! `hg-core` crate. From Python, this will be seen as `rustext.filepatterns`
11 //! and can be used as replacement for the the pure `filepatterns` Python module. 11 //! and can be used as replacement for the the pure `filepatterns` Python module.
12 //! 12 //!
13 use cpython::{ 13 use cpython::{
14 exc, PyDict, PyErr, PyModule, PyResult, PyString, PyTuple, Python, 14 PyBytes, PyDict, PyModule, PyObject, PyResult, PyTuple, Python, ToPyObject,
15 ToPyObject,
16 }; 15 };
17 use hg::{build_single_regex, read_pattern_file, PatternTuple}; 16 use exceptions::{PatternError, PatternFileError};
18 use exceptions::{ 17 use hg::{build_single_regex, read_pattern_file, LineNumber, PatternTuple};
19 PatternError,
20 PatternFileError,
21 };
22 18
23 /// Rust does not like functions with different return signatures. 19 /// Rust does not like functions with different return signatures.
24 /// The 3-tuple version is always returned by the hg-core function, 20 /// The 3-tuple version is always returned by the hg-core function,
25 /// the (potential) conversion is handled at this level since it is not likely 21 /// the (potential) conversion is handled at this level since it is not likely
26 /// to have any measurable impact on performance. 22 /// to have any measurable impact on performance.
30 /// implementation chooses to accumulate the warnings and propagate them to 26 /// implementation chooses to accumulate the warnings and propagate them to
31 /// Python upon completion. See the `readpatternfile` function in `match.py` 27 /// Python upon completion. See the `readpatternfile` function in `match.py`
32 /// for more details. 28 /// for more details.
33 fn read_pattern_file_wrapper( 29 fn read_pattern_file_wrapper(
34 py: Python, 30 py: Python,
35 file_path: String, 31 file_path: PyObject,
36 warn: bool, 32 warn: bool,
37 source_info: bool, 33 source_info: bool,
38 ) -> PyResult<PyTuple> { 34 ) -> PyResult<PyTuple> {
39 match read_pattern_file(file_path, warn) { 35 match read_pattern_file(file_path.extract::<PyBytes>(py)?.data(py), warn) {
40 Ok((patterns, warnings)) => { 36 Ok((patterns, warnings)) => {
41 if source_info { 37 if source_info {
42 return Ok((patterns, warnings).to_py_object(py)); 38 let itemgetter = |x: &PatternTuple| {
39 (PyBytes::new(py, &x.0), x.1, PyBytes::new(py, &x.2))
40 };
41 let results: Vec<(PyBytes, LineNumber, PyBytes)> =
42 patterns.iter().map(itemgetter).collect();
43 return Ok((results, warnings).to_py_object(py));
43 } 44 }
44 let itemgetter = |x: &PatternTuple| x.0.to_py_object(py); 45 let itemgetter = |x: &PatternTuple| PyBytes::new(py, &x.0);
45 let results: Vec<PyString> = 46 let results: Vec<PyBytes> =
46 patterns.iter().map(itemgetter).collect(); 47 patterns.iter().map(itemgetter).collect();
47 Ok((results, warnings).to_py_object(py)) 48 Ok((results, warnings).to_py_object(py))
48 } 49 }
49 Err(e) => Err(PatternFileError::pynew(py, e)), 50 Err(e) => Err(PatternFileError::pynew(py, e)),
50 } 51 }
51 } 52 }
52 53
53 fn build_single_regex_wrapper( 54 fn build_single_regex_wrapper(
54 py: Python, 55 py: Python,
55 kind: String, 56 kind: PyObject,
56 pat: String, 57 pat: PyObject,
57 globsuffix: String, 58 globsuffix: PyObject,
58 ) -> PyResult<PyString> { 59 ) -> PyResult<PyBytes> {
59 match build_single_regex( 60 match build_single_regex(
60 kind.as_ref(), 61 kind.extract::<PyBytes>(py)?.data(py),
61 pat.as_bytes(), 62 pat.extract::<PyBytes>(py)?.data(py),
62 globsuffix.as_bytes(), 63 globsuffix.extract::<PyBytes>(py)?.data(py),
63 ) { 64 ) {
64 Ok(regex) => match String::from_utf8(regex) { 65 Ok(regex) => Ok(PyBytes::new(py, &regex)),
65 Ok(regex) => Ok(regex.to_py_object(py)),
66 Err(e) => Err(PyErr::new::<exc::UnicodeDecodeError, _>(
67 py,
68 e.to_string(),
69 )),
70 },
71 Err(e) => Err(PatternError::pynew(py, e)), 66 Err(e) => Err(PatternError::pynew(py, e)),
72 } 67 }
73 } 68 }
74 69
75 pub fn init_module(py: Python, package: &str) -> PyResult<PyModule> { 70 pub fn init_module(py: Python, package: &str) -> PyResult<PyModule> {
86 py, 81 py,
87 "build_single_regex", 82 "build_single_regex",
88 py_fn!( 83 py_fn!(
89 py, 84 py,
90 build_single_regex_wrapper( 85 build_single_regex_wrapper(
91 kind: String, 86 kind: PyObject,
92 pat: String, 87 pat: PyObject,
93 globsuffix: String 88 globsuffix: PyObject
94 ) 89 )
95 ), 90 ),
96 )?; 91 )?;
97 m.add( 92 m.add(
98 py, 93 py,
99 "read_pattern_file", 94 "read_pattern_file",
100 py_fn!( 95 py_fn!(
101 py, 96 py,
102 read_pattern_file_wrapper( 97 read_pattern_file_wrapper(
103 file_path: String, 98 file_path: PyObject,
104 warn: bool, 99 warn: bool,
105 source_info: bool 100 source_info: bool
106 ) 101 )
107 ), 102 ),
108 )?; 103 )?;
109 104 m.add(py, "PatternError", py.get_type::<PatternError>())?;
110 let sys = PyModule::import(py, "sys")?; 105 let sys = PyModule::import(py, "sys")?;
111 let sys_modules: PyDict = sys.get(py, "modules")?.extract(py)?; 106 let sys_modules: PyDict = sys.get(py, "modules")?.extract(py)?;
112 sys_modules.set_item(py, dotted_name, &m)?; 107 sys_modules.set_item(py, dotted_name, &m)?;
113 108
114 Ok(m) 109 Ok(m)