# HG changeset patch # User Raphaël Gomès # Date 1562080503 -7200 # Node ID 326fdce22fb222492dc0ba114f4244aa2b8b3aff # Parent 717686c5e461b03cd34d010f9143f04bc5262cc6 rust: switch hg-core and hg-cpython to rust 2018 edition Many interesting changes have happened in Rust since the Oxidation Plan was introduced, like the 2018 edition and procedural macros: - Opting in to the 2018 edition is a clear benefit in terms of future proofing, new (nice to have) syntactical sugar notwithstanding. It also has a new non-lexical, non-AST based borrow checker that has fewer bugs(!) and allows us to write correct code that in some cases would have been rejected by the old one. - Procedural macros allow us to use the PyO3 crate which maintainers have expressed the clear goal of compiling on stable, which would help in code maintainability compared to rust-cpython. In this patch are the following changes: - Removing most `extern crate` uses - Updating `use` clauses (`crate` keyword, nested `use`) - Removing `mod.rs` in favor of an aptly named module file Like discussed in the mailing list ( https://www.mercurial-scm.org/pipermail/mercurial-devel/2019-July/132316.html ), until Rust integration in Mercurial is considered to be out of the experimental phase, the maximum version of Rust allowed is whatever the latest version Debian packages. Differential Revision: https://phab.mercurial-scm.org/D6597 diff -r 717686c5e461 -r 326fdce22fb2 rust/hg-core/Cargo.toml --- a/rust/hg-core/Cargo.toml Fri Jul 12 11:08:31 2019 +0200 +++ b/rust/hg-core/Cargo.toml Tue Jul 02 17:15:03 2019 +0200 @@ -3,6 +3,7 @@ version = "0.1.0" authors = ["Georges Racinet "] description = "Mercurial pure Rust core library, with no assumption on Python bindings (FFI)" +edition = "2018" [lib] name = "hg" diff -r 717686c5e461 -r 326fdce22fb2 rust/hg-core/src/dirstate.rs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rust/hg-core/src/dirstate.rs Tue Jul 02 17:15:03 2019 +0200 @@ -0,0 +1,36 @@ +pub mod dirs_multiset; +pub mod parsers; + +#[derive(Debug, PartialEq, Copy, Clone)] +pub struct DirstateParents<'a> { + pub p1: &'a [u8], + pub p2: &'a [u8], +} + +/// The C implementation uses all signed types. This will be an issue +/// either when 4GB+ source files are commonplace or in 2038, whichever +/// comes first. +#[derive(Debug, PartialEq)] +pub struct DirstateEntry { + pub state: i8, + pub mode: i32, + pub mtime: i32, + pub size: i32, +} + +pub type DirstateVec = Vec<(Vec, DirstateEntry)>; + +#[derive(Debug, PartialEq)] +pub struct CopyVecEntry<'a> { + pub path: &'a [u8], + pub copy_path: &'a [u8], +} + +pub type CopyVec<'a> = Vec>; + +/// The Python implementation passes either a mapping (dirstate) or a flat +/// iterable (manifest) +pub enum DirsIterable { + Dirstate(DirstateVec), + Manifest(Vec>), +} diff -r 717686c5e461 -r 326fdce22fb2 rust/hg-core/src/dirstate/dirs_multiset.rs --- a/rust/hg-core/src/dirstate/dirs_multiset.rs Fri Jul 12 11:08:31 2019 +0200 +++ b/rust/hg-core/src/dirstate/dirs_multiset.rs Tue Jul 02 17:15:03 2019 +0200 @@ -8,10 +8,9 @@ //! A multiset of directory names. //! //! Used to counts the references to directories in a manifest or dirstate. +use crate::{utils::files, DirsIterable, DirstateEntry, DirstateMapError}; use std::collections::hash_map::{Entry, Iter}; use std::collections::HashMap; -use {DirsIterable, DirstateEntry, DirstateMapError}; -use utils::files; #[derive(PartialEq, Debug)] pub struct DirsMultiset { diff -r 717686c5e461 -r 326fdce22fb2 rust/hg-core/src/dirstate/mod.rs --- a/rust/hg-core/src/dirstate/mod.rs Fri Jul 12 11:08:31 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,36 +0,0 @@ -pub mod dirs_multiset; -pub mod parsers; - -#[derive(Debug, PartialEq, Copy, Clone)] -pub struct DirstateParents<'a> { - pub p1: &'a [u8], - pub p2: &'a [u8], -} - -/// The C implementation uses all signed types. This will be an issue -/// either when 4GB+ source files are commonplace or in 2038, whichever -/// comes first. -#[derive(Debug, PartialEq)] -pub struct DirstateEntry { - pub state: i8, - pub mode: i32, - pub mtime: i32, - pub size: i32, -} - -pub type DirstateVec = Vec<(Vec, DirstateEntry)>; - -#[derive(Debug, PartialEq)] -pub struct CopyVecEntry<'a> { - pub path: &'a [u8], - pub copy_path: &'a [u8], -} - -pub type CopyVec<'a> = Vec>; - -/// The Python implementation passes either a mapping (dirstate) or a flat -/// iterable (manifest) -pub enum DirsIterable { - Dirstate(DirstateVec), - Manifest(Vec>), -} diff -r 717686c5e461 -r 326fdce22fb2 rust/hg-core/src/dirstate/parsers.rs --- a/rust/hg-core/src/dirstate/parsers.rs Fri Jul 12 11:08:31 2019 +0200 +++ b/rust/hg-core/src/dirstate/parsers.rs Tue Jul 02 17:15:03 2019 +0200 @@ -3,13 +3,13 @@ // This software may be used and distributed according to the terms of the // GNU General Public License version 2 or any later version. +use crate::{ + CopyVec, CopyVecEntry, DirstateEntry, DirstatePackError, DirstateParents, + DirstateParseError, DirstateVec, +}; use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use std::collections::HashMap; use std::io::Cursor; -use { - CopyVec, CopyVecEntry, DirstateEntry, DirstatePackError, DirstateParents, - DirstateParseError, DirstateVec, -}; /// Parents are stored in the dirstate as byte hashes. const PARENT_SIZE: usize = 20; diff -r 717686c5e461 -r 326fdce22fb2 rust/hg-core/src/filepatterns.rs --- a/rust/hg-core/src/filepatterns.rs Fri Jul 12 11:08:31 2019 +0200 +++ b/rust/hg-core/src/filepatterns.rs Tue Jul 02 17:15:03 2019 +0200 @@ -1,11 +1,13 @@ -use crate::{LineNumber, PatternError, PatternFileError}; +use crate::{ + utils::{files::get_path_from_bytes, replace_slice, SliceExt}, + LineNumber, PatternError, PatternFileError, +}; +use lazy_static::lazy_static; use regex::bytes::Regex; use std::collections::HashMap; use std::fs::File; use std::io::Read; use std::vec::Vec; -use utils::files::get_path_from_bytes; -use utils::{replace_slice, SliceExt}; lazy_static! { static ref RE_ESCAPE: Vec> = { diff -r 717686c5e461 -r 326fdce22fb2 rust/hg-core/src/lib.rs --- a/rust/hg-core/src/lib.rs Fri Jul 12 11:08:31 2019 +0200 +++ b/rust/hg-core/src/lib.rs Tue Jul 02 17:15:03 2019 +0200 @@ -2,12 +2,6 @@ // // This software may be used and distributed according to the terms of the // GNU General Public License version 2 or any later version. -extern crate byteorder; -extern crate memchr; -#[macro_use] -extern crate lazy_static; -extern crate regex; - mod ancestors; pub mod dagops; pub use ancestors::{AncestorsIterator, LazyAncestors, MissingAncestors}; @@ -50,7 +44,7 @@ /// Return the two parents of the given `Revision`. /// /// Each of the parents can be independently `NULL_REVISION` - fn parents(&self, Revision) -> Result<[Revision; 2], GraphError>; + fn parents(&self, rev: Revision) -> Result<[Revision; 2], GraphError>; } pub type LineNumber = usize; diff -r 717686c5e461 -r 326fdce22fb2 rust/hg-core/src/utils.rs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rust/hg-core/src/utils.rs Tue Jul 02 17:15:03 2019 +0200 @@ -0,0 +1,45 @@ +pub mod files; + +pub fn replace_slice(buf: &mut [T], from: &[T], to: &[T]) +where + T: Clone + PartialEq, +{ + if buf.len() < from.len() || from.len() != to.len() { + return; + } + for i in 0..=buf.len() - from.len() { + if buf[i..].starts_with(from) { + buf[i..(i + from.len())].clone_from_slice(to); + } + } +} + +pub trait SliceExt { + fn trim(&self) -> &Self; + fn trim_end(&self) -> &Self; +} + +fn is_not_whitespace(c: &u8) -> bool { + !(*c as char).is_whitespace() +} + +impl SliceExt for [u8] { + fn trim(&self) -> &[u8] { + if let Some(first) = self.iter().position(is_not_whitespace) { + if let Some(last) = self.iter().rposition(is_not_whitespace) { + &self[first..last + 1] + } else { + unreachable!(); + } + } else { + &[] + } + } + fn trim_end(&self) -> &[u8] { + if let Some(last) = self.iter().rposition(is_not_whitespace) { + &self[..last + 1] + } else { + &[] + } + } +} diff -r 717686c5e461 -r 326fdce22fb2 rust/hg-core/src/utils/mod.rs --- a/rust/hg-core/src/utils/mod.rs Fri Jul 12 11:08:31 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ -pub mod files; - -pub fn replace_slice(buf: &mut [T], from: &[T], to: &[T]) -where - T: Clone + PartialEq, -{ - if buf.len() < from.len() || from.len() != to.len() { - return; - } - for i in 0..=buf.len() - from.len() { - if buf[i..].starts_with(from) { - buf[i..(i + from.len())].clone_from_slice(to); - } - } -} - -pub trait SliceExt { - fn trim(&self) -> &Self; - fn trim_end(&self) -> &Self; -} - -fn is_not_whitespace(c: &u8) -> bool { - !(*c as char).is_whitespace() -} - -impl SliceExt for [u8] { - fn trim(&self) -> &[u8] { - if let Some(first) = self.iter().position(is_not_whitespace) { - if let Some(last) = self.iter().rposition(is_not_whitespace) { - &self[first..last + 1] - } else { - unreachable!(); - } - } else { - &[] - } - } - fn trim_end(&self) -> &[u8] { - if let Some(last) = self.iter().rposition(is_not_whitespace) { - &self[..last + 1] - } else { - &[] - } - } -} diff -r 717686c5e461 -r 326fdce22fb2 rust/hg-core/tests/test_missing_ancestors.rs --- a/rust/hg-core/tests/test_missing_ancestors.rs Fri Jul 12 11:08:31 2019 +0200 +++ b/rust/hg-core/tests/test_missing_ancestors.rs Tue Jul 02 17:15:03 2019 +0200 @@ -1,7 +1,3 @@ -extern crate hg; -extern crate rand; -extern crate rand_pcg; - use hg::testing::VecGraph; use hg::Revision; use hg::*; diff -r 717686c5e461 -r 326fdce22fb2 rust/hg-cpython/Cargo.toml --- a/rust/hg-cpython/Cargo.toml Fri Jul 12 11:08:31 2019 +0200 +++ b/rust/hg-cpython/Cargo.toml Tue Jul 02 17:15:03 2019 +0200 @@ -2,6 +2,7 @@ name = "hg-cpython" version = "0.1.0" authors = ["Georges Racinet "] +edition = "2018" [lib] name='rusthg' diff -r 717686c5e461 -r 326fdce22fb2 rust/hg-cpython/src/ancestors.rs --- a/rust/hg-cpython/src/ancestors.rs Fri Jul 12 11:08:31 2019 +0200 +++ b/rust/hg-cpython/src/ancestors.rs Tue Jul 02 17:15:03 2019 +0200 @@ -34,13 +34,15 @@ //! [`LazyAncestors`]: struct.LazyAncestors.html //! [`MissingAncestors`]: struct.MissingAncestors.html //! [`AncestorsIterator`]: struct.AncestorsIterator.html -use crate::conversion::{py_set, rev_pyiter_collect}; -use cindex::Index; +use crate::{ + cindex::Index, + conversion::{py_set, rev_pyiter_collect}, + exceptions::GraphError, +}; use cpython::{ ObjectProtocol, PyClone, PyDict, PyList, PyModule, PyObject, PyResult, Python, PythonObject, ToPyObject, }; -use exceptions::GraphError; use hg::Revision; use hg::{ AncestorsIterator as CoreIterator, LazyAncestors as CoreLazy, diff -r 717686c5e461 -r 326fdce22fb2 rust/hg-cpython/src/cindex.rs --- a/rust/hg-cpython/src/cindex.rs Fri Jul 12 11:08:31 2019 +0200 +++ b/rust/hg-cpython/src/cindex.rs Tue Jul 02 17:15:03 2019 +0200 @@ -10,14 +10,14 @@ //! Ideally, we should use an Index entirely implemented in Rust, //! but this will take some time to get there. #[cfg(feature = "python27")] -extern crate python27_sys as python_sys; +use python27_sys as python_sys; #[cfg(feature = "python3")] -extern crate python3_sys as python_sys; +use python3_sys as python_sys; -use self::python_sys::PyCapsule_Import; use cpython::{PyClone, PyErr, PyObject, PyResult, Python}; use hg::{Graph, GraphError, Revision, WORKING_DIRECTORY_REVISION}; use libc::c_int; +use python_sys::PyCapsule_Import; use std::ffi::CStr; use std::mem::transmute; diff -r 717686c5e461 -r 326fdce22fb2 rust/hg-cpython/src/dagops.rs --- a/rust/hg-cpython/src/dagops.rs Fri Jul 12 11:08:31 2019 +0200 +++ b/rust/hg-cpython/src/dagops.rs Tue Jul 02 17:15:03 2019 +0200 @@ -9,10 +9,12 @@ //! `hg-core` package. //! //! From Python, this will be seen as `mercurial.rustext.dagop` -use crate::conversion::{py_set, rev_pyiter_collect}; -use cindex::Index; +use crate::{ + cindex::Index, + conversion::{py_set, rev_pyiter_collect}, + exceptions::GraphError, +}; use cpython::{PyDict, PyModule, PyObject, PyResult, Python}; -use exceptions::GraphError; use hg::dagops; use hg::Revision; use std::collections::HashSet; diff -r 717686c5e461 -r 326fdce22fb2 rust/hg-cpython/src/dirstate.rs --- a/rust/hg-cpython/src/dirstate.rs Fri Jul 12 11:08:31 2019 +0200 +++ b/rust/hg-cpython/src/dirstate.rs Tue Jul 02 17:15:03 2019 +0200 @@ -19,17 +19,14 @@ DirstateEntry, DirstateMapError, DirstatePackError, DirstateParents, DirstateParseError, DirstateVec, }; +use libc::{c_char, c_int}; +#[cfg(feature = "python27")] +use python27_sys::PyCapsule_Import; +#[cfg(feature = "python3")] +use python3_sys::PyCapsule_Import; +use std::cell::RefCell; use std::collections::HashMap; use std::ffi::CStr; - -#[cfg(feature = "python27")] -extern crate python27_sys as python_sys; -#[cfg(feature = "python3")] -extern crate python3_sys as python_sys; - -use self::python_sys::PyCapsule_Import; -use libc::{c_char, c_int}; -use std::cell::RefCell; use std::mem::transmute; /// C code uses a custom `dirstate_tuple` type, checks in multiple instances diff -r 717686c5e461 -r 326fdce22fb2 rust/hg-cpython/src/discovery.rs --- a/rust/hg-cpython/src/discovery.rs Fri Jul 12 11:08:31 2019 +0200 +++ b/rust/hg-cpython/src/discovery.rs Tue Jul 02 17:15:03 2019 +0200 @@ -12,13 +12,15 @@ //! - [`PartialDiscover`] is the Rust implementation of //! `mercurial.setdiscovery.partialdiscovery`. -use crate::conversion::{py_set, rev_pyiter_collect}; -use cindex::Index; +use crate::{ + cindex::Index, + conversion::{py_set, rev_pyiter_collect}, + exceptions::GraphError, +}; use cpython::{ ObjectProtocol, PyDict, PyModule, PyObject, PyResult, Python, PythonObject, ToPyObject, }; -use exceptions::GraphError; use hg::discovery::PartialDiscovery as CorePartialDiscovery; use hg::Revision; diff -r 717686c5e461 -r 326fdce22fb2 rust/hg-cpython/src/exceptions.rs --- a/rust/hg-cpython/src/exceptions.rs Fri Jul 12 11:08:31 2019 +0200 +++ b/rust/hg-cpython/src/exceptions.rs Tue Jul 02 17:15:03 2019 +0200 @@ -12,8 +12,10 @@ //! existing Python exceptions if appropriate. //! //! [`GraphError`]: struct.GraphError.html -use cpython::exc::{RuntimeError, ValueError}; -use cpython::{exc, PyErr, Python}; +use cpython::{ + exc::{IOError, RuntimeError, ValueError}, + py_exception, PyErr, Python, +}; use hg; py_exception!(rustext, GraphError, ValueError); @@ -55,7 +57,7 @@ match inner { hg::PatternFileError::IO(e) => { let value = (e.raw_os_error().unwrap_or(2), e.to_string()); - PyErr::new::(py, value) + PyErr::new::(py, value) } hg::PatternFileError::Pattern(e, l) => match e { hg::PatternError::UnsupportedSyntax(m) => { diff -r 717686c5e461 -r 326fdce22fb2 rust/hg-cpython/src/filepatterns.rs --- a/rust/hg-cpython/src/filepatterns.rs Fri Jul 12 11:08:31 2019 +0200 +++ b/rust/hg-cpython/src/filepatterns.rs Tue Jul 02 17:15:03 2019 +0200 @@ -10,10 +10,10 @@ //! `hg-core` crate. From Python, this will be seen as `rustext.filepatterns` //! and can be used as replacement for the the pure `filepatterns` Python module. //! +use crate::exceptions::{PatternError, PatternFileError}; use cpython::{ PyBytes, PyDict, PyModule, PyObject, PyResult, PyTuple, Python, ToPyObject, }; -use exceptions::{PatternError, PatternFileError}; use hg::{build_single_regex, read_pattern_file, LineNumber, PatternTuple}; /// Rust does not like functions with different return signatures. diff -r 717686c5e461 -r 326fdce22fb2 rust/hg-cpython/src/lib.rs --- a/rust/hg-cpython/src/lib.rs Fri Jul 12 11:08:31 2019 +0200 +++ b/rust/hg-cpython/src/lib.rs Tue Jul 02 17:15:03 2019 +0200 @@ -19,10 +19,10 @@ //! 'Generic DAG ancestor algorithms - Rust implementation' //! ``` +/// This crate uses nested private macros, `extern crate` is still needed in +/// 2018 edition. #[macro_use] extern crate cpython; -extern crate hg; -extern crate libc; pub mod ancestors; mod cindex;