Mercurial > hg
comparison rust/hg-cpython/src/parsers.rs @ 42747:760a7851e9ba
rust-parsers: move parser bindings to their own file and Python module
This tidies up the Rust side while simplifying the Python side.
Differential Revision: https://phab.mercurial-scm.org/D6627
author | Raphaël Gomès <rgomes@octobus.net> |
---|---|
date | Wed, 10 Jul 2019 10:16:28 +0200 |
parents | rust/hg-cpython/src/dirstate.rs@b3518b0baa47 |
children | 7cae6bc29ff9 |
comparison
equal
deleted
inserted
replaced
42746:b3518b0baa47 | 42747:760a7851e9ba |
---|---|
1 // parsers.rs | |
2 // | |
3 // Copyright 2019 Raphaël Gomès <rgomes@octobus.net> | |
4 // | |
5 // This software may be used and distributed according to the terms of the | |
6 // GNU General Public License version 2 or any later version. | |
7 | |
8 //! Bindings for the `hg::dirstate::parsers` module provided by the | |
9 //! `hg-core` package. | |
10 //! | |
11 //! From Python, this will be seen as `mercurial.rustext.parsers` | |
12 //! | |
13 use cpython::{ | |
14 exc, PyBytes, PyDict, PyErr, PyInt, PyModule, PyResult, PyTuple, Python, | |
15 PythonObject, ToPyObject, | |
16 }; | |
17 use hg::{ | |
18 pack_dirstate, parse_dirstate, CopyVecEntry, DirstateEntry, | |
19 DirstatePackError, DirstateParents, DirstateParseError, | |
20 }; | |
21 use std::collections::HashMap; | |
22 | |
23 use libc::c_char; | |
24 | |
25 use crate::dirstate::{decapsule_make_dirstate_tuple, extract_dirstate_vec}; | |
26 | |
27 fn parse_dirstate_wrapper( | |
28 py: Python, | |
29 dmap: PyDict, | |
30 copymap: PyDict, | |
31 st: PyBytes, | |
32 ) -> PyResult<PyTuple> { | |
33 match parse_dirstate(st.data(py)) { | |
34 Ok((parents, dirstate_vec, copies)) => { | |
35 for (filename, entry) in dirstate_vec { | |
36 dmap.set_item( | |
37 py, | |
38 PyBytes::new(py, &filename[..]), | |
39 decapsule_make_dirstate_tuple(py)?( | |
40 entry.state as c_char, | |
41 entry.mode, | |
42 entry.size, | |
43 entry.mtime, | |
44 ), | |
45 )?; | |
46 } | |
47 for CopyVecEntry { path, copy_path } in copies { | |
48 copymap.set_item( | |
49 py, | |
50 PyBytes::new(py, path), | |
51 PyBytes::new(py, copy_path), | |
52 )?; | |
53 } | |
54 Ok((PyBytes::new(py, parents.p1), PyBytes::new(py, parents.p2)) | |
55 .to_py_object(py)) | |
56 } | |
57 Err(e) => Err(PyErr::new::<exc::ValueError, _>( | |
58 py, | |
59 match e { | |
60 DirstateParseError::TooLittleData => { | |
61 "too little data for parents".to_string() | |
62 } | |
63 DirstateParseError::Overflow => { | |
64 "overflow in dirstate".to_string() | |
65 } | |
66 DirstateParseError::CorruptedEntry(e) => e, | |
67 }, | |
68 )), | |
69 } | |
70 } | |
71 | |
72 fn pack_dirstate_wrapper( | |
73 py: Python, | |
74 dmap: PyDict, | |
75 copymap: PyDict, | |
76 pl: PyTuple, | |
77 now: PyInt, | |
78 ) -> PyResult<PyBytes> { | |
79 let p1 = pl.get_item(py, 0).extract::<PyBytes>(py)?; | |
80 let p1: &[u8] = p1.data(py); | |
81 let p2 = pl.get_item(py, 1).extract::<PyBytes>(py)?; | |
82 let p2: &[u8] = p2.data(py); | |
83 | |
84 let dirstate_vec = extract_dirstate_vec(py, &dmap)?; | |
85 | |
86 let copies: Result<HashMap<Vec<u8>, Vec<u8>>, PyErr> = copymap | |
87 .items(py) | |
88 .iter() | |
89 .map(|(key, value)| { | |
90 Ok(( | |
91 key.extract::<PyBytes>(py)?.data(py).to_owned(), | |
92 value.extract::<PyBytes>(py)?.data(py).to_owned(), | |
93 )) | |
94 }) | |
95 .collect(); | |
96 | |
97 match pack_dirstate( | |
98 &dirstate_vec, | |
99 &copies?, | |
100 DirstateParents { p1, p2 }, | |
101 now.as_object().extract::<i32>(py)?, | |
102 ) { | |
103 Ok((packed, new_dirstate_vec)) => { | |
104 for ( | |
105 filename, | |
106 DirstateEntry { | |
107 state, | |
108 mode, | |
109 size, | |
110 mtime, | |
111 }, | |
112 ) in new_dirstate_vec | |
113 { | |
114 dmap.set_item( | |
115 py, | |
116 PyBytes::new(py, &filename[..]), | |
117 decapsule_make_dirstate_tuple(py)?( | |
118 state as c_char, | |
119 mode, | |
120 size, | |
121 mtime, | |
122 ), | |
123 )?; | |
124 } | |
125 Ok(PyBytes::new(py, &packed)) | |
126 } | |
127 Err(error) => Err(PyErr::new::<exc::ValueError, _>( | |
128 py, | |
129 match error { | |
130 DirstatePackError::CorruptedParent => { | |
131 "expected a 20-byte hash".to_string() | |
132 } | |
133 DirstatePackError::CorruptedEntry(e) => e, | |
134 DirstatePackError::BadSize(expected, actual) => { | |
135 format!("bad dirstate size: {} != {}", actual, expected) | |
136 } | |
137 }, | |
138 )), | |
139 } | |
140 } | |
141 | |
142 /// Create the module, with `__package__` given from parent | |
143 pub fn init_parsers_module(py: Python, package: &str) -> PyResult<PyModule> { | |
144 let dotted_name = &format!("{}.parsers", package); | |
145 let m = PyModule::new(py, dotted_name)?; | |
146 | |
147 m.add(py, "__package__", package)?; | |
148 m.add(py, "__doc__", "Parsers - Rust implementation")?; | |
149 | |
150 m.add( | |
151 py, | |
152 "parse_dirstate", | |
153 py_fn!( | |
154 py, | |
155 parse_dirstate_wrapper(dmap: PyDict, copymap: PyDict, st: PyBytes) | |
156 ), | |
157 )?; | |
158 m.add( | |
159 py, | |
160 "pack_dirstate", | |
161 py_fn!( | |
162 py, | |
163 pack_dirstate_wrapper( | |
164 dmap: PyDict, | |
165 copymap: PyDict, | |
166 pl: PyTuple, | |
167 now: PyInt | |
168 ) | |
169 ), | |
170 )?; | |
171 | |
172 let sys = PyModule::import(py, "sys")?; | |
173 let sys_modules: PyDict = sys.get(py, "modules")?.extract(py)?; | |
174 sys_modules.set_item(py, dotted_name, &m)?; | |
175 | |
176 Ok(m) | |
177 } |