rust/hg-core/src/utils.rs
author Simon Sapin <simon.sapin@octobus.net>
Tue, 16 Feb 2021 13:08:37 +0100
changeset 46640 755c31a1caf9
parent 46625 435d9fc72646
child 46653 a069639783a0
permissions -rw-r--r--
rhg: Add support for the blackbox extension Only `command` and `commandfinish` events are logged. The `dirty`, `logsource`, `track` and `ignore` configuration items are not supported yet. To indicate commands executed without Python, a `(rust) ` prefix is added in corresponding log messages. Differential Revision: https://phab.mercurial-scm.org/D10012
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
42767
4b3b27d567d5 rust-docstrings: add missing module docstrings
Raphaël Gomès <rgomes@octobus.net>
parents: 42764
diff changeset
     1
// utils module
4b3b27d567d5 rust-docstrings: add missing module docstrings
Raphaël Gomès <rgomes@octobus.net>
parents: 42764
diff changeset
     2
//
4b3b27d567d5 rust-docstrings: add missing module docstrings
Raphaël Gomès <rgomes@octobus.net>
parents: 42764
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: 42764
diff changeset
     4
//
4b3b27d567d5 rust-docstrings: add missing module docstrings
Raphaël Gomès <rgomes@octobus.net>
parents: 42764
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: 42764
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: 42764
diff changeset
     7
4b3b27d567d5 rust-docstrings: add missing module docstrings
Raphaël Gomès <rgomes@octobus.net>
parents: 42764
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: 42764
diff changeset
     9
46513
ca3f73cc3cf4 rhg: Simplify CommandError based on its use
Simon Sapin <simon.sapin@octobus.net>
parents: 46091
diff changeset
    10
use crate::errors::{HgError, IoErrorContext};
44315
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44312
diff changeset
    11
use crate::utils::hg_path::HgPath;
46625
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
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: 46557
diff changeset
    13
use im_rc::ordmap::OrdMap;
44315
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44312
diff changeset
    14
use std::{io::Write, ops::Deref};
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44312
diff changeset
    15
42453
9609430d3625 rust-filepatterns: use bytes instead of String
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    16
pub mod files;
42959
3fe40dd6355d rust-hgpath: add HgPath and HgPathBuf structs to encapsulate handling of paths
Raphaël Gomès <rgomes@octobus.net>
parents: 42869
diff changeset
    17
pub mod hg_path;
44312
c18dd48cea4a rust-pathauditor: add Rust implementation of the `pathauditor`
Raphaël Gomès <rgomes@octobus.net>
parents: 44079
diff changeset
    18
pub mod path_auditor;
42453
9609430d3625 rust-filepatterns: use bytes instead of String
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    19
44079
191a461d6be6 rust-utils: add util to find a slice in another slice
Raphaël Gomès <rgomes@octobus.net>
parents: 42959
diff changeset
    20
/// 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: 42959
diff changeset
    21
///
191a461d6be6 rust-utils: add util to find a slice in another slice
Raphaël Gomès <rgomes@octobus.net>
parents: 42959
diff changeset
    22
/// # Examples
191a461d6be6 rust-utils: add util to find a slice in another slice
Raphaël Gomès <rgomes@octobus.net>
parents: 42959
diff changeset
    23
///
191a461d6be6 rust-utils: add util to find a slice in another slice
Raphaël Gomès <rgomes@octobus.net>
parents: 42959
diff changeset
    24
/// ```
191a461d6be6 rust-utils: add util to find a slice in another slice
Raphaël Gomès <rgomes@octobus.net>
parents: 42959
diff changeset
    25
/// 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: 42959
diff changeset
    26
///
191a461d6be6 rust-utils: add util to find a slice in another slice
Raphaël Gomès <rgomes@octobus.net>
parents: 42959
diff changeset
    27
/// 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: 42959
diff changeset
    28
/// 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: 42959
diff changeset
    29
/// 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: 42959
diff changeset
    30
/// ```
191a461d6be6 rust-utils: add util to find a slice in another slice
Raphaël Gomès <rgomes@octobus.net>
parents: 42959
diff changeset
    31
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: 42959
diff changeset
    32
where
191a461d6be6 rust-utils: add util to find a slice in another slice
Raphaël Gomès <rgomes@octobus.net>
parents: 42959
diff changeset
    33
    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: 42959
diff changeset
    34
{
191a461d6be6 rust-utils: add util to find a slice in another slice
Raphaël Gomès <rgomes@octobus.net>
parents: 42959
diff changeset
    35
    slice
191a461d6be6 rust-utils: add util to find a slice in another slice
Raphaël Gomès <rgomes@octobus.net>
parents: 42959
diff changeset
    36
        .windows(needle.len())
191a461d6be6 rust-utils: add util to find a slice in another slice
Raphaël Gomès <rgomes@octobus.net>
parents: 42959
diff changeset
    37
        .position(|window| window == needle)
191a461d6be6 rust-utils: add util to find a slice in another slice
Raphaël Gomès <rgomes@octobus.net>
parents: 42959
diff changeset
    38
}
191a461d6be6 rust-utils: add util to find a slice in another slice
Raphaël Gomès <rgomes@octobus.net>
parents: 42959
diff changeset
    39
42610
5672bb73f61e rust-utils: add docstrings and doctests for utils.rs
Raphaël Gomès <rgomes@octobus.net>
parents: 42609
diff changeset
    40
/// 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
    41
///
5672bb73f61e rust-utils: add docstrings and doctests for utils.rs
Raphaël Gomès <rgomes@octobus.net>
parents: 42609
diff changeset
    42
/// # Examples
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
/// ```
5672bb73f61e rust-utils: add docstrings and doctests for utils.rs
Raphaël Gomès <rgomes@octobus.net>
parents: 42609
diff changeset
    45
/// 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
    46
/// 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
    47
/// 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
    48
/// assert_eq!(
5672bb73f61e rust-utils: add docstrings and doctests for utils.rs
Raphaël Gomès <rgomes@octobus.net>
parents: 42609
diff changeset
    49
///     line,
5672bb73f61e rust-utils: add docstrings and doctests for utils.rs
Raphaël Gomès <rgomes@octobus.net>
parents: 42609
diff changeset
    50
///     b"I love writing tests!".to_vec()
42851
ce6797ef6eab rust: apply more formatting fixes
Yuya Nishihara <yuya@tcha.org>
parents: 42815
diff changeset
    51
/// );
42610
5672bb73f61e rust-utils: add docstrings and doctests for utils.rs
Raphaël Gomès <rgomes@octobus.net>
parents: 42609
diff changeset
    52
/// ```
42453
9609430d3625 rust-filepatterns: use bytes instead of String
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    53
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
    54
where
9609430d3625 rust-filepatterns: use bytes instead of String
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    55
    T: Clone + PartialEq,
9609430d3625 rust-filepatterns: use bytes instead of String
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    56
{
42611
2f760da140ee rust-utils: remove buggy assertion
Raphaël Gomès <rgomes@octobus.net>
parents: 42610
diff changeset
    57
    if buf.len() < from.len() || from.len() != to.len() {
42453
9609430d3625 rust-filepatterns: use bytes instead of String
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    58
        return;
9609430d3625 rust-filepatterns: use bytes instead of String
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    59
    }
9609430d3625 rust-filepatterns: use bytes instead of String
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    60
    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
    61
        if buf[i..].starts_with(from) {
9609430d3625 rust-filepatterns: use bytes instead of String
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    62
            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
    63
        }
9609430d3625 rust-filepatterns: use bytes instead of String
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    64
    }
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
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
    68
    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
    69
    fn trim_start(&self) -> &Self;
42453
9609430d3625 rust-filepatterns: use bytes instead of String
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    70
    fn trim(&self) -> &Self;
42869
62eabdf91f85 rustfilepatterns: refactor the pattern of removing a prefix from a &[u8]
Valentin Gatien-Baron <valentin.gatienbaron@gmail.com>
parents: 42851
diff changeset
    71
    fn drop_prefix(&self, needle: &Self) -> Option<&Self>;
46557
a25033eb43b5 rhg: add limited support for the `config` sub-command
Simon Sapin <simon.sapin@octobus.net>
parents: 46542
diff changeset
    72
    fn split_2(&self, separator: u8) -> Option<(&[u8], &[u8])>;
42453
9609430d3625 rust-filepatterns: use bytes instead of String
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    73
}
9609430d3625 rust-filepatterns: use bytes instead of String
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    74
44998
26114bd6ec60 rust: do a clippy pass
Raphaël Gomès <rgomes@octobus.net>
parents: 44315
diff changeset
    75
#[allow(clippy::trivially_copy_pass_by_ref)]
42453
9609430d3625 rust-filepatterns: use bytes instead of String
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    76
fn is_not_whitespace(c: &u8) -> bool {
9609430d3625 rust-filepatterns: use bytes instead of String
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    77
    !(*c as char).is_whitespace()
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
9609430d3625 rust-filepatterns: use bytes instead of String
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    80
impl SliceExt for [u8] {
9609430d3625 rust-filepatterns: use bytes instead of String
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    81
    fn trim_end(&self) -> &[u8] {
9609430d3625 rust-filepatterns: use bytes instead of String
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    82
        if let Some(last) = self.iter().rposition(is_not_whitespace) {
44998
26114bd6ec60 rust: do a clippy pass
Raphaël Gomès <rgomes@octobus.net>
parents: 44315
diff changeset
    83
            &self[..=last]
42453
9609430d3625 rust-filepatterns: use bytes instead of String
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    84
        } else {
9609430d3625 rust-filepatterns: use bytes instead of String
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    85
            &[]
9609430d3625 rust-filepatterns: use bytes instead of String
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    86
        }
9609430d3625 rust-filepatterns: use bytes instead of String
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
    87
    }
42610
5672bb73f61e rust-utils: add docstrings and doctests for utils.rs
Raphaël Gomès <rgomes@octobus.net>
parents: 42609
diff changeset
    88
    fn trim_start(&self) -> &[u8] {
5672bb73f61e rust-utils: add docstrings and doctests for utils.rs
Raphaël Gomès <rgomes@octobus.net>
parents: 42609
diff changeset
    89
        if let Some(first) = self.iter().position(is_not_whitespace) {
5672bb73f61e rust-utils: add docstrings and doctests for utils.rs
Raphaël Gomès <rgomes@octobus.net>
parents: 42609
diff changeset
    90
            &self[first..]
5672bb73f61e rust-utils: add docstrings and doctests for utils.rs
Raphaël Gomès <rgomes@octobus.net>
parents: 42609
diff changeset
    91
        } else {
5672bb73f61e rust-utils: add docstrings and doctests for utils.rs
Raphaël Gomès <rgomes@octobus.net>
parents: 42609
diff changeset
    92
            &[]
5672bb73f61e rust-utils: add docstrings and doctests for utils.rs
Raphaël Gomès <rgomes@octobus.net>
parents: 42609
diff changeset
    93
        }
5672bb73f61e rust-utils: add docstrings and doctests for utils.rs
Raphaël Gomès <rgomes@octobus.net>
parents: 42609
diff changeset
    94
    }
5672bb73f61e rust-utils: add docstrings and doctests for utils.rs
Raphaël Gomès <rgomes@octobus.net>
parents: 42609
diff changeset
    95
5672bb73f61e rust-utils: add docstrings and doctests for utils.rs
Raphaël Gomès <rgomes@octobus.net>
parents: 42609
diff changeset
    96
    /// ```
5672bb73f61e rust-utils: add docstrings and doctests for utils.rs
Raphaël Gomès <rgomes@octobus.net>
parents: 42609
diff changeset
    97
    /// 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
    98
    /// assert_eq!(
5672bb73f61e rust-utils: add docstrings and doctests for utils.rs
Raphaël Gomès <rgomes@octobus.net>
parents: 42609
diff changeset
    99
    ///     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
   100
    ///     b"to trim"
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
    /// assert_eq!(
5672bb73f61e rust-utils: add docstrings and doctests for utils.rs
Raphaël Gomès <rgomes@octobus.net>
parents: 42609
diff changeset
   103
    ///     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
   104
    ///     b"to trim"
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
    /// assert_eq!(
5672bb73f61e rust-utils: add docstrings and doctests for utils.rs
Raphaël Gomès <rgomes@octobus.net>
parents: 42609
diff changeset
   107
    ///     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
   108
    ///     b"to trim"
5672bb73f61e rust-utils: add docstrings and doctests for utils.rs
Raphaël Gomès <rgomes@octobus.net>
parents: 42609
diff changeset
   109
    /// );
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
    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
   112
        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
   113
    }
42869
62eabdf91f85 rustfilepatterns: refactor the pattern of removing a prefix from a &[u8]
Valentin Gatien-Baron <valentin.gatienbaron@gmail.com>
parents: 42851
diff changeset
   114
62eabdf91f85 rustfilepatterns: refactor the pattern of removing a prefix from a &[u8]
Valentin Gatien-Baron <valentin.gatienbaron@gmail.com>
parents: 42851
diff changeset
   115
    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: 42851
diff changeset
   116
        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: 42851
diff changeset
   117
            Some(&self[needle.len()..])
62eabdf91f85 rustfilepatterns: refactor the pattern of removing a prefix from a &[u8]
Valentin Gatien-Baron <valentin.gatienbaron@gmail.com>
parents: 42851
diff changeset
   118
        } else {
62eabdf91f85 rustfilepatterns: refactor the pattern of removing a prefix from a &[u8]
Valentin Gatien-Baron <valentin.gatienbaron@gmail.com>
parents: 42851
diff changeset
   119
            None
62eabdf91f85 rustfilepatterns: refactor the pattern of removing a prefix from a &[u8]
Valentin Gatien-Baron <valentin.gatienbaron@gmail.com>
parents: 42851
diff changeset
   120
        }
62eabdf91f85 rustfilepatterns: refactor the pattern of removing a prefix from a &[u8]
Valentin Gatien-Baron <valentin.gatienbaron@gmail.com>
parents: 42851
diff changeset
   121
    }
46557
a25033eb43b5 rhg: add limited support for the `config` sub-command
Simon Sapin <simon.sapin@octobus.net>
parents: 46542
diff changeset
   122
a25033eb43b5 rhg: add limited support for the `config` sub-command
Simon Sapin <simon.sapin@octobus.net>
parents: 46542
diff changeset
   123
    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: 46542
diff changeset
   124
        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: 46542
diff changeset
   125
        let a = iter.next()?;
a25033eb43b5 rhg: add limited support for the `config` sub-command
Simon Sapin <simon.sapin@octobus.net>
parents: 46542
diff changeset
   126
        let b = iter.next()?;
a25033eb43b5 rhg: add limited support for the `config` sub-command
Simon Sapin <simon.sapin@octobus.net>
parents: 46542
diff changeset
   127
        Some((a, b))
a25033eb43b5 rhg: add limited support for the `config` sub-command
Simon Sapin <simon.sapin@octobus.net>
parents: 46542
diff changeset
   128
    }
42453
9609430d3625 rust-filepatterns: use bytes instead of String
Raphaël Gomès <rgomes@octobus.net>
parents:
diff changeset
   129
}
44315
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44312
diff changeset
   130
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44312
diff changeset
   131
pub trait Escaped {
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44312
diff changeset
   132
    /// Return bytes escaped for display to the user
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44312
diff changeset
   133
    fn escaped_bytes(&self) -> Vec<u8>;
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44312
diff changeset
   134
}
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44312
diff changeset
   135
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44312
diff changeset
   136
impl Escaped for u8 {
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44312
diff changeset
   137
    fn escaped_bytes(&self) -> Vec<u8> {
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44312
diff changeset
   138
        let mut acc = vec![];
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44312
diff changeset
   139
        match self {
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44312
diff changeset
   140
            c @ b'\'' | c @ b'\\' => {
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44312
diff changeset
   141
                acc.push(b'\\');
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44312
diff changeset
   142
                acc.push(*c);
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44312
diff changeset
   143
            }
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44312
diff changeset
   144
            b'\t' => {
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44312
diff changeset
   145
                acc.extend(br"\\t");
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44312
diff changeset
   146
            }
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44312
diff changeset
   147
            b'\n' => {
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44312
diff changeset
   148
                acc.extend(br"\\n");
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44312
diff changeset
   149
            }
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44312
diff changeset
   150
            b'\r' => {
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44312
diff changeset
   151
                acc.extend(br"\\r");
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44312
diff changeset
   152
            }
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44312
diff changeset
   153
            c if (*c < b' ' || *c >= 127) => {
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44312
diff changeset
   154
                write!(acc, "\\x{:x}", self).unwrap();
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44312
diff changeset
   155
            }
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44312
diff changeset
   156
            c => {
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44312
diff changeset
   157
                acc.push(*c);
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44312
diff changeset
   158
            }
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44312
diff changeset
   159
        }
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44312
diff changeset
   160
        acc
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44312
diff changeset
   161
    }
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44312
diff changeset
   162
}
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44312
diff changeset
   163
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44312
diff changeset
   164
impl<'a, T: Escaped> Escaped for &'a [T] {
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44312
diff changeset
   165
    fn escaped_bytes(&self) -> Vec<u8> {
44998
26114bd6ec60 rust: do a clippy pass
Raphaël Gomès <rgomes@octobus.net>
parents: 44315
diff changeset
   166
        self.iter().flat_map(Escaped::escaped_bytes).collect()
44315
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44312
diff changeset
   167
    }
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44312
diff changeset
   168
}
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44312
diff changeset
   169
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44312
diff changeset
   170
impl<T: Escaped> Escaped for Vec<T> {
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44312
diff changeset
   171
    fn escaped_bytes(&self) -> Vec<u8> {
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44312
diff changeset
   172
        self.deref().escaped_bytes()
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44312
diff changeset
   173
    }
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44312
diff changeset
   174
}
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44312
diff changeset
   175
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44312
diff changeset
   176
impl<'a> Escaped for &'a HgPath {
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44312
diff changeset
   177
    fn escaped_bytes(&self) -> Vec<u8> {
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44312
diff changeset
   178
        self.as_bytes().escaped_bytes()
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44312
diff changeset
   179
    }
aa0fc32ece9e rust-utils: add `Escaped` trait
Raphaël Gomès <rgomes@octobus.net>
parents: 44312
diff changeset
   180
}
46091
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents: 44998
diff changeset
   181
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents: 44998
diff changeset
   182
// 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: 44998
diff changeset
   183
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: 44998
diff changeset
   184
    if s.ends_with(suffix) {
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents: 44998
diff changeset
   185
        Some(&s[..s.len() - suffix.len()])
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents: 44998
diff changeset
   186
    } else {
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents: 44998
diff changeset
   187
        None
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents: 44998
diff changeset
   188
    }
9eb07ab3f2d4 rhg: use persistent nodemap when available
Simon Sapin <simon-commits@exyr.org>
parents: 44998
diff changeset
   189
}
46513
ca3f73cc3cf4 rhg: Simplify CommandError based on its use
Simon Sapin <simon.sapin@octobus.net>
parents: 46091
diff changeset
   190
46640
755c31a1caf9 rhg: Add support for the blackbox extension
Simon Sapin <simon.sapin@octobus.net>
parents: 46625
diff changeset
   191
#[cfg(unix)]
755c31a1caf9 rhg: Add support for the blackbox extension
Simon Sapin <simon.sapin@octobus.net>
parents: 46625
diff changeset
   192
pub fn shell_quote(value: &[u8]) -> Vec<u8> {
755c31a1caf9 rhg: Add support for the blackbox extension
Simon Sapin <simon.sapin@octobus.net>
parents: 46625
diff changeset
   193
    // 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: 46625
diff changeset
   194
    if value.iter().all(|&byte| match byte {
755c31a1caf9 rhg: Add support for the blackbox extension
Simon Sapin <simon.sapin@octobus.net>
parents: 46625
diff changeset
   195
        b'a'..=b'z'
755c31a1caf9 rhg: Add support for the blackbox extension
Simon Sapin <simon.sapin@octobus.net>
parents: 46625
diff changeset
   196
        | b'A'..=b'Z'
755c31a1caf9 rhg: Add support for the blackbox extension
Simon Sapin <simon.sapin@octobus.net>
parents: 46625
diff changeset
   197
        | b'0'..=b'9'
755c31a1caf9 rhg: Add support for the blackbox extension
Simon Sapin <simon.sapin@octobus.net>
parents: 46625
diff changeset
   198
        | b'.'
755c31a1caf9 rhg: Add support for the blackbox extension
Simon Sapin <simon.sapin@octobus.net>
parents: 46625
diff changeset
   199
        | b'_'
755c31a1caf9 rhg: Add support for the blackbox extension
Simon Sapin <simon.sapin@octobus.net>
parents: 46625
diff changeset
   200
        | b'/'
755c31a1caf9 rhg: Add support for the blackbox extension
Simon Sapin <simon.sapin@octobus.net>
parents: 46625
diff changeset
   201
        | b'+'
755c31a1caf9 rhg: Add support for the blackbox extension
Simon Sapin <simon.sapin@octobus.net>
parents: 46625
diff changeset
   202
        | b'-' => true,
755c31a1caf9 rhg: Add support for the blackbox extension
Simon Sapin <simon.sapin@octobus.net>
parents: 46625
diff changeset
   203
        _ => false,
755c31a1caf9 rhg: Add support for the blackbox extension
Simon Sapin <simon.sapin@octobus.net>
parents: 46625
diff changeset
   204
    }) {
755c31a1caf9 rhg: Add support for the blackbox extension
Simon Sapin <simon.sapin@octobus.net>
parents: 46625
diff changeset
   205
        value.to_owned()
755c31a1caf9 rhg: Add support for the blackbox extension
Simon Sapin <simon.sapin@octobus.net>
parents: 46625
diff changeset
   206
    } else {
755c31a1caf9 rhg: Add support for the blackbox extension
Simon Sapin <simon.sapin@octobus.net>
parents: 46625
diff changeset
   207
        let mut quoted = Vec::with_capacity(value.len() + 2);
755c31a1caf9 rhg: Add support for the blackbox extension
Simon Sapin <simon.sapin@octobus.net>
parents: 46625
diff changeset
   208
        quoted.push(b'\'');
755c31a1caf9 rhg: Add support for the blackbox extension
Simon Sapin <simon.sapin@octobus.net>
parents: 46625
diff changeset
   209
        for &byte in value {
755c31a1caf9 rhg: Add support for the blackbox extension
Simon Sapin <simon.sapin@octobus.net>
parents: 46625
diff changeset
   210
            if byte == b'\'' {
755c31a1caf9 rhg: Add support for the blackbox extension
Simon Sapin <simon.sapin@octobus.net>
parents: 46625
diff changeset
   211
                quoted.push(b'\\');
755c31a1caf9 rhg: Add support for the blackbox extension
Simon Sapin <simon.sapin@octobus.net>
parents: 46625
diff changeset
   212
            }
755c31a1caf9 rhg: Add support for the blackbox extension
Simon Sapin <simon.sapin@octobus.net>
parents: 46625
diff changeset
   213
            quoted.push(byte);
755c31a1caf9 rhg: Add support for the blackbox extension
Simon Sapin <simon.sapin@octobus.net>
parents: 46625
diff changeset
   214
        }
755c31a1caf9 rhg: Add support for the blackbox extension
Simon Sapin <simon.sapin@octobus.net>
parents: 46625
diff changeset
   215
        quoted.push(b'\'');
755c31a1caf9 rhg: Add support for the blackbox extension
Simon Sapin <simon.sapin@octobus.net>
parents: 46625
diff changeset
   216
        quoted
755c31a1caf9 rhg: Add support for the blackbox extension
Simon Sapin <simon.sapin@octobus.net>
parents: 46625
diff changeset
   217
    }
755c31a1caf9 rhg: Add support for the blackbox extension
Simon Sapin <simon.sapin@octobus.net>
parents: 46625
diff changeset
   218
}
755c31a1caf9 rhg: Add support for the blackbox extension
Simon Sapin <simon.sapin@octobus.net>
parents: 46625
diff changeset
   219
46513
ca3f73cc3cf4 rhg: Simplify CommandError based on its use
Simon Sapin <simon.sapin@octobus.net>
parents: 46091
diff changeset
   220
pub fn current_dir() -> Result<std::path::PathBuf, HgError> {
ca3f73cc3cf4 rhg: Simplify CommandError based on its use
Simon Sapin <simon.sapin@octobus.net>
parents: 46091
diff changeset
   221
    std::env::current_dir().map_err(|error| HgError::IoError {
ca3f73cc3cf4 rhg: Simplify CommandError based on its use
Simon Sapin <simon.sapin@octobus.net>
parents: 46091
diff changeset
   222
        error,
ca3f73cc3cf4 rhg: Simplify CommandError based on its use
Simon Sapin <simon.sapin@octobus.net>
parents: 46091
diff changeset
   223
        context: IoErrorContext::CurrentDir,
ca3f73cc3cf4 rhg: Simplify CommandError based on its use
Simon Sapin <simon.sapin@octobus.net>
parents: 46091
diff changeset
   224
    })
ca3f73cc3cf4 rhg: Simplify CommandError based on its use
Simon Sapin <simon.sapin@octobus.net>
parents: 46091
diff changeset
   225
}
46542
2845892dd489 rust: Parse system and user configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46513
diff changeset
   226
2845892dd489 rust: Parse system and user configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46513
diff changeset
   227
pub fn current_exe() -> Result<std::path::PathBuf, HgError> {
2845892dd489 rust: Parse system and user configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46513
diff changeset
   228
    std::env::current_exe().map_err(|error| HgError::IoError {
2845892dd489 rust: Parse system and user configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46513
diff changeset
   229
        error,
2845892dd489 rust: Parse system and user configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46513
diff changeset
   230
        context: IoErrorContext::CurrentExe,
2845892dd489 rust: Parse system and user configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46513
diff changeset
   231
    })
2845892dd489 rust: Parse system and user configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46513
diff changeset
   232
}
46625
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   233
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   234
pub(crate) enum MergeResult<V> {
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   235
    UseLeftValue,
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   236
    UseRightValue,
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   237
    UseNewValue(V),
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   238
}
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   239
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   240
/// 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: 46557
diff changeset
   241
/// 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: 46557
diff changeset
   242
/// both.
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   243
///
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   244
/// 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: 46557
diff changeset
   245
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: 46557
diff changeset
   246
    left: OrdMap<K, V>,
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   247
    right: OrdMap<K, V>,
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   248
    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: 46557
diff changeset
   249
) -> OrdMap<K, V>
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   250
where
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   251
    K: Clone + Ord,
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   252
    V: Clone + PartialEq,
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   253
{
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   254
    if left.ptr_eq(&right) {
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   255
        // 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: 46557
diff changeset
   256
        left
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   257
    } 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: 46557
diff changeset
   258
        // 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: 46557
diff changeset
   259
        // 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: 46557
diff changeset
   260
        // 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: 46557
diff changeset
   261
        // 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: 46557
diff changeset
   262
        // `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: 46557
diff changeset
   263
        // 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: 46557
diff changeset
   264
        //
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   265
        // 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: 46557
diff changeset
   266
        // 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: 46557
diff changeset
   267
        // `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: 46557
diff changeset
   268
        // is more efficient.
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   269
        //
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   270
        // 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: 46557
diff changeset
   271
        // with a large one.
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   272
        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: 46557
diff changeset
   273
    } 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: 46557
diff changeset
   274
        // 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: 46557
diff changeset
   275
        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: 46557
diff changeset
   276
            // Also swapped in `merge` arguments:
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   277
            match merge(key, b, a) {
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   278
                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: 46557
diff changeset
   279
                // … 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: 46557
diff changeset
   280
                MergeResult::UseLeftValue => MergeResult::UseRightValue,
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   281
                MergeResult::UseRightValue => MergeResult::UseLeftValue,
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   282
            }
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   283
        })
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   284
    } else {
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   285
        // 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: 46557
diff changeset
   286
        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: 46557
diff changeset
   287
    }
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   288
}
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   289
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   290
/// 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: 46557
diff changeset
   291
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: 46557
diff changeset
   292
    mut left: OrdMap<K, V>,
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   293
    right: OrdMap<K, V>,
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   294
    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: 46557
diff changeset
   295
) -> OrdMap<K, V>
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   296
where
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   297
    K: Clone + Ord,
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   298
    V: Clone,
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   299
{
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   300
    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: 46557
diff changeset
   301
        match left.get(&key) {
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   302
            None => {
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   303
                left.insert(key, right_value);
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   304
            }
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   305
            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: 46557
diff changeset
   306
                MergeResult::UseLeftValue => {}
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   307
                MergeResult::UseRightValue => {
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   308
                    left.insert(key, right_value);
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   309
                }
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   310
                MergeResult::UseNewValue(new_value) => {
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   311
                    left.insert(key, new_value);
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   312
                }
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   313
            },
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   314
        }
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   315
    }
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   316
    left
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   317
}
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   318
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   319
/// 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: 46557
diff changeset
   320
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: 46557
diff changeset
   321
    mut left: OrdMap<K, V>,
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   322
    mut right: OrdMap<K, V>,
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   323
    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: 46557
diff changeset
   324
) -> OrdMap<K, V>
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   325
where
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   326
    K: Clone + Ord,
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   327
    V: Clone + PartialEq,
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   328
{
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   329
    // (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: 46557
diff changeset
   330
    // 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: 46557
diff changeset
   331
    //
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   332
    // 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: 46557
diff changeset
   333
    // 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: 46557
diff changeset
   334
    // 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: 46557
diff changeset
   335
    // `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: 46557
diff changeset
   336
    //
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   337
    // 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: 46557
diff changeset
   338
    // 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: 46557
diff changeset
   339
    // (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: 46557
diff changeset
   340
    // 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: 46557
diff changeset
   341
    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: 46557
diff changeset
   342
    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: 46557
diff changeset
   343
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   344
    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: 46557
diff changeset
   345
        match difference {
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   346
            DiffItem::Add(key, value) => {
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   347
                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: 46557
diff changeset
   348
            }
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   349
            DiffItem::Remove(key, value) => {
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   350
                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: 46557
diff changeset
   351
            }
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   352
            DiffItem::Update {
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   353
                old: (key, left_value),
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   354
                new: (_, right_value),
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   355
            } => 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: 46557
diff changeset
   356
                MergeResult::UseLeftValue => {
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   357
                    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: 46557
diff changeset
   358
                }
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   359
                MergeResult::UseRightValue => {
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   360
                    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: 46557
diff changeset
   361
                }
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   362
                MergeResult::UseNewValue(new_value) => {
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   363
                    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: 46557
diff changeset
   364
                    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: 46557
diff changeset
   365
                }
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   366
            },
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   367
        }
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   368
    }
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   369
    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: 46557
diff changeset
   370
        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: 46557
diff changeset
   371
            left.insert(key, value);
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   372
        }
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   373
        left
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   374
    } else {
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   375
        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: 46557
diff changeset
   376
            right.insert(key, value);
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   377
        }
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   378
        right
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   379
    }
435d9fc72646 copies-rust: extract generic map merge logic from merge_copies_dict
Simon Sapin <simon.sapin@octobus.net>
parents: 46557
diff changeset
   380
}