Mercurial > public > mercurial-scm > hg
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, ®ex)), |
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) |