rust/hg-cpython/src/dirstate.rs
author Raphaël Gomès <rgomes@octobus.net>
Wed, 10 Jul 2019 09:56:53 +0200
changeset 42754 4e8f504424f3
parent 42749 7ceded4419a3
child 42957 7a01778bc7b7
permissions -rw-r--r--
rust-dirstate: rust-cpython bridge for dirstatemap This change also showcases the limitations of the `py_shared_ref!` macro. See the previous commit 'rust-dirstate: rust implementation of dirstatemap` for an explanation for the TODOs in the code. Differential Revision: https://phab.mercurial-scm.org/D6633
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
42303
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
     1
// dirstate.rs
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
     2
//
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
     3
// Copyright 2019 Raphaël Gomès <rgomes@octobus.net>
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
     4
//
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
     5
// This software may be used and distributed according to the terms of the
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
     6
// GNU General Public License version 2 or any later version.
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
     7
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
     8
//! Bindings for the `hg::dirstate` module provided by the
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
     9
//! `hg-core` package.
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    10
//!
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    11
//! From Python, this will be seen as `mercurial.rustext.dirstate`
42754
4e8f504424f3 rust-dirstate: rust-cpython bridge for dirstatemap
Raphaël Gomès <rgomes@octobus.net>
parents: 42749
diff changeset
    12
mod copymap;
42746
b3518b0baa47 rust-dirstate: create dirstate submodule in hg-cpython
Raphaël Gomès <rgomes@octobus.net>
parents: 42609
diff changeset
    13
mod dirs_multiset;
42754
4e8f504424f3 rust-dirstate: rust-cpython bridge for dirstatemap
Raphaël Gomès <rgomes@octobus.net>
parents: 42749
diff changeset
    14
mod dirstate_map;
4e8f504424f3 rust-dirstate: rust-cpython bridge for dirstatemap
Raphaël Gomès <rgomes@octobus.net>
parents: 42749
diff changeset
    15
use crate::dirstate::{dirs_multiset::Dirs, dirstate_map::DirstateMap};
42303
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    16
use cpython::{
42749
7ceded4419a3 rust-dirstate: use EntryState enum instead of literals
Raphaël Gomès <rgomes@octobus.net>
parents: 42748
diff changeset
    17
    exc, PyBytes, PyDict, PyErr, PyModule, PyObject, PyResult, PySequence,
7ceded4419a3 rust-dirstate: use EntryState enum instead of literals
Raphaël Gomès <rgomes@octobus.net>
parents: 42748
diff changeset
    18
    Python,
42303
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    19
};
42749
7ceded4419a3 rust-dirstate: use EntryState enum instead of literals
Raphaël Gomès <rgomes@octobus.net>
parents: 42748
diff changeset
    20
use hg::{DirstateEntry, DirstateParseError, EntryState, StateMap};
42609
326fdce22fb2 rust: switch hg-core and hg-cpython to rust 2018 edition
Raphaël Gomès <rgomes@octobus.net>
parents: 42558
diff changeset
    21
use libc::{c_char, c_int};
326fdce22fb2 rust: switch hg-core and hg-cpython to rust 2018 edition
Raphaël Gomès <rgomes@octobus.net>
parents: 42558
diff changeset
    22
#[cfg(feature = "python27")]
326fdce22fb2 rust: switch hg-core and hg-cpython to rust 2018 edition
Raphaël Gomès <rgomes@octobus.net>
parents: 42558
diff changeset
    23
use python27_sys::PyCapsule_Import;
326fdce22fb2 rust: switch hg-core and hg-cpython to rust 2018 edition
Raphaël Gomès <rgomes@octobus.net>
parents: 42558
diff changeset
    24
#[cfg(feature = "python3")]
326fdce22fb2 rust: switch hg-core and hg-cpython to rust 2018 edition
Raphaël Gomès <rgomes@octobus.net>
parents: 42558
diff changeset
    25
use python3_sys::PyCapsule_Import;
42749
7ceded4419a3 rust-dirstate: use EntryState enum instead of literals
Raphaël Gomès <rgomes@octobus.net>
parents: 42748
diff changeset
    26
use std::convert::TryFrom;
42303
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    27
use std::ffi::CStr;
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    28
use std::mem::transmute;
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    29
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    30
/// C code uses a custom `dirstate_tuple` type, checks in multiple instances
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    31
/// for this type, and raises a Python `Exception` if the check does not pass.
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    32
/// Because this type differs only in name from the regular Python tuple, it
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    33
/// would be a good idea in the near future to remove it entirely to allow
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    34
/// for a pure Python tuple of the same effective structure to be used,
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    35
/// rendering this type and the capsule below useless.
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    36
type MakeDirstateTupleFn = extern "C" fn(
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    37
    state: c_char,
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    38
    mode: c_int,
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    39
    size: c_int,
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    40
    mtime: c_int,
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    41
) -> PyObject;
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    42
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    43
/// This is largely a copy/paste from cindex.rs, pending the merge of a
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    44
/// `py_capsule_fn!` macro in the rust-cpython project:
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    45
/// https://github.com/dgrunwald/rust-cpython/pull/169
42747
760a7851e9ba rust-parsers: move parser bindings to their own file and Python module
Raphaël Gomès <rgomes@octobus.net>
parents: 42746
diff changeset
    46
pub fn decapsule_make_dirstate_tuple(
760a7851e9ba rust-parsers: move parser bindings to their own file and Python module
Raphaël Gomès <rgomes@octobus.net>
parents: 42746
diff changeset
    47
    py: Python,
760a7851e9ba rust-parsers: move parser bindings to their own file and Python module
Raphaël Gomès <rgomes@octobus.net>
parents: 42746
diff changeset
    48
) -> PyResult<MakeDirstateTupleFn> {
42303
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    49
    unsafe {
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    50
        let caps_name = CStr::from_bytes_with_nul_unchecked(
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    51
            b"mercurial.cext.parsers.make_dirstate_tuple_CAPI\0",
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    52
        );
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    53
        let from_caps = PyCapsule_Import(caps_name.as_ptr(), 0);
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    54
        if from_caps.is_null() {
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    55
            return Err(PyErr::fetch(py));
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    56
        }
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    57
        Ok(transmute(from_caps))
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    58
    }
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    59
}
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    60
42748
7cae6bc29ff9 rust-parsers: switch to parse/pack_dirstate to mutate-on-loop
Raphaël Gomès <rgomes@octobus.net>
parents: 42747
diff changeset
    61
pub fn extract_dirstate(py: Python, dmap: &PyDict) -> Result<StateMap, PyErr> {
42537
ce94f9622acd rust-dirstate: add "dirs" rust-cpython binding
Raphaël Gomès <rgomes@octobus.net>
parents: 42408
diff changeset
    62
    dmap.items(py)
42303
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    63
        .iter()
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    64
        .map(|(filename, stats)| {
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    65
            let stats = stats.extract::<PySequence>(py)?;
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    66
            let state = stats.get_item(py, 0)?.extract::<PyBytes>(py)?;
42749
7ceded4419a3 rust-dirstate: use EntryState enum instead of literals
Raphaël Gomès <rgomes@octobus.net>
parents: 42748
diff changeset
    67
            let state = EntryState::try_from(state.data(py)[0]).map_err(
7ceded4419a3 rust-dirstate: use EntryState enum instead of literals
Raphaël Gomès <rgomes@octobus.net>
parents: 42748
diff changeset
    68
                |e: DirstateParseError| {
7ceded4419a3 rust-dirstate: use EntryState enum instead of literals
Raphaël Gomès <rgomes@octobus.net>
parents: 42748
diff changeset
    69
                    PyErr::new::<exc::ValueError, _>(py, e.to_string())
7ceded4419a3 rust-dirstate: use EntryState enum instead of literals
Raphaël Gomès <rgomes@octobus.net>
parents: 42748
diff changeset
    70
                },
7ceded4419a3 rust-dirstate: use EntryState enum instead of literals
Raphaël Gomès <rgomes@octobus.net>
parents: 42748
diff changeset
    71
            )?;
42303
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    72
            let mode = stats.get_item(py, 1)?.extract(py)?;
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    73
            let size = stats.get_item(py, 2)?.extract(py)?;
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    74
            let mtime = stats.get_item(py, 3)?.extract(py)?;
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    75
            let filename = filename.extract::<PyBytes>(py)?;
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    76
            let filename = filename.data(py);
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    77
            Ok((
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    78
                filename.to_owned(),
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    79
                DirstateEntry {
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    80
                    state,
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    81
                    mode,
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    82
                    size,
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    83
                    mtime,
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    84
                },
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    85
            ))
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    86
        })
42537
ce94f9622acd rust-dirstate: add "dirs" rust-cpython binding
Raphaël Gomès <rgomes@octobus.net>
parents: 42408
diff changeset
    87
        .collect()
ce94f9622acd rust-dirstate: add "dirs" rust-cpython binding
Raphaël Gomès <rgomes@octobus.net>
parents: 42408
diff changeset
    88
}
ce94f9622acd rust-dirstate: add "dirs" rust-cpython binding
Raphaël Gomès <rgomes@octobus.net>
parents: 42408
diff changeset
    89
42303
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    90
/// Create the module, with `__package__` given from parent
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    91
pub fn init_module(py: Python, package: &str) -> PyResult<PyModule> {
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    92
    let dotted_name = &format!("{}.dirstate", package);
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    93
    let m = PyModule::new(py, dotted_name)?;
42537
ce94f9622acd rust-dirstate: add "dirs" rust-cpython binding
Raphaël Gomès <rgomes@octobus.net>
parents: 42408
diff changeset
    94
42303
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    95
    m.add(py, "__package__", package)?;
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    96
    m.add(py, "__doc__", "Dirstate - Rust implementation")?;
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    97
42537
ce94f9622acd rust-dirstate: add "dirs" rust-cpython binding
Raphaël Gomès <rgomes@octobus.net>
parents: 42408
diff changeset
    98
    m.add_class::<Dirs>(py)?;
42754
4e8f504424f3 rust-dirstate: rust-cpython bridge for dirstatemap
Raphaël Gomès <rgomes@octobus.net>
parents: 42749
diff changeset
    99
    m.add_class::<DirstateMap>(py)?;
42537
ce94f9622acd rust-dirstate: add "dirs" rust-cpython binding
Raphaël Gomès <rgomes@octobus.net>
parents: 42408
diff changeset
   100
42303
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   101
    let sys = PyModule::import(py, "sys")?;
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   102
    let sys_modules: PyDict = sys.get(py, "modules")?.extract(py)?;
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   103
    sys_modules.set_item(py, dotted_name, &m)?;
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   104
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   105
    Ok(m)
e240bec26626 rust-dirstate: add rust-cpython bindings to the new parse/pack functions
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   106
}