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) |