##// END OF EJS Templates
revlog: split `rawtext` retrieval out of _revisiondata...
revlog: split `rawtext` retrieval out of _revisiondata This part is reasonably independent. Having it on its own clarify the code flow and will help code that inherit from revlog to overwrite specific area only.

File last commit:

r42994:7ceded44 default
r43060:e91411fc default
Show More
parsers.rs
207 lines | 6.2 KiB | application/rls-services+xml | RustLexer
Raphaël Gomès
rust-parsers: move parser bindings to their own file and Python module...
r42992 // parsers.rs
//
// Copyright 2019 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::dirstate::parsers` module provided by the
//! `hg-core` package.
//!
//! From Python, this will be seen as `mercurial.rustext.parsers`
//!
use cpython::{
exc, PyBytes, PyDict, PyErr, PyInt, PyModule, PyResult, PyTuple, Python,
Raphaël Gomès
rust-parsers: switch to parse/pack_dirstate to mutate-on-loop...
r42993 ToPyObject,
Raphaël Gomès
rust-parsers: move parser bindings to their own file and Python module...
r42992 };
use hg::{
Raphaël Gomès
rust-parsers: switch to parse/pack_dirstate to mutate-on-loop...
r42993 pack_dirstate, parse_dirstate, utils::copy_into_array, DirstateEntry,
DirstatePackError, DirstateParents, DirstateParseError, PARENT_SIZE,
Raphaël Gomès
rust-parsers: move parser bindings to their own file and Python module...
r42992 };
use std::collections::HashMap;
use libc::c_char;
Raphaël Gomès
rust-parsers: switch to parse/pack_dirstate to mutate-on-loop...
r42993 use crate::dirstate::{decapsule_make_dirstate_tuple, extract_dirstate};
use std::time::Duration;
Raphaël Gomès
rust-parsers: move parser bindings to their own file and Python module...
r42992
fn parse_dirstate_wrapper(
py: Python,
dmap: PyDict,
copymap: PyDict,
st: PyBytes,
) -> PyResult<PyTuple> {
Raphaël Gomès
rust-parsers: switch to parse/pack_dirstate to mutate-on-loop...
r42993 let mut dirstate_map = HashMap::new();
let mut copies = HashMap::new();
match parse_dirstate(&mut dirstate_map, &mut copies, st.data(py)) {
Ok(parents) => {
for (filename, entry) in dirstate_map {
Raphaël Gomès
rust-dirstate: use EntryState enum instead of literals...
r42994 // Explicitly go through u8 first, then cast to
// platform-specific `c_char` because Into<u8> has a specific
// implementation while `as c_char` would just do a naive enum
// cast.
let state: u8 = entry.state.into();
Raphaël Gomès
rust-parsers: move parser bindings to their own file and Python module...
r42992 dmap.set_item(
py,
Raphaël Gomès
rust-parsers: switch to parse/pack_dirstate to mutate-on-loop...
r42993 PyBytes::new(py, &filename),
Raphaël Gomès
rust-parsers: move parser bindings to their own file and Python module...
r42992 decapsule_make_dirstate_tuple(py)?(
Raphaël Gomès
rust-dirstate: use EntryState enum instead of literals...
r42994 state as c_char,
Raphaël Gomès
rust-parsers: move parser bindings to their own file and Python module...
r42992 entry.mode,
entry.size,
entry.mtime,
),
)?;
}
Raphaël Gomès
rust-parsers: switch to parse/pack_dirstate to mutate-on-loop...
r42993 for (path, copy_path) in copies {
Raphaël Gomès
rust-parsers: move parser bindings to their own file and Python module...
r42992 copymap.set_item(
py,
Raphaël Gomès
rust-parsers: switch to parse/pack_dirstate to mutate-on-loop...
r42993 PyBytes::new(py, &path),
PyBytes::new(py, &copy_path),
Raphaël Gomès
rust-parsers: move parser bindings to their own file and Python module...
r42992 )?;
}
Raphaël Gomès
rust-parsers: switch to parse/pack_dirstate to mutate-on-loop...
r42993 Ok(
(PyBytes::new(py, &parents.p1), PyBytes::new(py, &parents.p2))
.to_py_object(py),
)
Raphaël Gomès
rust-parsers: move parser bindings to their own file and Python module...
r42992 }
Err(e) => Err(PyErr::new::<exc::ValueError, _>(
py,
match e {
DirstateParseError::TooLittleData => {
"too little data for parents".to_string()
}
DirstateParseError::Overflow => {
"overflow in dirstate".to_string()
}
DirstateParseError::CorruptedEntry(e) => e,
Raphaël Gomès
rust-parsers: switch to parse/pack_dirstate to mutate-on-loop...
r42993 DirstateParseError::Damaged => {
"dirstate appears to be damaged".to_string()
}
Raphaël Gomès
rust-parsers: move parser bindings to their own file and Python module...
r42992 },
)),
}
}
fn pack_dirstate_wrapper(
py: Python,
dmap: PyDict,
copymap: PyDict,
pl: PyTuple,
now: PyInt,
) -> PyResult<PyBytes> {
let p1 = pl.get_item(py, 0).extract::<PyBytes>(py)?;
let p1: &[u8] = p1.data(py);
let p2 = pl.get_item(py, 1).extract::<PyBytes>(py)?;
let p2: &[u8] = p2.data(py);
Raphaël Gomès
rust-parsers: switch to parse/pack_dirstate to mutate-on-loop...
r42993 let mut dirstate_map = extract_dirstate(py, &dmap)?;
Raphaël Gomès
rust-parsers: move parser bindings to their own file and Python module...
r42992
let copies: Result<HashMap<Vec<u8>, Vec<u8>>, PyErr> = copymap
.items(py)
.iter()
.map(|(key, value)| {
Ok((
key.extract::<PyBytes>(py)?.data(py).to_owned(),
value.extract::<PyBytes>(py)?.data(py).to_owned(),
))
})
.collect();
Raphaël Gomès
rust-parsers: switch to parse/pack_dirstate to mutate-on-loop...
r42993 if p1.len() != PARENT_SIZE || p2.len() != PARENT_SIZE {
return Err(PyErr::new::<exc::ValueError, _>(
py,
"expected a 20-byte hash".to_string(),
));
}
Raphaël Gomès
rust-parsers: move parser bindings to their own file and Python module...
r42992 match pack_dirstate(
Raphaël Gomès
rust-parsers: switch to parse/pack_dirstate to mutate-on-loop...
r42993 &mut dirstate_map,
Raphaël Gomès
rust-parsers: move parser bindings to their own file and Python module...
r42992 &copies?,
Raphaël Gomès
rust-parsers: switch to parse/pack_dirstate to mutate-on-loop...
r42993 DirstateParents {
p1: copy_into_array(&p1),
p2: copy_into_array(&p2),
},
Duration::from_secs(now.value(py) as u64),
Raphaël Gomès
rust-parsers: move parser bindings to their own file and Python module...
r42992 ) {
Raphaël Gomès
rust-parsers: switch to parse/pack_dirstate to mutate-on-loop...
r42993 Ok(packed) => {
Raphaël Gomès
rust-parsers: move parser bindings to their own file and Python module...
r42992 for (
filename,
DirstateEntry {
state,
mode,
size,
mtime,
},
Raphaël Gomès
rust-parsers: switch to parse/pack_dirstate to mutate-on-loop...
r42993 ) in dirstate_map
Raphaël Gomès
rust-parsers: move parser bindings to their own file and Python module...
r42992 {
Raphaël Gomès
rust-dirstate: use EntryState enum instead of literals...
r42994 // Explicitly go through u8 first, then cast to
// platform-specific `c_char` because Into<u8> has a specific
// implementation while `as c_char` would just do a naive enum
// cast.
let state: u8 = state.into();
Raphaël Gomès
rust-parsers: move parser bindings to their own file and Python module...
r42992 dmap.set_item(
py,
PyBytes::new(py, &filename[..]),
decapsule_make_dirstate_tuple(py)?(
state as c_char,
mode,
size,
mtime,
),
)?;
}
Ok(PyBytes::new(py, &packed))
}
Err(error) => Err(PyErr::new::<exc::ValueError, _>(
py,
match error {
DirstatePackError::CorruptedParent => {
"expected a 20-byte hash".to_string()
}
DirstatePackError::CorruptedEntry(e) => e,
DirstatePackError::BadSize(expected, actual) => {
format!("bad dirstate size: {} != {}", actual, expected)
}
},
)),
}
}
/// Create the module, with `__package__` given from parent
pub fn init_parsers_module(py: Python, package: &str) -> PyResult<PyModule> {
let dotted_name = &format!("{}.parsers", package);
let m = PyModule::new(py, dotted_name)?;
m.add(py, "__package__", package)?;
m.add(py, "__doc__", "Parsers - Rust implementation")?;
m.add(
py,
"parse_dirstate",
py_fn!(
py,
parse_dirstate_wrapper(dmap: PyDict, copymap: PyDict, st: PyBytes)
),
)?;
m.add(
py,
"pack_dirstate",
py_fn!(
py,
pack_dirstate_wrapper(
dmap: PyDict,
copymap: PyDict,
pl: PyTuple,
now: PyInt
)
),
)?;
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)
}