rust/hg-core/src/utils.rs
author Raphaël Gomès <rgomes@octobus.net>
Fri, 18 Feb 2022 14:27:43 +0100
branchstable
changeset 48796 c00d3ce4e94b
parent 48417 5734b03ecf3e
child 49631 29cf3167e459
child 50214 8e0d823ef182
permissions -rw-r--r--
branching: merge default into stable for 6.1 freeze
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
42751
4b3b27d567d5 rust-docstrings: add missing module docstrings
Raphaël Gomès <rgomes@octobus.net>
parents: 42748
diff changeset
     1
// utils module
4b3b27d567d5 rust-docstrings: add missing module docstrings
Raphaël Gomès <rgomes@octobus.net>
parents: 42748
diff changeset
     2
//
4b3b27d567d5 rust-docstrings: add missing module docstrings
Raphaël Gomès <rgomes@octobus.net>
parents: 42748
diff changeset
     3
// Copyright 2019 Raphaël Gomès <rgomes@octobus.net>
4b3b27d567d5 rust-docstrings: add missing module docstrings
Raphaël Gomès <rgomes@octobus.net>
parents: 42748
diff changeset
     4
//
4b3b27d567d5 rust-docstrings: add missing module docstrings
Raphaël Gomès <rgomes@octobus.net>
parents: 42748
diff changeset
     5
// This software may be used and distributed according to the terms of the
4b3b27d567d5 rust-docstrings: add missing module docstrings
Raphaël Gomès <rgomes@octobus.net>
parents: 42748
diff changeset
     6
// GNU General Public License version 2 or any later version.
4b3b27d567d5 rust-docstrings: add missing module docstrings
Raphaël Gomès <rgomes@octobus.net>
parents: 42748
diff changeset
     7
4b3b27d567d5 rust-docstrings: add missing module docstrings
Raphaël Gomès <rgomes@octobus.net>
parents: 42748
diff changeset
     8
//! Contains useful functions, traits, structs, etc. for use in core.
4b3b27d567d5 rust-docstrings: add missing module docstrings
Raphaël Gomès <rgomes@octobus.net>
parents: 42748
diff changeset
     9
46445
ca3f73cc3cf4 rhg: Simplify CommandError based on its use
Simon Sapin <simon.sapin@octobus.net>
parents: 46090
diff changeset
    10
use crate::errors::{HgError, IoErrorContext};
44268
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44265
diff changeset
    11
use crate::utils::hg_path::HgPath;
46586
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
    12
use im_rc::ordmap::DiffItem;
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
    13
use im_rc::ordmap::OrdMap;
46614
a069639783a0 rhg: Check .hg/requires for absence of required features
Simon Sapin <simon.sapin@octobus.net>
parents: 46601
diff changeset
    14
use std::cell::Cell;
a069639783a0 rhg: Check .hg/requires for absence of required features
Simon Sapin <simon.sapin@octobus.net>
parents: 46601
diff changeset
    15
use std::fmt;
44268
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44265
diff changeset
    16
use std::{io::Write, ops::Deref};
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44265
diff changeset
    17
42437
9609430d3625 rust-filepatterns: use bytes instead of String
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    18
pub mod files;
42956
3fe40dd6355d rust-hgpath: add HgPath and HgPathBuf structs to encapsulate handling of paths
Raphaël Gomès <rgomes@octobus.net>
parents: 42863
diff changeset
    19
pub mod hg_path;
44265
c18dd48cea4a rust-pathauditor: add Rust implementation of the `pathauditor`
Raphaël Gomès <rgomes@octobus.net>
parents: 44079
diff changeset
    20
pub mod path_auditor;
42437
9609430d3625 rust-filepatterns: use bytes instead of String
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    21
44079
191a461d6be6 rust-utils: add util to find a slice in another slice
Raphaël Gomès <rgomes@octobus.net>
parents: 42956
diff changeset
    22
/// Useful until rust/issues/56345 is stable
191a461d6be6 rust-utils: add util to find a slice in another slice
Raphaël Gomès <rgomes@octobus.net>
parents: 42956
diff changeset
    23
///
191a461d6be6 rust-utils: add util to find a slice in another slice
Raphaël Gomès <rgomes@octobus.net>
parents: 42956
diff changeset
    24
/// # Examples
191a461d6be6 rust-utils: add util to find a slice in another slice
Raphaël Gomès <rgomes@octobus.net>
parents: 42956
diff changeset
    25
///
191a461d6be6 rust-utils: add util to find a slice in another slice
Raphaël Gomès <rgomes@octobus.net>
parents: 42956
diff changeset
    26
/// ```
191a461d6be6 rust-utils: add util to find a slice in another slice
Raphaël Gomès <rgomes@octobus.net>
parents: 42956
diff changeset
    27
/// use crate::hg::utils::find_slice_in_slice;
191a461d6be6 rust-utils: add util to find a slice in another slice
Raphaël Gomès <rgomes@octobus.net>
parents: 42956
diff changeset
    28
///
191a461d6be6 rust-utils: add util to find a slice in another slice
Raphaël Gomès <rgomes@octobus.net>
parents: 42956
diff changeset
    29
/// let haystack = b"This is the haystack".to_vec();
191a461d6be6 rust-utils: add util to find a slice in another slice
Raphaël Gomès <rgomes@octobus.net>
parents: 42956
diff changeset
    30
/// assert_eq!(find_slice_in_slice(&haystack, b"the"), Some(8));
191a461d6be6 rust-utils: add util to find a slice in another slice
Raphaël Gomès <rgomes@octobus.net>
parents: 42956
diff changeset
    31
/// assert_eq!(find_slice_in_slice(&haystack, b"not here"), None);
191a461d6be6 rust-utils: add util to find a slice in another slice
Raphaël Gomès <rgomes@octobus.net>
parents: 42956
diff changeset
    32
/// ```
191a461d6be6 rust-utils: add util to find a slice in another slice
Raphaël Gomès <rgomes@octobus.net>
parents: 42956
diff changeset
    33
pub fn find_slice_in_slice<T>(slice: &[T], needle: &[T]) -> Option<usize>
191a461d6be6 rust-utils: add util to find a slice in another slice
Raphaël Gomès <rgomes@octobus.net>
parents: 42956
diff changeset
    34
where
191a461d6be6 rust-utils: add util to find a slice in another slice
Raphaël Gomès <rgomes@octobus.net>
parents: 42956
diff changeset
    35
    for<'a> &'a [T]: PartialEq,
191a461d6be6 rust-utils: add util to find a slice in another slice
Raphaël Gomès <rgomes@octobus.net>
parents: 42956
diff changeset
    36
{
191a461d6be6 rust-utils: add util to find a slice in another slice
Raphaël Gomès <rgomes@octobus.net>
parents: 42956
diff changeset
    37
    slice
191a461d6be6 rust-utils: add util to find a slice in another slice
Raphaël Gomès <rgomes@octobus.net>
parents: 42956
diff changeset
    38
        .windows(needle.len())
191a461d6be6 rust-utils: add util to find a slice in another slice
Raphaël Gomès <rgomes@octobus.net>
parents: 42956
diff changeset
    39
        .position(|window| window == needle)
191a461d6be6 rust-utils: add util to find a slice in another slice
Raphaël Gomès <rgomes@octobus.net>
parents: 42956
diff changeset
    40
}
191a461d6be6 rust-utils: add util to find a slice in another slice
Raphaël Gomès <rgomes@octobus.net>
parents: 42956
diff changeset
    41
42610
5672bb73f61e rust-utils: add docstrings and doctests for utils.rs
Raphaël Gomès <rgomes@octobus.net>
parents: 42609
diff changeset
    42
/// Replaces the `from` slice with the `to` slice inside the `buf` slice.
5672bb73f61e rust-utils: add docstrings and doctests for utils.rs
Raphaël Gomès <rgomes@octobus.net>
parents: 42609
diff changeset
    43
///
5672bb73f61e rust-utils: add docstrings and doctests for utils.rs
Raphaël Gomès <rgomes@octobus.net>
parents: 42609
diff changeset
    44
/// # Examples
5672bb73f61e rust-utils: add docstrings and doctests for utils.rs
Raphaël Gomès <rgomes@octobus.net>
parents: 42609
diff changeset
    45
///
5672bb73f61e rust-utils: add docstrings and doctests for utils.rs
Raphaël Gomès <rgomes@octobus.net>
parents: 42609
diff changeset
    46
/// ```
5672bb73f61e rust-utils: add docstrings and doctests for utils.rs
Raphaël Gomès <rgomes@octobus.net>
parents: 42609
diff changeset
    47
/// use crate::hg::utils::replace_slice;
5672bb73f61e rust-utils: add docstrings and doctests for utils.rs
Raphaël Gomès <rgomes@octobus.net>
parents: 42609
diff changeset
    48
/// let mut line = b"I hate writing tests!".to_vec();
5672bb73f61e rust-utils: add docstrings and doctests for utils.rs
Raphaël Gomès <rgomes@octobus.net>
parents: 42609
diff changeset
    49
/// replace_slice(&mut line, b"hate", b"love");
5672bb73f61e rust-utils: add docstrings and doctests for utils.rs
Raphaël Gomès <rgomes@octobus.net>
parents: 42609
diff changeset
    50
/// assert_eq!(
5672bb73f61e rust-utils: add docstrings and doctests for utils.rs
Raphaël Gomès <rgomes@octobus.net>
parents: 42609
diff changeset
    51
///     line,
5672bb73f61e rust-utils: add docstrings and doctests for utils.rs
Raphaël Gomès <rgomes@octobus.net>
parents: 42609
diff changeset
    52
///     b"I love writing tests!".to_vec()
42841
ce6797ef6eab rust: apply more formatting fixes
Yuya Nishihara <yuya@tcha.org>
parents: 42799
diff changeset
    53
/// );
42610
5672bb73f61e rust-utils: add docstrings and doctests for utils.rs
Raphaël Gomès <rgomes@octobus.net>
parents: 42609
diff changeset
    54
/// ```
42437
9609430d3625 rust-filepatterns: use bytes instead of String
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    55
pub fn replace_slice<T>(buf: &mut [T], from: &[T], to: &[T])
9609430d3625 rust-filepatterns: use bytes instead of String
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    56
where
9609430d3625 rust-filepatterns: use bytes instead of String
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    57
    T: Clone + PartialEq,
9609430d3625 rust-filepatterns: use bytes instead of String
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    58
{
42611
2f760da140ee rust-utils: remove buggy assertion
Raphaël Gomès <rgomes@octobus.net>
parents: 42610
diff changeset
    59
    if buf.len() < from.len() || from.len() != to.len() {
42437
9609430d3625 rust-filepatterns: use bytes instead of String
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    60
        return;
9609430d3625 rust-filepatterns: use bytes instead of String
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    61
    }
9609430d3625 rust-filepatterns: use bytes instead of String
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    62
    for i in 0..=buf.len() - from.len() {
9609430d3625 rust-filepatterns: use bytes instead of String
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    63
        if buf[i..].starts_with(from) {
9609430d3625 rust-filepatterns: use bytes instead of String
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    64
            buf[i..(i + from.len())].clone_from_slice(to);
9609430d3625 rust-filepatterns: use bytes instead of String
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    65
        }
9609430d3625 rust-filepatterns: use bytes instead of String
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    66
    }
9609430d3625 rust-filepatterns: use bytes instead of String
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    67
}
9609430d3625 rust-filepatterns: use bytes instead of String
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    68
9609430d3625 rust-filepatterns: use bytes instead of String
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    69
pub trait SliceExt {
42610
5672bb73f61e rust-utils: add docstrings and doctests for utils.rs
Raphaël Gomès <rgomes@octobus.net>
parents: 42609
diff changeset
    70
    fn trim_end(&self) -> &Self;
5672bb73f61e rust-utils: add docstrings and doctests for utils.rs
Raphaël Gomès <rgomes@octobus.net>
parents: 42609
diff changeset
    71
    fn trim_start(&self) -> &Self;
47949
696abab107b4 rust: Generalize the `trim_end_newlines` utility of byte strings
Simon Sapin <simon.sapin@octobus.net>
parents: 46742
diff changeset
    72
    fn trim_end_matches(&self, f: impl FnMut(u8) -> bool) -> &Self;
696abab107b4 rust: Generalize the `trim_end_newlines` utility of byte strings
Simon Sapin <simon.sapin@octobus.net>
parents: 46742
diff changeset
    73
    fn trim_start_matches(&self, f: impl FnMut(u8) -> bool) -> &Self;
42437
9609430d3625 rust-filepatterns: use bytes instead of String
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    74
    fn trim(&self) -> &Self;
42863
62eabdf91f85 rustfilepatterns: refactor the pattern of removing a prefix from a &[u8]
Valentin Gatien-Baron <valentin.gatienbaron@gmail.com>
parents: 42841
diff changeset
    75
    fn drop_prefix(&self, needle: &Self) -> Option<&Self>;
46505
a25033eb43b5 rhg: add limited support for the `config` sub-command
Simon Sapin <simon.sapin@octobus.net>
parents: 46483
diff changeset
    76
    fn split_2(&self, separator: u8) -> Option<(&[u8], &[u8])>;
47961
4d2a5ca060e3 rust: Add a Filelog struct that wraps Revlog
Simon Sapin <simon.sapin@octobus.net>
parents: 47949
diff changeset
    77
    fn split_2_by_slice(&self, separator: &[u8]) -> Option<(&[u8], &[u8])>;
42437
9609430d3625 rust-filepatterns: use bytes instead of String
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    78
}
9609430d3625 rust-filepatterns: use bytes instead of String
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    79
47949
696abab107b4 rust: Generalize the `trim_end_newlines` utility of byte strings
Simon Sapin <simon.sapin@octobus.net>
parents: 46742
diff changeset
    80
impl SliceExt for [u8] {
696abab107b4 rust: Generalize the `trim_end_newlines` utility of byte strings
Simon Sapin <simon.sapin@octobus.net>
parents: 46742
diff changeset
    81
    fn trim_end(&self) -> &[u8] {
696abab107b4 rust: Generalize the `trim_end_newlines` utility of byte strings
Simon Sapin <simon.sapin@octobus.net>
parents: 46742
diff changeset
    82
        self.trim_end_matches(|byte| byte.is_ascii_whitespace())
696abab107b4 rust: Generalize the `trim_end_newlines` utility of byte strings
Simon Sapin <simon.sapin@octobus.net>
parents: 46742
diff changeset
    83
    }
42437
9609430d3625 rust-filepatterns: use bytes instead of String
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    84
47949
696abab107b4 rust: Generalize the `trim_end_newlines` utility of byte strings
Simon Sapin <simon.sapin@octobus.net>
parents: 46742
diff changeset
    85
    fn trim_start(&self) -> &[u8] {
696abab107b4 rust: Generalize the `trim_end_newlines` utility of byte strings
Simon Sapin <simon.sapin@octobus.net>
parents: 46742
diff changeset
    86
        self.trim_start_matches(|byte| byte.is_ascii_whitespace())
696abab107b4 rust: Generalize the `trim_end_newlines` utility of byte strings
Simon Sapin <simon.sapin@octobus.net>
parents: 46742
diff changeset
    87
    }
696abab107b4 rust: Generalize the `trim_end_newlines` utility of byte strings
Simon Sapin <simon.sapin@octobus.net>
parents: 46742
diff changeset
    88
696abab107b4 rust: Generalize the `trim_end_newlines` utility of byte strings
Simon Sapin <simon.sapin@octobus.net>
parents: 46742
diff changeset
    89
    fn trim_end_matches(&self, mut f: impl FnMut(u8) -> bool) -> &Self {
696abab107b4 rust: Generalize the `trim_end_newlines` utility of byte strings
Simon Sapin <simon.sapin@octobus.net>
parents: 46742
diff changeset
    90
        if let Some(last) = self.iter().rposition(|&byte| !f(byte)) {
46669
e8cd519a0a34 rhg: Ignore trailing newlines in .hg/sharedpath
Simon Sapin <simon.sapin@octobus.net>
parents: 46614
diff changeset
    91
            &self[..=last]
e8cd519a0a34 rhg: Ignore trailing newlines in .hg/sharedpath
Simon Sapin <simon.sapin@octobus.net>
parents: 46614
diff changeset
    92
        } else {
e8cd519a0a34 rhg: Ignore trailing newlines in .hg/sharedpath
Simon Sapin <simon.sapin@octobus.net>
parents: 46614
diff changeset
    93
            &[]
e8cd519a0a34 rhg: Ignore trailing newlines in .hg/sharedpath
Simon Sapin <simon.sapin@octobus.net>
parents: 46614
diff changeset
    94
        }
e8cd519a0a34 rhg: Ignore trailing newlines in .hg/sharedpath
Simon Sapin <simon.sapin@octobus.net>
parents: 46614
diff changeset
    95
    }
47949
696abab107b4 rust: Generalize the `trim_end_newlines` utility of byte strings
Simon Sapin <simon.sapin@octobus.net>
parents: 46742
diff changeset
    96
696abab107b4 rust: Generalize the `trim_end_newlines` utility of byte strings
Simon Sapin <simon.sapin@octobus.net>
parents: 46742
diff changeset
    97
    fn trim_start_matches(&self, mut f: impl FnMut(u8) -> bool) -> &Self {
696abab107b4 rust: Generalize the `trim_end_newlines` utility of byte strings
Simon Sapin <simon.sapin@octobus.net>
parents: 46742
diff changeset
    98
        if let Some(first) = self.iter().position(|&byte| !f(byte)) {
42610
5672bb73f61e rust-utils: add docstrings and doctests for utils.rs
Raphaël Gomès <rgomes@octobus.net>
parents: 42609
diff changeset
    99
            &self[first..]
5672bb73f61e rust-utils: add docstrings and doctests for utils.rs
Raphaël Gomès <rgomes@octobus.net>
parents: 42609
diff changeset
   100
        } else {
5672bb73f61e rust-utils: add docstrings and doctests for utils.rs
Raphaël Gomès <rgomes@octobus.net>
parents: 42609
diff changeset
   101
            &[]
5672bb73f61e rust-utils: add docstrings and doctests for utils.rs
Raphaël Gomès <rgomes@octobus.net>
parents: 42609
diff changeset
   102
        }
5672bb73f61e rust-utils: add docstrings and doctests for utils.rs
Raphaël Gomès <rgomes@octobus.net>
parents: 42609
diff changeset
   103
    }
5672bb73f61e rust-utils: add docstrings and doctests for utils.rs
Raphaël Gomès <rgomes@octobus.net>
parents: 42609
diff changeset
   104
5672bb73f61e rust-utils: add docstrings and doctests for utils.rs
Raphaël Gomès <rgomes@octobus.net>
parents: 42609
diff changeset
   105
    /// ```
5672bb73f61e rust-utils: add docstrings and doctests for utils.rs
Raphaël Gomès <rgomes@octobus.net>
parents: 42609
diff changeset
   106
    /// use hg::utils::SliceExt;
5672bb73f61e rust-utils: add docstrings and doctests for utils.rs
Raphaël Gomès <rgomes@octobus.net>
parents: 42609
diff changeset
   107
    /// assert_eq!(
5672bb73f61e rust-utils: add docstrings and doctests for utils.rs
Raphaël Gomès <rgomes@octobus.net>
parents: 42609
diff changeset
   108
    ///     b"  to trim  ".trim(),
5672bb73f61e rust-utils: add docstrings and doctests for utils.rs
Raphaël Gomès <rgomes@octobus.net>
parents: 42609
diff changeset
   109
    ///     b"to trim"
5672bb73f61e rust-utils: add docstrings and doctests for utils.rs
Raphaël Gomès <rgomes@octobus.net>
parents: 42609
diff changeset
   110
    /// );
5672bb73f61e rust-utils: add docstrings and doctests for utils.rs
Raphaël Gomès <rgomes@octobus.net>
parents: 42609
diff changeset
   111
    /// assert_eq!(
5672bb73f61e rust-utils: add docstrings and doctests for utils.rs
Raphaël Gomès <rgomes@octobus.net>
parents: 42609
diff changeset
   112
    ///     b"to trim  ".trim(),
5672bb73f61e rust-utils: add docstrings and doctests for utils.rs
Raphaël Gomès <rgomes@octobus.net>
parents: 42609
diff changeset
   113
    ///     b"to trim"
5672bb73f61e rust-utils: add docstrings and doctests for utils.rs
Raphaël Gomès <rgomes@octobus.net>
parents: 42609
diff changeset
   114
    /// );
5672bb73f61e rust-utils: add docstrings and doctests for utils.rs
Raphaël Gomès <rgomes@octobus.net>
parents: 42609
diff changeset
   115
    /// assert_eq!(
5672bb73f61e rust-utils: add docstrings and doctests for utils.rs
Raphaël Gomès <rgomes@octobus.net>
parents: 42609
diff changeset
   116
    ///     b"  to trim".trim(),
5672bb73f61e rust-utils: add docstrings and doctests for utils.rs
Raphaël Gomès <rgomes@octobus.net>
parents: 42609
diff changeset
   117
    ///     b"to trim"
5672bb73f61e rust-utils: add docstrings and doctests for utils.rs
Raphaël Gomès <rgomes@octobus.net>
parents: 42609
diff changeset
   118
    /// );
5672bb73f61e rust-utils: add docstrings and doctests for utils.rs
Raphaël Gomès <rgomes@octobus.net>
parents: 42609
diff changeset
   119
    /// ```
5672bb73f61e rust-utils: add docstrings and doctests for utils.rs
Raphaël Gomès <rgomes@octobus.net>
parents: 42609
diff changeset
   120
    fn trim(&self) -> &[u8] {
5672bb73f61e rust-utils: add docstrings and doctests for utils.rs
Raphaël Gomès <rgomes@octobus.net>
parents: 42609
diff changeset
   121
        self.trim_start().trim_end()
5672bb73f61e rust-utils: add docstrings and doctests for utils.rs
Raphaël Gomès <rgomes@octobus.net>
parents: 42609
diff changeset
   122
    }
42863
62eabdf91f85 rustfilepatterns: refactor the pattern of removing a prefix from a &[u8]
Valentin Gatien-Baron <valentin.gatienbaron@gmail.com>
parents: 42841
diff changeset
   123
62eabdf91f85 rustfilepatterns: refactor the pattern of removing a prefix from a &[u8]
Valentin Gatien-Baron <valentin.gatienbaron@gmail.com>
parents: 42841
diff changeset
   124
    fn drop_prefix(&self, needle: &Self) -> Option<&Self> {
62eabdf91f85 rustfilepatterns: refactor the pattern of removing a prefix from a &[u8]
Valentin Gatien-Baron <valentin.gatienbaron@gmail.com>
parents: 42841
diff changeset
   125
        if self.starts_with(needle) {
62eabdf91f85 rustfilepatterns: refactor the pattern of removing a prefix from a &[u8]
Valentin Gatien-Baron <valentin.gatienbaron@gmail.com>
parents: 42841
diff changeset
   126
            Some(&self[needle.len()..])
62eabdf91f85 rustfilepatterns: refactor the pattern of removing a prefix from a &[u8]
Valentin Gatien-Baron <valentin.gatienbaron@gmail.com>
parents: 42841
diff changeset
   127
        } else {
62eabdf91f85 rustfilepatterns: refactor the pattern of removing a prefix from a &[u8]
Valentin Gatien-Baron <valentin.gatienbaron@gmail.com>
parents: 42841
diff changeset
   128
            None
62eabdf91f85 rustfilepatterns: refactor the pattern of removing a prefix from a &[u8]
Valentin Gatien-Baron <valentin.gatienbaron@gmail.com>
parents: 42841
diff changeset
   129
        }
62eabdf91f85 rustfilepatterns: refactor the pattern of removing a prefix from a &[u8]
Valentin Gatien-Baron <valentin.gatienbaron@gmail.com>
parents: 42841
diff changeset
   130
    }
46505
a25033eb43b5 rhg: add limited support for the `config` sub-command
Simon Sapin <simon.sapin@octobus.net>
parents: 46483
diff changeset
   131
a25033eb43b5 rhg: add limited support for the `config` sub-command
Simon Sapin <simon.sapin@octobus.net>
parents: 46483
diff changeset
   132
    fn split_2(&self, separator: u8) -> Option<(&[u8], &[u8])> {
a25033eb43b5 rhg: add limited support for the `config` sub-command
Simon Sapin <simon.sapin@octobus.net>
parents: 46483
diff changeset
   133
        let mut iter = self.splitn(2, |&byte| byte == separator);
a25033eb43b5 rhg: add limited support for the `config` sub-command
Simon Sapin <simon.sapin@octobus.net>
parents: 46483
diff changeset
   134
        let a = iter.next()?;
a25033eb43b5 rhg: add limited support for the `config` sub-command
Simon Sapin <simon.sapin@octobus.net>
parents: 46483
diff changeset
   135
        let b = iter.next()?;
a25033eb43b5 rhg: add limited support for the `config` sub-command
Simon Sapin <simon.sapin@octobus.net>
parents: 46483
diff changeset
   136
        Some((a, b))
a25033eb43b5 rhg: add limited support for the `config` sub-command
Simon Sapin <simon.sapin@octobus.net>
parents: 46483
diff changeset
   137
    }
47961
4d2a5ca060e3 rust: Add a Filelog struct that wraps Revlog
Simon Sapin <simon.sapin@octobus.net>
parents: 47949
diff changeset
   138
4d2a5ca060e3 rust: Add a Filelog struct that wraps Revlog
Simon Sapin <simon.sapin@octobus.net>
parents: 47949
diff changeset
   139
    fn split_2_by_slice(&self, separator: &[u8]) -> Option<(&[u8], &[u8])> {
4d2a5ca060e3 rust: Add a Filelog struct that wraps Revlog
Simon Sapin <simon.sapin@octobus.net>
parents: 47949
diff changeset
   140
        if let Some(pos) = find_slice_in_slice(self, separator) {
4d2a5ca060e3 rust: Add a Filelog struct that wraps Revlog
Simon Sapin <simon.sapin@octobus.net>
parents: 47949
diff changeset
   141
            Some((&self[..pos], &self[pos + separator.len()..]))
4d2a5ca060e3 rust: Add a Filelog struct that wraps Revlog
Simon Sapin <simon.sapin@octobus.net>
parents: 47949
diff changeset
   142
        } else {
4d2a5ca060e3 rust: Add a Filelog struct that wraps Revlog
Simon Sapin <simon.sapin@octobus.net>
parents: 47949
diff changeset
   143
            None
4d2a5ca060e3 rust: Add a Filelog struct that wraps Revlog
Simon Sapin <simon.sapin@octobus.net>
parents: 47949
diff changeset
   144
        }
4d2a5ca060e3 rust: Add a Filelog struct that wraps Revlog
Simon Sapin <simon.sapin@octobus.net>
parents: 47949
diff changeset
   145
    }
42437
9609430d3625 rust-filepatterns: use bytes instead of String
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   146
}
44268
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44265
diff changeset
   147
48417
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents: 47961
diff changeset
   148
pub trait StrExt {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents: 47961
diff changeset
   149
    // TODO: Use https://doc.rust-lang.org/nightly/std/primitive.str.html#method.split_once
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents: 47961
diff changeset
   150
    // once we require Rust 1.52+
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents: 47961
diff changeset
   151
    fn split_2(&self, separator: char) -> Option<(&str, &str)>;
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents: 47961
diff changeset
   152
}
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents: 47961
diff changeset
   153
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents: 47961
diff changeset
   154
impl StrExt for str {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents: 47961
diff changeset
   155
    fn split_2(&self, separator: char) -> Option<(&str, &str)> {
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents: 47961
diff changeset
   156
        let mut iter = self.splitn(2, separator);
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents: 47961
diff changeset
   157
        let a = iter.next()?;
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents: 47961
diff changeset
   158
        let b = iter.next()?;
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents: 47961
diff changeset
   159
        Some((a, b))
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents: 47961
diff changeset
   160
    }
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents: 47961
diff changeset
   161
}
5734b03ecf3e rhg: Initial repository locking
Simon Sapin <simon.sapin@octobus.net>
parents: 47961
diff changeset
   162
44268
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44265
diff changeset
   163
pub trait Escaped {
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44265
diff changeset
   164
    /// Return bytes escaped for display to the user
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44265
diff changeset
   165
    fn escaped_bytes(&self) -> Vec<u8>;
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44265
diff changeset
   166
}
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44265
diff changeset
   167
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44265
diff changeset
   168
impl Escaped for u8 {
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44265
diff changeset
   169
    fn escaped_bytes(&self) -> Vec<u8> {
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44265
diff changeset
   170
        let mut acc = vec![];
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44265
diff changeset
   171
        match self {
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44265
diff changeset
   172
            c @ b'\'' | c @ b'\\' => {
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44265
diff changeset
   173
                acc.push(b'\\');
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44265
diff changeset
   174
                acc.push(*c);
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44265
diff changeset
   175
            }
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44265
diff changeset
   176
            b'\t' => {
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44265
diff changeset
   177
                acc.extend(br"\\t");
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44265
diff changeset
   178
            }
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44265
diff changeset
   179
            b'\n' => {
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44265
diff changeset
   180
                acc.extend(br"\\n");
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44265
diff changeset
   181
            }
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44265
diff changeset
   182
            b'\r' => {
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44265
diff changeset
   183
                acc.extend(br"\\r");
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44265
diff changeset
   184
            }
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44265
diff changeset
   185
            c if (*c < b' ' || *c >= 127) => {
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44265
diff changeset
   186
                write!(acc, "\\x{:x}", self).unwrap();
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44265
diff changeset
   187
            }
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44265
diff changeset
   188
            c => {
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44265
diff changeset
   189
                acc.push(*c);
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44265
diff changeset
   190
            }
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44265
diff changeset
   191
        }
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44265
diff changeset
   192
        acc
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44265
diff changeset
   193
    }
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44265
diff changeset
   194
}
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44265
diff changeset
   195
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44265
diff changeset
   196
impl<'a, T: Escaped> Escaped for &'a [T] {
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44265
diff changeset
   197
    fn escaped_bytes(&self) -> Vec<u8> {
44973
26114bd6ec60 rust: do a clippy pass
Raphaël Gomès <rgomes@octobus.net>
parents: 44268
diff changeset
   198
        self.iter().flat_map(Escaped::escaped_bytes).collect()
44268
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44265
diff changeset
   199
    }
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44265
diff changeset
   200
}
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44265
diff changeset
   201
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44265
diff changeset
   202
impl<T: Escaped> Escaped for Vec<T> {
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44265
diff changeset
   203
    fn escaped_bytes(&self) -> Vec<u8> {
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44265
diff changeset
   204
        self.deref().escaped_bytes()
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44265
diff changeset
   205
    }
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44265
diff changeset
   206
}
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44265
diff changeset
   207
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44265
diff changeset
   208
impl<'a> Escaped for &'a HgPath {
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44265
diff changeset
   209
    fn escaped_bytes(&self) -> Vec<u8> {
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44265
diff changeset
   210
        self.as_bytes().escaped_bytes()
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44265
diff changeset
   211
    }
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44265
diff changeset
   212
}
46090
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents: 44973
diff changeset
   213
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents: 44973
diff changeset
   214
// TODO: use the str method when we require Rust 1.45
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents: 44973
diff changeset
   215
pub(crate) fn strip_suffix<'a>(s: &'a str, suffix: &str) -> Option<&'a str> {
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents: 44973
diff changeset
   216
    if s.ends_with(suffix) {
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents: 44973
diff changeset
   217
        Some(&s[..s.len() - suffix.len()])
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents: 44973
diff changeset
   218
    } else {
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents: 44973
diff changeset
   219
        None
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents: 44973
diff changeset
   220
    }
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents: 44973
diff changeset
   221
}
46445
ca3f73cc3cf4 rhg: Simplify CommandError based on its use
Simon Sapin <simon.sapin@octobus.net>
parents: 46090
diff changeset
   222
46601
755c31a1caf9 rhg: Add support for the blackbox extension
Simon Sapin <simon.sapin@octobus.net>
parents: 46586
diff changeset
   223
#[cfg(unix)]
755c31a1caf9 rhg: Add support for the blackbox extension
Simon Sapin <simon.sapin@octobus.net>
parents: 46586
diff changeset
   224
pub fn shell_quote(value: &[u8]) -> Vec<u8> {
755c31a1caf9 rhg: Add support for the blackbox extension
Simon Sapin <simon.sapin@octobus.net>
parents: 46586
diff changeset
   225
    // TODO: Use the `matches!` macro when we require Rust 1.42+
755c31a1caf9 rhg: Add support for the blackbox extension
Simon Sapin <simon.sapin@octobus.net>
parents: 46586
diff changeset
   226
    if value.iter().all(|&byte| match byte {
755c31a1caf9 rhg: Add support for the blackbox extension
Simon Sapin <simon.sapin@octobus.net>
parents: 46586
diff changeset
   227
        b'a'..=b'z'
755c31a1caf9 rhg: Add support for the blackbox extension
Simon Sapin <simon.sapin@octobus.net>
parents: 46586
diff changeset
   228
        | b'A'..=b'Z'
755c31a1caf9 rhg: Add support for the blackbox extension
Simon Sapin <simon.sapin@octobus.net>
parents: 46586
diff changeset
   229
        | b'0'..=b'9'
755c31a1caf9 rhg: Add support for the blackbox extension
Simon Sapin <simon.sapin@octobus.net>
parents: 46586
diff changeset
   230
        | b'.'
755c31a1caf9 rhg: Add support for the blackbox extension
Simon Sapin <simon.sapin@octobus.net>
parents: 46586
diff changeset
   231
        | b'_'
755c31a1caf9 rhg: Add support for the blackbox extension
Simon Sapin <simon.sapin@octobus.net>
parents: 46586
diff changeset
   232
        | b'/'
755c31a1caf9 rhg: Add support for the blackbox extension
Simon Sapin <simon.sapin@octobus.net>
parents: 46586
diff changeset
   233
        | b'+'
755c31a1caf9 rhg: Add support for the blackbox extension
Simon Sapin <simon.sapin@octobus.net>
parents: 46586
diff changeset
   234
        | b'-' => true,
755c31a1caf9 rhg: Add support for the blackbox extension
Simon Sapin <simon.sapin@octobus.net>
parents: 46586
diff changeset
   235
        _ => false,
755c31a1caf9 rhg: Add support for the blackbox extension
Simon Sapin <simon.sapin@octobus.net>
parents: 46586
diff changeset
   236
    }) {
755c31a1caf9 rhg: Add support for the blackbox extension
Simon Sapin <simon.sapin@octobus.net>
parents: 46586
diff changeset
   237
        value.to_owned()
755c31a1caf9 rhg: Add support for the blackbox extension
Simon Sapin <simon.sapin@octobus.net>
parents: 46586
diff changeset
   238
    } else {
755c31a1caf9 rhg: Add support for the blackbox extension
Simon Sapin <simon.sapin@octobus.net>
parents: 46586
diff changeset
   239
        let mut quoted = Vec::with_capacity(value.len() + 2);
755c31a1caf9 rhg: Add support for the blackbox extension
Simon Sapin <simon.sapin@octobus.net>
parents: 46586
diff changeset
   240
        quoted.push(b'\'');
755c31a1caf9 rhg: Add support for the blackbox extension
Simon Sapin <simon.sapin@octobus.net>
parents: 46586
diff changeset
   241
        for &byte in value {
755c31a1caf9 rhg: Add support for the blackbox extension
Simon Sapin <simon.sapin@octobus.net>
parents: 46586
diff changeset
   242
            if byte == b'\'' {
755c31a1caf9 rhg: Add support for the blackbox extension
Simon Sapin <simon.sapin@octobus.net>
parents: 46586
diff changeset
   243
                quoted.push(b'\\');
755c31a1caf9 rhg: Add support for the blackbox extension
Simon Sapin <simon.sapin@octobus.net>
parents: 46586
diff changeset
   244
            }
755c31a1caf9 rhg: Add support for the blackbox extension
Simon Sapin <simon.sapin@octobus.net>
parents: 46586
diff changeset
   245
            quoted.push(byte);
755c31a1caf9 rhg: Add support for the blackbox extension
Simon Sapin <simon.sapin@octobus.net>
parents: 46586
diff changeset
   246
        }
755c31a1caf9 rhg: Add support for the blackbox extension
Simon Sapin <simon.sapin@octobus.net>
parents: 46586
diff changeset
   247
        quoted.push(b'\'');
755c31a1caf9 rhg: Add support for the blackbox extension
Simon Sapin <simon.sapin@octobus.net>
parents: 46586
diff changeset
   248
        quoted
755c31a1caf9 rhg: Add support for the blackbox extension
Simon Sapin <simon.sapin@octobus.net>
parents: 46586
diff changeset
   249
    }
755c31a1caf9 rhg: Add support for the blackbox extension
Simon Sapin <simon.sapin@octobus.net>
parents: 46586
diff changeset
   250
}
755c31a1caf9 rhg: Add support for the blackbox extension
Simon Sapin <simon.sapin@octobus.net>
parents: 46586
diff changeset
   251
46445
ca3f73cc3cf4 rhg: Simplify CommandError based on its use
Simon Sapin <simon.sapin@octobus.net>
parents: 46090
diff changeset
   252
pub fn current_dir() -> Result<std::path::PathBuf, HgError> {
ca3f73cc3cf4 rhg: Simplify CommandError based on its use
Simon Sapin <simon.sapin@octobus.net>
parents: 46090
diff changeset
   253
    std::env::current_dir().map_err(|error| HgError::IoError {
ca3f73cc3cf4 rhg: Simplify CommandError based on its use
Simon Sapin <simon.sapin@octobus.net>
parents: 46090
diff changeset
   254
        error,
ca3f73cc3cf4 rhg: Simplify CommandError based on its use
Simon Sapin <simon.sapin@octobus.net>
parents: 46090
diff changeset
   255
        context: IoErrorContext::CurrentDir,
ca3f73cc3cf4 rhg: Simplify CommandError based on its use
Simon Sapin <simon.sapin@octobus.net>
parents: 46090
diff changeset
   256
    })
ca3f73cc3cf4 rhg: Simplify CommandError based on its use
Simon Sapin <simon.sapin@octobus.net>
parents: 46090
diff changeset
   257
}
46483
2845892dd489 rust: Parse system and user configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46445
diff changeset
   258
2845892dd489 rust: Parse system and user configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46445
diff changeset
   259
pub fn current_exe() -> Result<std::path::PathBuf, HgError> {
2845892dd489 rust: Parse system and user configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46445
diff changeset
   260
    std::env::current_exe().map_err(|error| HgError::IoError {
2845892dd489 rust: Parse system and user configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46445
diff changeset
   261
        error,
2845892dd489 rust: Parse system and user configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46445
diff changeset
   262
        context: IoErrorContext::CurrentExe,
2845892dd489 rust: Parse system and user configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46445
diff changeset
   263
    })
2845892dd489 rust: Parse system and user configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46445
diff changeset
   264
}
46586
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   265
46742
91ab5190a3de rhg: Add support for environment variables in config include paths
Simon Sapin <simon.sapin@octobus.net>
parents: 46669
diff changeset
   266
/// Expand `$FOO` and `${FOO}` environment variables in the given byte string
91ab5190a3de rhg: Add support for environment variables in config include paths
Simon Sapin <simon.sapin@octobus.net>
parents: 46669
diff changeset
   267
pub fn expand_vars(s: &[u8]) -> std::borrow::Cow<[u8]> {
91ab5190a3de rhg: Add support for environment variables in config include paths
Simon Sapin <simon.sapin@octobus.net>
parents: 46669
diff changeset
   268
    lazy_static::lazy_static! {
91ab5190a3de rhg: Add support for environment variables in config include paths
Simon Sapin <simon.sapin@octobus.net>
parents: 46669
diff changeset
   269
        /// https://github.com/python/cpython/blob/3.9/Lib/posixpath.py#L301
91ab5190a3de rhg: Add support for environment variables in config include paths
Simon Sapin <simon.sapin@octobus.net>
parents: 46669
diff changeset
   270
        /// The `x` makes whitespace ignored.
91ab5190a3de rhg: Add support for environment variables in config include paths
Simon Sapin <simon.sapin@octobus.net>
parents: 46669
diff changeset
   271
        /// `-u` disables the Unicode flag, which makes `\w` like Python with the ASCII flag.
91ab5190a3de rhg: Add support for environment variables in config include paths
Simon Sapin <simon.sapin@octobus.net>
parents: 46669
diff changeset
   272
        static ref VAR_RE: regex::bytes::Regex =
91ab5190a3de rhg: Add support for environment variables in config include paths
Simon Sapin <simon.sapin@octobus.net>
parents: 46669
diff changeset
   273
            regex::bytes::Regex::new(r"(?x-u)
91ab5190a3de rhg: Add support for environment variables in config include paths
Simon Sapin <simon.sapin@octobus.net>
parents: 46669
diff changeset
   274
                \$
91ab5190a3de rhg: Add support for environment variables in config include paths
Simon Sapin <simon.sapin@octobus.net>
parents: 46669
diff changeset
   275
                (?:
91ab5190a3de rhg: Add support for environment variables in config include paths
Simon Sapin <simon.sapin@octobus.net>
parents: 46669
diff changeset
   276
                    (\w+)
91ab5190a3de rhg: Add support for environment variables in config include paths
Simon Sapin <simon.sapin@octobus.net>
parents: 46669
diff changeset
   277
                    |
91ab5190a3de rhg: Add support for environment variables in config include paths
Simon Sapin <simon.sapin@octobus.net>
parents: 46669
diff changeset
   278
                    \{
91ab5190a3de rhg: Add support for environment variables in config include paths
Simon Sapin <simon.sapin@octobus.net>
parents: 46669
diff changeset
   279
                        ([^}]*)
91ab5190a3de rhg: Add support for environment variables in config include paths
Simon Sapin <simon.sapin@octobus.net>
parents: 46669
diff changeset
   280
                    \}
91ab5190a3de rhg: Add support for environment variables in config include paths
Simon Sapin <simon.sapin@octobus.net>
parents: 46669
diff changeset
   281
                )
91ab5190a3de rhg: Add support for environment variables in config include paths
Simon Sapin <simon.sapin@octobus.net>
parents: 46669
diff changeset
   282
            ").unwrap();
91ab5190a3de rhg: Add support for environment variables in config include paths
Simon Sapin <simon.sapin@octobus.net>
parents: 46669
diff changeset
   283
    }
91ab5190a3de rhg: Add support for environment variables in config include paths
Simon Sapin <simon.sapin@octobus.net>
parents: 46669
diff changeset
   284
    VAR_RE.replace_all(s, |captures: &regex::bytes::Captures| {
91ab5190a3de rhg: Add support for environment variables in config include paths
Simon Sapin <simon.sapin@octobus.net>
parents: 46669
diff changeset
   285
        let var_name = files::get_os_str_from_bytes(
91ab5190a3de rhg: Add support for environment variables in config include paths
Simon Sapin <simon.sapin@octobus.net>
parents: 46669
diff changeset
   286
            captures
91ab5190a3de rhg: Add support for environment variables in config include paths
Simon Sapin <simon.sapin@octobus.net>
parents: 46669
diff changeset
   287
                .get(1)
91ab5190a3de rhg: Add support for environment variables in config include paths
Simon Sapin <simon.sapin@octobus.net>
parents: 46669
diff changeset
   288
                .or_else(|| captures.get(2))
91ab5190a3de rhg: Add support for environment variables in config include paths
Simon Sapin <simon.sapin@octobus.net>
parents: 46669
diff changeset
   289
                .expect("either side of `|` must participate in match")
91ab5190a3de rhg: Add support for environment variables in config include paths
Simon Sapin <simon.sapin@octobus.net>
parents: 46669
diff changeset
   290
                .as_bytes(),
91ab5190a3de rhg: Add support for environment variables in config include paths
Simon Sapin <simon.sapin@octobus.net>
parents: 46669
diff changeset
   291
        );
91ab5190a3de rhg: Add support for environment variables in config include paths
Simon Sapin <simon.sapin@octobus.net>
parents: 46669
diff changeset
   292
        std::env::var_os(var_name)
91ab5190a3de rhg: Add support for environment variables in config include paths
Simon Sapin <simon.sapin@octobus.net>
parents: 46669
diff changeset
   293
            .map(files::get_bytes_from_os_str)
91ab5190a3de rhg: Add support for environment variables in config include paths
Simon Sapin <simon.sapin@octobus.net>
parents: 46669
diff changeset
   294
            .unwrap_or_else(|| {
91ab5190a3de rhg: Add support for environment variables in config include paths
Simon Sapin <simon.sapin@octobus.net>
parents: 46669
diff changeset
   295
                // Referencing an environment variable that does not exist.
91ab5190a3de rhg: Add support for environment variables in config include paths
Simon Sapin <simon.sapin@octobus.net>
parents: 46669
diff changeset
   296
                // Leave the $FOO reference as-is.
91ab5190a3de rhg: Add support for environment variables in config include paths
Simon Sapin <simon.sapin@octobus.net>
parents: 46669
diff changeset
   297
                captures[0].to_owned()
91ab5190a3de rhg: Add support for environment variables in config include paths
Simon Sapin <simon.sapin@octobus.net>
parents: 46669
diff changeset
   298
            })
91ab5190a3de rhg: Add support for environment variables in config include paths
Simon Sapin <simon.sapin@octobus.net>
parents: 46669
diff changeset
   299
    })
91ab5190a3de rhg: Add support for environment variables in config include paths
Simon Sapin <simon.sapin@octobus.net>
parents: 46669
diff changeset
   300
}
91ab5190a3de rhg: Add support for environment variables in config include paths
Simon Sapin <simon.sapin@octobus.net>
parents: 46669
diff changeset
   301
91ab5190a3de rhg: Add support for environment variables in config include paths
Simon Sapin <simon.sapin@octobus.net>
parents: 46669
diff changeset
   302
#[test]
91ab5190a3de rhg: Add support for environment variables in config include paths
Simon Sapin <simon.sapin@octobus.net>
parents: 46669
diff changeset
   303
fn test_expand_vars() {
91ab5190a3de rhg: Add support for environment variables in config include paths
Simon Sapin <simon.sapin@octobus.net>
parents: 46669
diff changeset
   304
    // Modifying process-global state in a test isn’t great,
91ab5190a3de rhg: Add support for environment variables in config include paths
Simon Sapin <simon.sapin@octobus.net>
parents: 46669
diff changeset
   305
    // but hopefully this won’t collide with anything.
91ab5190a3de rhg: Add support for environment variables in config include paths
Simon Sapin <simon.sapin@octobus.net>
parents: 46669
diff changeset
   306
    std::env::set_var("TEST_EXPAND_VAR", "1");
91ab5190a3de rhg: Add support for environment variables in config include paths
Simon Sapin <simon.sapin@octobus.net>
parents: 46669
diff changeset
   307
    assert_eq!(
91ab5190a3de rhg: Add support for environment variables in config include paths
Simon Sapin <simon.sapin@octobus.net>
parents: 46669
diff changeset
   308
        expand_vars(b"before/$TEST_EXPAND_VAR/after"),
91ab5190a3de rhg: Add support for environment variables in config include paths
Simon Sapin <simon.sapin@octobus.net>
parents: 46669
diff changeset
   309
        &b"before/1/after"[..]
91ab5190a3de rhg: Add support for environment variables in config include paths
Simon Sapin <simon.sapin@octobus.net>
parents: 46669
diff changeset
   310
    );
91ab5190a3de rhg: Add support for environment variables in config include paths
Simon Sapin <simon.sapin@octobus.net>
parents: 46669
diff changeset
   311
    assert_eq!(
91ab5190a3de rhg: Add support for environment variables in config include paths
Simon Sapin <simon.sapin@octobus.net>
parents: 46669
diff changeset
   312
        expand_vars(b"before${TEST_EXPAND_VAR}${TEST_EXPAND_VAR}${TEST_EXPAND_VAR}after"),
91ab5190a3de rhg: Add support for environment variables in config include paths
Simon Sapin <simon.sapin@octobus.net>
parents: 46669
diff changeset
   313
        &b"before111after"[..]
91ab5190a3de rhg: Add support for environment variables in config include paths
Simon Sapin <simon.sapin@octobus.net>
parents: 46669
diff changeset
   314
    );
91ab5190a3de rhg: Add support for environment variables in config include paths
Simon Sapin <simon.sapin@octobus.net>
parents: 46669
diff changeset
   315
    let s = b"before $SOME_LONG_NAME_THAT_WE_ASSUME_IS_NOT_AN_ACTUAL_ENV_VAR after";
91ab5190a3de rhg: Add support for environment variables in config include paths
Simon Sapin <simon.sapin@octobus.net>
parents: 46669
diff changeset
   316
    assert_eq!(expand_vars(s), &s[..]);
91ab5190a3de rhg: Add support for environment variables in config include paths
Simon Sapin <simon.sapin@octobus.net>
parents: 46669
diff changeset
   317
}
91ab5190a3de rhg: Add support for environment variables in config include paths
Simon Sapin <simon.sapin@octobus.net>
parents: 46669
diff changeset
   318
46586
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   319
pub(crate) enum MergeResult<V> {
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   320
    UseLeftValue,
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   321
    UseRightValue,
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   322
    UseNewValue(V),
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   323
}
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   324
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   325
/// Return the union of the two given maps,
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   326
/// calling `merge(key, left_value, right_value)` to resolve keys that exist in
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   327
/// both.
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   328
///
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   329
/// CC https://github.com/bodil/im-rs/issues/166
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   330
pub(crate) fn ordmap_union_with_merge<K, V>(
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   331
    left: OrdMap<K, V>,
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   332
    right: OrdMap<K, V>,
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   333
    mut merge: impl FnMut(&K, &V, &V) -> MergeResult<V>,
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   334
) -> OrdMap<K, V>
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   335
where
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   336
    K: Clone + Ord,
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   337
    V: Clone + PartialEq,
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   338
{
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   339
    if left.ptr_eq(&right) {
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   340
        // One of the two maps is an unmodified clone of the other
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   341
        left
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   342
    } else if left.len() / 2 > right.len() {
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   343
        // When two maps have different sizes,
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   344
        // their size difference is a lower bound on
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   345
        // how many keys of the larger map are not also in the smaller map.
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   346
        // This in turn is a lower bound on the number of differences in
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   347
        // `OrdMap::diff` and the "amount of work" that would be done
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   348
        // by `ordmap_union_with_merge_by_diff`.
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   349
        //
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   350
        // Here `left` is more than twice the size of `right`,
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   351
        // so the number of differences is more than the total size of
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   352
        // `right`. Therefore an algorithm based on iterating `right`
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   353
        // is more efficient.
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   354
        //
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   355
        // This helps a lot when a tiny (or empty) map is merged
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   356
        // with a large one.
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   357
        ordmap_union_with_merge_by_iter(left, right, merge)
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   358
    } else if left.len() < right.len() / 2 {
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   359
        // Same as above but with `left` and `right` swapped
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   360
        ordmap_union_with_merge_by_iter(right, left, |key, a, b| {
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   361
            // Also swapped in `merge` arguments:
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   362
            match merge(key, b, a) {
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   363
                MergeResult::UseNewValue(v) => MergeResult::UseNewValue(v),
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   364
                // … and swap back in `merge` result:
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   365
                MergeResult::UseLeftValue => MergeResult::UseRightValue,
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   366
                MergeResult::UseRightValue => MergeResult::UseLeftValue,
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   367
            }
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   368
        })
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   369
    } else {
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   370
        // For maps of similar size, use the algorithm based on `OrdMap::diff`
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   371
        ordmap_union_with_merge_by_diff(left, right, merge)
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   372
    }
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   373
}
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   374
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   375
/// Efficient if `right` is much smaller than `left`
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   376
fn ordmap_union_with_merge_by_iter<K, V>(
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   377
    mut left: OrdMap<K, V>,
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   378
    right: OrdMap<K, V>,
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   379
    mut merge: impl FnMut(&K, &V, &V) -> MergeResult<V>,
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   380
) -> OrdMap<K, V>
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   381
where
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   382
    K: Clone + Ord,
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   383
    V: Clone,
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   384
{
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   385
    for (key, right_value) in right {
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   386
        match left.get(&key) {
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   387
            None => {
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   388
                left.insert(key, right_value);
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   389
            }
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   390
            Some(left_value) => match merge(&key, left_value, &right_value) {
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   391
                MergeResult::UseLeftValue => {}
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   392
                MergeResult::UseRightValue => {
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   393
                    left.insert(key, right_value);
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   394
                }
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   395
                MergeResult::UseNewValue(new_value) => {
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   396
                    left.insert(key, new_value);
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   397
                }
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   398
            },
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   399
        }
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   400
    }
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   401
    left
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   402
}
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   403
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   404
/// Fallback when both maps are of similar size
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   405
fn ordmap_union_with_merge_by_diff<K, V>(
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   406
    mut left: OrdMap<K, V>,
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   407
    mut right: OrdMap<K, V>,
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   408
    mut merge: impl FnMut(&K, &V, &V) -> MergeResult<V>,
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   409
) -> OrdMap<K, V>
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   410
where
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   411
    K: Clone + Ord,
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   412
    V: Clone + PartialEq,
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   413
{
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   414
    // (key, value) pairs that would need to be inserted in either map
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   415
    // in order to turn it into the union.
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   416
    //
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   417
    // TODO: if/when https://github.com/bodil/im-rs/pull/168 is accepted,
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   418
    // change these from `Vec<(K, V)>` to `Vec<(&K, Cow<V>)>`
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   419
    // with `left_updates` only borrowing from `right` and `right_updates` from
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   420
    // `left`, and with `Cow::Owned` used for `MergeResult::UseNewValue`.
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   421
    //
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   422
    // This would allow moving all `.clone()` calls to after we’ve decided
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   423
    // which of `right_updates` or `left_updates` to use
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   424
    // (value ones becoming `Cow::into_owned`),
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   425
    // and avoid making clones we don’t end up using.
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   426
    let mut left_updates = Vec::new();
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   427
    let mut right_updates = Vec::new();
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   428
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   429
    for difference in left.diff(&right) {
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   430
        match difference {
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   431
            DiffItem::Add(key, value) => {
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   432
                left_updates.push((key.clone(), value.clone()))
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   433
            }
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   434
            DiffItem::Remove(key, value) => {
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   435
                right_updates.push((key.clone(), value.clone()))
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   436
            }
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   437
            DiffItem::Update {
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   438
                old: (key, left_value),
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   439
                new: (_, right_value),
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   440
            } => match merge(key, left_value, right_value) {
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   441
                MergeResult::UseLeftValue => {
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   442
                    right_updates.push((key.clone(), left_value.clone()))
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   443
                }
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   444
                MergeResult::UseRightValue => {
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   445
                    left_updates.push((key.clone(), right_value.clone()))
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   446
                }
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   447
                MergeResult::UseNewValue(new_value) => {
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   448
                    left_updates.push((key.clone(), new_value.clone()));
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   449
                    right_updates.push((key.clone(), new_value))
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   450
                }
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   451
            },
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   452
        }
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   453
    }
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   454
    if left_updates.len() < right_updates.len() {
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   455
        for (key, value) in left_updates {
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   456
            left.insert(key, value);
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   457
        }
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   458
        left
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   459
    } else {
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   460
        for (key, value) in right_updates {
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   461
            right.insert(key, value);
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   462
        }
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   463
        right
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   464
    }
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46505
diff changeset
   465
}
46614
a069639783a0 rhg: Check .hg/requires for absence of required features
Simon Sapin <simon.sapin@octobus.net>
parents: 46601
diff changeset
   466
a069639783a0 rhg: Check .hg/requires for absence of required features
Simon Sapin <simon.sapin@octobus.net>
parents: 46601
diff changeset
   467
/// Join items of the iterable with the given separator, similar to Python’s
a069639783a0 rhg: Check .hg/requires for absence of required features
Simon Sapin <simon.sapin@octobus.net>
parents: 46601
diff changeset
   468
/// `separator.join(iter)`.
a069639783a0 rhg: Check .hg/requires for absence of required features
Simon Sapin <simon.sapin@octobus.net>
parents: 46601
diff changeset
   469
///
a069639783a0 rhg: Check .hg/requires for absence of required features
Simon Sapin <simon.sapin@octobus.net>
parents: 46601
diff changeset
   470
/// Formatting the return value consumes the iterator.
a069639783a0 rhg: Check .hg/requires for absence of required features
Simon Sapin <simon.sapin@octobus.net>
parents: 46601
diff changeset
   471
/// Formatting it again will produce an empty string.
a069639783a0 rhg: Check .hg/requires for absence of required features
Simon Sapin <simon.sapin@octobus.net>
parents: 46601
diff changeset
   472
pub fn join_display(
a069639783a0 rhg: Check .hg/requires for absence of required features
Simon Sapin <simon.sapin@octobus.net>
parents: 46601
diff changeset
   473
    iter: impl IntoIterator<Item = impl fmt::Display>,
a069639783a0 rhg: Check .hg/requires for absence of required features
Simon Sapin <simon.sapin@octobus.net>
parents: 46601
diff changeset
   474
    separator: impl fmt::Display,
a069639783a0 rhg: Check .hg/requires for absence of required features
Simon Sapin <simon.sapin@octobus.net>
parents: 46601
diff changeset
   475
) -> impl fmt::Display {
a069639783a0 rhg: Check .hg/requires for absence of required features
Simon Sapin <simon.sapin@octobus.net>
parents: 46601
diff changeset
   476
    JoinDisplay {
a069639783a0 rhg: Check .hg/requires for absence of required features
Simon Sapin <simon.sapin@octobus.net>
parents: 46601
diff changeset
   477
        iter: Cell::new(Some(iter.into_iter())),
a069639783a0 rhg: Check .hg/requires for absence of required features
Simon Sapin <simon.sapin@octobus.net>
parents: 46601
diff changeset
   478
        separator,
a069639783a0 rhg: Check .hg/requires for absence of required features
Simon Sapin <simon.sapin@octobus.net>
parents: 46601
diff changeset
   479
    }
a069639783a0 rhg: Check .hg/requires for absence of required features
Simon Sapin <simon.sapin@octobus.net>
parents: 46601
diff changeset
   480
}
a069639783a0 rhg: Check .hg/requires for absence of required features
Simon Sapin <simon.sapin@octobus.net>
parents: 46601
diff changeset
   481
a069639783a0 rhg: Check .hg/requires for absence of required features
Simon Sapin <simon.sapin@octobus.net>
parents: 46601
diff changeset
   482
struct JoinDisplay<I, S> {
a069639783a0 rhg: Check .hg/requires for absence of required features
Simon Sapin <simon.sapin@octobus.net>
parents: 46601
diff changeset
   483
    iter: Cell<Option<I>>,
a069639783a0 rhg: Check .hg/requires for absence of required features
Simon Sapin <simon.sapin@octobus.net>
parents: 46601
diff changeset
   484
    separator: S,
a069639783a0 rhg: Check .hg/requires for absence of required features
Simon Sapin <simon.sapin@octobus.net>
parents: 46601
diff changeset
   485
}
a069639783a0 rhg: Check .hg/requires for absence of required features
Simon Sapin <simon.sapin@octobus.net>
parents: 46601
diff changeset
   486
a069639783a0 rhg: Check .hg/requires for absence of required features
Simon Sapin <simon.sapin@octobus.net>
parents: 46601
diff changeset
   487
impl<I, T, S> fmt::Display for JoinDisplay<I, S>
a069639783a0 rhg: Check .hg/requires for absence of required features
Simon Sapin <simon.sapin@octobus.net>
parents: 46601
diff changeset
   488
where
a069639783a0 rhg: Check .hg/requires for absence of required features
Simon Sapin <simon.sapin@octobus.net>
parents: 46601
diff changeset
   489
    I: Iterator<Item = T>,
a069639783a0 rhg: Check .hg/requires for absence of required features
Simon Sapin <simon.sapin@octobus.net>
parents: 46601
diff changeset
   490
    T: fmt::Display,
a069639783a0 rhg: Check .hg/requires for absence of required features
Simon Sapin <simon.sapin@octobus.net>
parents: 46601
diff changeset
   491
    S: fmt::Display,
a069639783a0 rhg: Check .hg/requires for absence of required features
Simon Sapin <simon.sapin@octobus.net>
parents: 46601
diff changeset
   492
{
a069639783a0 rhg: Check .hg/requires for absence of required features
Simon Sapin <simon.sapin@octobus.net>
parents: 46601
diff changeset
   493
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
a069639783a0 rhg: Check .hg/requires for absence of required features
Simon Sapin <simon.sapin@octobus.net>
parents: 46601
diff changeset
   494
        if let Some(mut iter) = self.iter.take() {
a069639783a0 rhg: Check .hg/requires for absence of required features
Simon Sapin <simon.sapin@octobus.net>
parents: 46601
diff changeset
   495
            if let Some(first) = iter.next() {
a069639783a0 rhg: Check .hg/requires for absence of required features
Simon Sapin <simon.sapin@octobus.net>
parents: 46601
diff changeset
   496
                first.fmt(f)?;
a069639783a0 rhg: Check .hg/requires for absence of required features
Simon Sapin <simon.sapin@octobus.net>
parents: 46601
diff changeset
   497
            }
a069639783a0 rhg: Check .hg/requires for absence of required features
Simon Sapin <simon.sapin@octobus.net>
parents: 46601
diff changeset
   498
            for value in iter {
a069639783a0 rhg: Check .hg/requires for absence of required features
Simon Sapin <simon.sapin@octobus.net>
parents: 46601
diff changeset
   499
                self.separator.fmt(f)?;
a069639783a0 rhg: Check .hg/requires for absence of required features
Simon Sapin <simon.sapin@octobus.net>
parents: 46601
diff changeset
   500
                value.fmt(f)?;
a069639783a0 rhg: Check .hg/requires for absence of required features
Simon Sapin <simon.sapin@octobus.net>
parents: 46601
diff changeset
   501
            }
a069639783a0 rhg: Check .hg/requires for absence of required features
Simon Sapin <simon.sapin@octobus.net>
parents: 46601
diff changeset
   502
        }
a069639783a0 rhg: Check .hg/requires for absence of required features
Simon Sapin <simon.sapin@octobus.net>
parents: 46601
diff changeset
   503
        Ok(())
a069639783a0 rhg: Check .hg/requires for absence of required features
Simon Sapin <simon.sapin@octobus.net>
parents: 46601
diff changeset
   504
    }
a069639783a0 rhg: Check .hg/requires for absence of required features
Simon Sapin <simon.sapin@octobus.net>
parents: 46601
diff changeset
   505
}