##// END OF EJS Templates
rust-index: optimize find_gca_candidates() on less than 8 revisions...
rust-index: optimize find_gca_candidates() on less than 8 revisions This is expected to be by far the most common case, given that, e.g., merging involves using it on two revisions. Using a `u8` as support for the bitset obviously divides the amount of RAM needed by 8. To state the obvious, on a repository with 10 million changesets, this spares 70MB. It is also possible that it'd be slightly faster, because it is easier to allocate and provides better cache locality. It is possible that some exhaustive listing of the traits implemented by `u8` and `u64` would avoid the added duplication, but that can be done later and would need a replacement for the `MAX` consts.

File last commit:

r51264:3f513754 stable
r52122:1b23aaf5 default
Show More
path_encode.rs
639 lines | 18.5 KiB | application/rls-services+xml | RustLexer
Simon Sapin
rust: Use a maintained crate for SHA-1 hashing...
r48171 use sha1::{Digest, Sha1};
Antoine Cezar
hg-core: add path_encode...
r46110
#[derive(PartialEq, Debug)]
#[allow(non_camel_case_types)]
Raphaël Gomès
rust-clippy: fix most warnings in `hg-core`...
r50825 #[allow(clippy::upper_case_acronyms)]
Antoine Cezar
hg-core: add path_encode...
r46110 enum path_state {
START, /* first byte of a path component */
A, /* "AUX" */
AU,
THIRD, /* third of a 3-byte sequence, e.g. "AUX", "NUL" */
C, /* "CON" or "COMn" */
CO,
COMLPT, /* "COM" or "LPT" */
COMLPTn,
L,
LP,
N,
NU,
P, /* "PRN" */
PR,
LDOT, /* leading '.' */
DOT, /* '.' in a non-leading position */
H, /* ".h" */
HGDI, /* ".hg", ".d", or ".i" */
SPACE,
DEFAULT, /* byte of a path component after the first */
}
/* state machine for dir-encoding */
#[allow(non_camel_case_types)]
Raphaël Gomès
rust-clippy: fix most warnings in `hg-core`...
r50825 #[allow(clippy::upper_case_acronyms)]
Antoine Cezar
hg-core: add path_encode...
r46110 enum dir_state {
DDOT,
DH,
DHGDI,
DDEFAULT,
}
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 trait Sink {
fn write_byte(&mut self, c: u8);
fn write_bytes(&mut self, c: &[u8]);
}
Antoine Cezar
hg-core: add path_encode...
r46110 fn inset(bitset: &[u32; 8], c: u8) -> bool {
bitset[(c as usize) >> 5] & (1 << (c & 31)) != 0
}
Arseniy Alekseyev
rhg: in path_encode add a DestArr type...
r51055 const MAXENCODE: usize = 4096 * 4;
Arseniy Alekseyev
rhg: in path_encode, make DestArr generic over its size
r51056 struct DestArr<const N: usize> {
buf: [u8; N],
Arseniy Alekseyev
rhg: in path_encode add a DestArr type...
r51055 pub len: usize,
}
Arseniy Alekseyev
rhg: in path_encode, make DestArr generic over its size
r51056 impl<const N: usize> DestArr<N> {
Arseniy Alekseyev
rhg: in path_encode add a DestArr type...
r51055 pub fn create() -> Self {
DestArr {
Arseniy Alekseyev
rhg: in path_encode, make DestArr generic over its size
r51056 buf: [0; N],
Arseniy Alekseyev
rhg: in path_encode add a DestArr type...
r51055 len: 0,
}
}
pub fn contents(&self) -> &[u8] {
&self.buf[..self.len]
}
}
Arseniy Alekseyev
rhg: in path_encode, make DestArr generic over its size
r51056 impl<const N: usize> Sink for DestArr<N> {
Arseniy Alekseyev
rhg: in path_encode add a DestArr type...
r51055 fn write_byte(&mut self, c: u8) {
self.buf[self.len] = c;
self.len += 1;
}
fn write_bytes(&mut self, src: &[u8]) {
self.buf[self.len..self.len + src.len()].copy_from_slice(src);
self.len += src.len();
}
}
Arseniy Alekseyev
rhg: in path_encode, split Dest into VecDest and MeasureDest...
r51058 struct MeasureDest {
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 pub len: usize,
Antoine Cezar
hg-core: add path_encode...
r46110 }
Arseniy Alekseyev
rhg: in path_encode, use Vec directly instead of VecDest...
r51059 impl Sink for Vec<u8> {
Arseniy Alekseyev
rhg: in path_encode, split Dest into VecDest and MeasureDest...
r51058 fn write_byte(&mut self, c: u8) {
Arseniy Alekseyev
rhg: in path_encode, use Vec directly instead of VecDest...
r51059 self.push(c)
Arseniy Alekseyev
rhg: in path_encode, split Dest into VecDest and MeasureDest...
r51058 }
fn write_bytes(&mut self, src: &[u8]) {
Arseniy Alekseyev
rhg: in path_encode, use Vec directly instead of VecDest...
r51059 self.extend_from_slice(src)
Antoine Cezar
hg-core: add path_encode...
r46110 }
}
Arseniy Alekseyev
rhg: in path_encode, split Dest into VecDest and MeasureDest...
r51058 impl MeasureDest {
fn create() -> Self {
Self { len: 0 }
}
}
impl Sink for MeasureDest {
fn write_byte(&mut self, _c: u8) {
self.len += 1;
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 }
fn write_bytes(&mut self, src: &[u8]) {
self.len += src.len();
}
}
fn hexencode(dest: &mut impl Sink, c: u8) {
Antoine Cezar
hg-core: add path_encode...
r46110 let hexdigit = b"0123456789abcdef";
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(hexdigit[(c as usize) >> 4]);
dest.write_byte(hexdigit[(c as usize) & 15]);
Antoine Cezar
hg-core: add path_encode...
r46110 }
/* 3-byte escape: tilde followed by two hex digits */
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 fn escape3(dest: &mut impl Sink, c: u8) {
dest.write_byte(b'~');
hexencode(dest, c);
Antoine Cezar
hg-core: add path_encode...
r46110 }
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 fn encode_dir(dest: &mut impl Sink, src: &[u8]) {
Antoine Cezar
hg-core: add path_encode...
r46110 let mut state = dir_state::DDEFAULT;
let mut i = 0;
while i < src.len() {
match state {
dir_state::DDOT => match src[i] {
b'd' | b'i' => {
state = dir_state::DHGDI;
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(src[i]);
Antoine Cezar
hg-core: add path_encode...
r46110 i += 1;
}
b'h' => {
state = dir_state::DH;
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(src[i]);
Antoine Cezar
hg-core: add path_encode...
r46110 i += 1;
}
_ => {
state = dir_state::DDEFAULT;
}
},
dir_state::DH => {
if src[i] == b'g' {
state = dir_state::DHGDI;
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(src[i]);
Antoine Cezar
hg-core: add path_encode...
r46110 i += 1;
} else {
state = dir_state::DDEFAULT;
}
}
dir_state::DHGDI => {
if src[i] == b'/' {
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_bytes(b".hg");
dest.write_byte(src[i]);
Antoine Cezar
hg-core: add path_encode...
r46110 i += 1;
}
state = dir_state::DDEFAULT;
}
dir_state::DDEFAULT => {
if src[i] == b'.' {
state = dir_state::DDOT
}
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(src[i]);
Antoine Cezar
hg-core: add path_encode...
r46110 i += 1;
}
}
}
}
fn _encode(
twobytes: &[u32; 8],
onebyte: &[u32; 8],
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest: &mut impl Sink,
Antoine Cezar
hg-core: add path_encode...
r46110 src: &[u8],
encodedir: bool,
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 ) {
Antoine Cezar
hg-core: add path_encode...
r46110 let mut state = path_state::START;
let mut i = 0;
let len = src.len();
while i < len {
match state {
path_state::START => match src[i] {
b'/' => {
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(src[i]);
Antoine Cezar
hg-core: add path_encode...
r46110 i += 1;
}
b'.' => {
state = path_state::LDOT;
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 escape3(dest, src[i]);
Antoine Cezar
hg-core: add path_encode...
r46110 i += 1;
}
b' ' => {
state = path_state::DEFAULT;
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 escape3(dest, src[i]);
Antoine Cezar
hg-core: add path_encode...
r46110 i += 1;
}
b'a' => {
state = path_state::A;
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(src[i]);
Antoine Cezar
hg-core: add path_encode...
r46110 i += 1;
}
b'c' => {
state = path_state::C;
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(src[i]);
Antoine Cezar
hg-core: add path_encode...
r46110 i += 1;
}
b'l' => {
state = path_state::L;
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(src[i]);
Antoine Cezar
hg-core: add path_encode...
r46110 i += 1;
}
b'n' => {
state = path_state::N;
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(src[i]);
Antoine Cezar
hg-core: add path_encode...
r46110 i += 1;
}
b'p' => {
state = path_state::P;
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(src[i]);
Antoine Cezar
hg-core: add path_encode...
r46110 i += 1;
}
_ => {
state = path_state::DEFAULT;
}
},
path_state::A => {
if src[i] == b'u' {
state = path_state::AU;
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(src[i]);
Antoine Cezar
hg-core: add path_encode...
r46110 i += 1;
} else {
state = path_state::DEFAULT;
}
}
path_state::AU => {
if src[i] == b'x' {
state = path_state::THIRD;
i += 1;
} else {
state = path_state::DEFAULT;
}
}
path_state::THIRD => {
state = path_state::DEFAULT;
match src[i] {
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 b'.' | b'/' | b'\0' => escape3(dest, src[i - 1]),
Antoine Cezar
hg-core: add path_encode...
r46110 _ => i -= 1,
}
}
path_state::C => {
if src[i] == b'o' {
state = path_state::CO;
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(src[i]);
Antoine Cezar
hg-core: add path_encode...
r46110 i += 1;
} else {
state = path_state::DEFAULT;
}
}
path_state::CO => {
if src[i] == b'm' {
state = path_state::COMLPT;
i += 1;
} else if src[i] == b'n' {
state = path_state::THIRD;
i += 1;
} else {
state = path_state::DEFAULT;
}
}
path_state::COMLPT => {
if src[i] >= b'1' && src[i] <= b'9' {
state = path_state::COMLPTn;
i += 1;
} else {
state = path_state::DEFAULT;
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(src[i - 1]);
Antoine Cezar
hg-core: add path_encode...
r46110 }
}
path_state::COMLPTn => {
state = path_state::DEFAULT;
match src[i] {
b'.' | b'/' | b'\0' => {
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 escape3(dest, src[i - 2]);
dest.write_byte(src[i - 1]);
Antoine Cezar
hg-core: add path_encode...
r46110 }
_ => {
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_bytes(&src[i - 2..i]);
Antoine Cezar
hg-core: add path_encode...
r46110 }
}
}
path_state::L => {
if src[i] == b'p' {
state = path_state::LP;
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(src[i]);
Antoine Cezar
hg-core: add path_encode...
r46110 i += 1;
} else {
state = path_state::DEFAULT;
}
}
path_state::LP => {
if src[i] == b't' {
state = path_state::COMLPT;
i += 1;
} else {
state = path_state::DEFAULT;
}
}
path_state::N => {
if src[i] == b'u' {
state = path_state::NU;
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(src[i]);
Antoine Cezar
hg-core: add path_encode...
r46110 i += 1;
} else {
state = path_state::DEFAULT;
}
}
path_state::NU => {
if src[i] == b'l' {
state = path_state::THIRD;
i += 1;
} else {
state = path_state::DEFAULT;
}
}
path_state::P => {
if src[i] == b'r' {
state = path_state::PR;
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(src[i]);
Antoine Cezar
hg-core: add path_encode...
r46110 i += 1;
} else {
state = path_state::DEFAULT;
}
}
path_state::PR => {
if src[i] == b'n' {
state = path_state::THIRD;
i += 1;
} else {
state = path_state::DEFAULT;
}
}
path_state::LDOT => match src[i] {
b'd' | b'i' => {
state = path_state::HGDI;
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(src[i]);
Antoine Cezar
hg-core: add path_encode...
r46110 i += 1;
}
b'h' => {
state = path_state::H;
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(src[i]);
Antoine Cezar
hg-core: add path_encode...
r46110 i += 1;
}
_ => {
state = path_state::DEFAULT;
}
},
path_state::DOT => match src[i] {
b'/' | b'\0' => {
state = path_state::START;
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_bytes(b"~2e");
dest.write_byte(src[i]);
Antoine Cezar
hg-core: add path_encode...
r46110 i += 1;
}
b'd' | b'i' => {
state = path_state::HGDI;
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(b'.');
dest.write_byte(src[i]);
Antoine Cezar
hg-core: add path_encode...
r46110 i += 1;
}
b'h' => {
state = path_state::H;
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_bytes(b".h");
Antoine Cezar
hg-core: add path_encode...
r46110 i += 1;
}
_ => {
state = path_state::DEFAULT;
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(b'.');
Antoine Cezar
hg-core: add path_encode...
r46110 }
},
path_state::H => {
if src[i] == b'g' {
state = path_state::HGDI;
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(src[i]);
Antoine Cezar
hg-core: add path_encode...
r46110 i += 1;
} else {
state = path_state::DEFAULT;
}
}
path_state::HGDI => {
if src[i] == b'/' {
state = path_state::START;
if encodedir {
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_bytes(b".hg");
Antoine Cezar
hg-core: add path_encode...
r46110 }
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(src[i]);
Antoine Cezar
hg-core: add path_encode...
r46110 i += 1
} else {
state = path_state::DEFAULT;
}
}
path_state::SPACE => match src[i] {
b'/' | b'\0' => {
state = path_state::START;
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_bytes(b"~20");
dest.write_byte(src[i]);
Antoine Cezar
hg-core: add path_encode...
r46110 i += 1;
}
_ => {
state = path_state::DEFAULT;
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(b' ');
Antoine Cezar
hg-core: add path_encode...
r46110 }
},
path_state::DEFAULT => {
while i != len && inset(onebyte, src[i]) {
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(src[i]);
Antoine Cezar
hg-core: add path_encode...
r46110 i += 1;
}
if i == len {
break;
}
match src[i] {
b'.' => {
state = path_state::DOT;
i += 1
}
b' ' => {
state = path_state::SPACE;
i += 1
}
b'/' => {
state = path_state::START;
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(b'/');
Antoine Cezar
hg-core: add path_encode...
r46110 i += 1;
}
_ => {
if inset(onebyte, src[i]) {
loop {
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(src[i]);
Antoine Cezar
hg-core: add path_encode...
r46110 i += 1;
if !(i < len && inset(onebyte, src[i])) {
break;
}
}
} else if inset(twobytes, src[i]) {
let c = src[i];
i += 1;
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(b'_');
dest.write_byte(if c == b'_' {
b'_'
} else {
c + 32
});
Antoine Cezar
hg-core: add path_encode...
r46110 } else {
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 escape3(dest, src[i]);
Antoine Cezar
hg-core: add path_encode...
r46110 i += 1;
}
}
}
}
}
}
match state {
path_state::START => (),
path_state::A => (),
path_state::AU => (),
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 path_state::THIRD => escape3(dest, src[i - 1]),
Antoine Cezar
hg-core: add path_encode...
r46110 path_state::C => (),
path_state::CO => (),
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 path_state::COMLPT => dest.write_byte(src[i - 1]),
Antoine Cezar
hg-core: add path_encode...
r46110 path_state::COMLPTn => {
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 escape3(dest, src[i - 2]);
dest.write_byte(src[i - 1]);
Antoine Cezar
hg-core: add path_encode...
r46110 }
path_state::L => (),
path_state::LP => (),
path_state::N => (),
path_state::NU => (),
path_state::P => (),
path_state::PR => (),
path_state::LDOT => (),
path_state::DOT => {
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_bytes(b"~2e");
Antoine Cezar
hg-core: add path_encode...
r46110 }
path_state::H => (),
path_state::HGDI => (),
path_state::SPACE => {
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_bytes(b"~20");
Antoine Cezar
hg-core: add path_encode...
r46110 }
path_state::DEFAULT => (),
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 }
Antoine Cezar
hg-core: add path_encode...
r46110 }
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 fn basic_encode(dest: &mut impl Sink, src: &[u8]) {
Antoine Cezar
hg-core: add path_encode...
r46110 let twobytes: [u32; 8] = [0, 0, 0x87ff_fffe, 0, 0, 0, 0, 0];
let onebyte: [u32; 8] =
[1, 0x2bff_3bfa, 0x6800_0001, 0x2fff_ffff, 0, 0, 0, 0];
_encode(&twobytes, &onebyte, dest, src, true)
}
const MAXSTOREPATHLEN: usize = 120;
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 fn lower_encode(dest: &mut impl Sink, src: &[u8]) {
Antoine Cezar
hg-core: add path_encode...
r46110 let onebyte: [u32; 8] =
[1, 0x2bff_fbfb, 0xe800_0001, 0x2fff_ffff, 0, 0, 0, 0];
let lower: [u32; 8] = [0, 0, 0x07ff_fffe, 0, 0, 0, 0, 0];
for c in src {
if inset(&onebyte, *c) {
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(*c)
Antoine Cezar
hg-core: add path_encode...
r46110 } else if inset(&lower, *c) {
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(*c + 32)
Antoine Cezar
hg-core: add path_encode...
r46110 } else {
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 escape3(dest, *c)
Antoine Cezar
hg-core: add path_encode...
r46110 }
}
}
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 fn aux_encode(dest: &mut impl Sink, src: &[u8]) {
Antoine Cezar
hg-core: add path_encode...
r46110 let twobytes = [0; 8];
let onebyte: [u32; 8] = [!0, 0xffff_3ffe, !0, !0, !0, !0, !0, !0];
_encode(&twobytes, &onebyte, dest, src, false)
}
fn hash_mangle(src: &[u8], sha: &[u8]) -> Vec<u8> {
let dirprefixlen = 8;
let maxshortdirslen = 68;
let last_slash = src.iter().rposition(|b| *b == b'/');
Arseniy Alekseyev
rhg: in path_encode, simplify a bit more...
r51062 let basename_start = match last_slash {
Some(slash) => slash + 1,
None => 0,
};
let basename = &src[basename_start..];
let ext = match basename.iter().rposition(|b| *b == b'.') {
None => &[],
Some(dot) => &basename[dot..],
Antoine Cezar
hg-core: add path_encode...
r46110 };
Arseniy Alekseyev
rhg: in path_encode, use Vec directly instead of VecDest...
r51059 let mut dest = Vec::with_capacity(MAXSTOREPATHLEN);
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_bytes(b"dh/");
Antoine Cezar
hg-core: add path_encode...
r46110
Arseniy Alekseyev
rhg: fix a bug in path_encode...
r50991 if let Some(last_slash) = last_slash {
for slice in src[..last_slash].split(|b| *b == b'/') {
Antoine Cezar
hg-core: add path_encode...
r46110 let slice = &slice[..std::cmp::min(slice.len(), dirprefixlen)];
Arseniy Alekseyev
rhg: in path_encode, use Vec directly instead of VecDest...
r51059 if dest.len() + slice.len() > maxshortdirslen + 3 {
Antoine Cezar
hg-core: add path_encode...
r46110 break;
Arseniy Alekseyev
rhg: don't crash on empty directory names in path_encode, just in case...
r51264 }
if let Some(last_char) = slice.last() {
if *last_char == b'.' || *last_char == b' ' {
Arseniy Alekseyev
rhg: fix a bug in path encoding, demonstrated in the parent commit
r51263 dest.write_bytes(&slice[0..slice.len() - 1]);
dest.write_byte(b'_');
} else {
dest.write_bytes(slice);
}
Arseniy Alekseyev
rhg: don't crash on empty directory names in path_encode, just in case...
r51264 };
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(b'/');
Antoine Cezar
hg-core: add path_encode...
r46110 }
}
Arseniy Alekseyev
rhg: in path_encode, simplify a bit more...
r51062 let used = dest.len() + 40 + ext.len();
Antoine Cezar
hg-core: add path_encode...
r46110
if MAXSTOREPATHLEN > used {
let slop = MAXSTOREPATHLEN - used;
Arseniy Alekseyev
rhg: in path_encode, simplify a bit more...
r51062 let len = std::cmp::min(basename.len(), slop);
dest.write_bytes(&basename[..len])
Antoine Cezar
hg-core: add path_encode...
r46110 }
for c in sha {
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 hexencode(&mut dest, *c);
Antoine Cezar
hg-core: add path_encode...
r46110 }
Arseniy Alekseyev
rhg: in path_encode, simplify a bit more...
r51062 dest.write_bytes(ext);
Arseniy Alekseyev
rhg: in path_encode, be a bit more conservative about memory usage...
r51061 dest.shrink_to_fit();
Arseniy Alekseyev
rhg: in path_encode, use Vec directly instead of VecDest...
r51059 dest
Antoine Cezar
hg-core: add path_encode...
r46110 }
fn hash_encode(src: &[u8]) -> Vec<u8> {
Arseniy Alekseyev
rhg: in path_encode, make DestArr generic over its size
r51056 let mut dired: DestArr<MAXENCODE> = DestArr::create();
let mut lowered: DestArr<MAXENCODE> = DestArr::create();
let mut auxed: DestArr<MAXENCODE> = DestArr::create();
Antoine Cezar
hg-core: add path_encode...
r46110 let baselen = (src.len() - 5) * 3;
if baselen >= MAXENCODE {
panic!("path_encode::hash_encore: string too long: {}", baselen)
};
Arseniy Alekseyev
rhg: in path_encode add a DestArr type...
r51055 encode_dir(&mut dired, src);
let sha = Sha1::digest(dired.contents());
lower_encode(&mut lowered, &dired.contents()[5..]);
aux_encode(&mut auxed, lowered.contents());
hash_mangle(auxed.contents(), &sha)
Antoine Cezar
hg-core: add path_encode...
r46110 }
pub fn path_encode(path: &[u8]) -> Vec<u8> {
let newlen = if path.len() <= MAXSTOREPATHLEN {
Arseniy Alekseyev
rhg: in path_encode, split Dest into VecDest and MeasureDest...
r51058 let mut measure = MeasureDest::create();
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 basic_encode(&mut measure, path);
measure.len
Antoine Cezar
hg-core: add path_encode...
r46110 } else {
Arseniy Alekseyev
rhg: small refactor: stop using a magical constant "+ 1"...
r51060 return hash_encode(path);
Antoine Cezar
hg-core: add path_encode...
r46110 };
if newlen <= MAXSTOREPATHLEN {
if newlen == path.len() {
path.to_vec()
} else {
Arseniy Alekseyev
rhg: in path_encode, use Vec directly instead of VecDest...
r51059 let mut dest = Vec::with_capacity(newlen);
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 basic_encode(&mut dest, path);
Arseniy Alekseyev
rhg: in path_encode, use Vec directly instead of VecDest...
r51059 assert!(dest.len() == newlen);
dest
Antoine Cezar
hg-core: add path_encode...
r46110 }
} else {
Raphaël Gomès
rust-clippy: fix most warnings in `hg-core`...
r50825 hash_encode(path)
Antoine Cezar
hg-core: add path_encode...
r46110 }
}
Arseniy Alekseyev
rhg: demonstrate a bug in path_encode...
r50990
#[cfg(test)]
mod tests {
use super::*;
use crate::utils::hg_path::HgPathBuf;
#[test]
Arseniy Alekseyev
rhg: show a bug in the rust implementation of path_encode introduced recently...
r51262 fn test_dirname_ends_with_underscore() {
let input = b"data/dir1234.foo/ABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJ.i";
Arseniy Alekseyev
rhg: fix a bug in path encoding, demonstrated in the parent commit
r51263 let expected = b"dh/dir1234_/abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij.if2e9ce59e095eff5f8f334dc809e65606a0aa50b.i";
Arseniy Alekseyev
rhg: show a bug in the rust implementation of path_encode introduced recently...
r51262 let res = path_encode(input);
assert_eq!(
HgPathBuf::from_bytes(&res),
HgPathBuf::from_bytes(expected)
);
}
#[test]
Arseniy Alekseyev
rhg: demonstrate a bug in path_encode...
r50990 fn test_long_filename_at_root() {
let input = b"data/ABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJ.i";
let expected = b"dh/abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij.i708243a2237a7afae259ea3545a72a2ef11c247b.i";
let res = path_encode(input);
assert_eq!(
HgPathBuf::from_bytes(&res),
HgPathBuf::from_bytes(expected)
);
}
}