##// END OF EJS Templates
rust-parsers: use in-place mutation instead of allocating a new `Vec`...
Raphaël Gomès -
r46223:1efbc787 default
parent child Browse files
Show More
@@ -1,518 +1,512
1 // Copyright 2019 Raphaël Gomès <rgomes@octobus.net>
1 // Copyright 2019 Raphaël Gomès <rgomes@octobus.net>
2 //
2 //
3 // This software may be used and distributed according to the terms of the
3 // This software may be used and distributed according to the terms of the
4 // GNU General Public License version 2 or any later version.
4 // GNU General Public License version 2 or any later version.
5
5
6 use crate::utils::hg_path::HgPath;
6 use crate::utils::hg_path::HgPath;
7 use crate::{
7 use crate::{
8 dirstate::{CopyMap, EntryState, StateMap},
8 dirstate::{CopyMap, EntryState, StateMap},
9 DirstateEntry, DirstatePackError, DirstateParents, DirstateParseError,
9 DirstateEntry, DirstatePackError, DirstateParents, DirstateParseError,
10 };
10 };
11 use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
11 use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
12 use micro_timer::timed;
12 use micro_timer::timed;
13 use std::convert::{TryFrom, TryInto};
13 use std::convert::{TryFrom, TryInto};
14 use std::io::Cursor;
14 use std::io::Cursor;
15 use std::time::Duration;
15 use std::time::Duration;
16
16
17 /// Parents are stored in the dirstate as byte hashes.
17 /// Parents are stored in the dirstate as byte hashes.
18 pub const PARENT_SIZE: usize = 20;
18 pub const PARENT_SIZE: usize = 20;
19 /// Dirstate entries have a static part of 8 + 32 + 32 + 32 + 32 bits.
19 /// Dirstate entries have a static part of 8 + 32 + 32 + 32 + 32 bits.
20 const MIN_ENTRY_SIZE: usize = 17;
20 const MIN_ENTRY_SIZE: usize = 17;
21
21
22 type ParseResult<'a> = (
22 type ParseResult<'a> = (
23 DirstateParents,
23 DirstateParents,
24 Vec<(&'a HgPath, DirstateEntry)>,
24 Vec<(&'a HgPath, DirstateEntry)>,
25 Vec<(&'a HgPath, &'a HgPath)>,
25 Vec<(&'a HgPath, &'a HgPath)>,
26 );
26 );
27
27
28 #[timed]
28 #[timed]
29 pub fn parse_dirstate(
29 pub fn parse_dirstate(
30 contents: &[u8],
30 contents: &[u8],
31 ) -> Result<ParseResult, DirstateParseError> {
31 ) -> Result<ParseResult, DirstateParseError> {
32 if contents.len() < PARENT_SIZE * 2 {
32 if contents.len() < PARENT_SIZE * 2 {
33 return Err(DirstateParseError::TooLittleData);
33 return Err(DirstateParseError::TooLittleData);
34 }
34 }
35 let mut copies = vec![];
35 let mut copies = vec![];
36 let mut entries = vec![];
36 let mut entries = vec![];
37
37
38 let mut curr_pos = PARENT_SIZE * 2;
38 let mut curr_pos = PARENT_SIZE * 2;
39 let parents = DirstateParents {
39 let parents = DirstateParents {
40 p1: contents[..PARENT_SIZE].try_into().unwrap(),
40 p1: contents[..PARENT_SIZE].try_into().unwrap(),
41 p2: contents[PARENT_SIZE..curr_pos].try_into().unwrap(),
41 p2: contents[PARENT_SIZE..curr_pos].try_into().unwrap(),
42 };
42 };
43
43
44 while curr_pos < contents.len() {
44 while curr_pos < contents.len() {
45 if curr_pos + MIN_ENTRY_SIZE > contents.len() {
45 if curr_pos + MIN_ENTRY_SIZE > contents.len() {
46 return Err(DirstateParseError::Overflow);
46 return Err(DirstateParseError::Overflow);
47 }
47 }
48 let entry_bytes = &contents[curr_pos..];
48 let entry_bytes = &contents[curr_pos..];
49
49
50 let mut cursor = Cursor::new(entry_bytes);
50 let mut cursor = Cursor::new(entry_bytes);
51 let state = EntryState::try_from(cursor.read_u8()?)?;
51 let state = EntryState::try_from(cursor.read_u8()?)?;
52 let mode = cursor.read_i32::<BigEndian>()?;
52 let mode = cursor.read_i32::<BigEndian>()?;
53 let size = cursor.read_i32::<BigEndian>()?;
53 let size = cursor.read_i32::<BigEndian>()?;
54 let mtime = cursor.read_i32::<BigEndian>()?;
54 let mtime = cursor.read_i32::<BigEndian>()?;
55 let path_len = cursor.read_i32::<BigEndian>()? as usize;
55 let path_len = cursor.read_i32::<BigEndian>()? as usize;
56
56
57 if path_len > contents.len() - curr_pos {
57 if path_len > contents.len() - curr_pos {
58 return Err(DirstateParseError::Overflow);
58 return Err(DirstateParseError::Overflow);
59 }
59 }
60
60
61 // Slice instead of allocating a Vec needed for `read_exact`
61 // Slice instead of allocating a Vec needed for `read_exact`
62 let path = &entry_bytes[MIN_ENTRY_SIZE..MIN_ENTRY_SIZE + (path_len)];
62 let path = &entry_bytes[MIN_ENTRY_SIZE..MIN_ENTRY_SIZE + (path_len)];
63
63
64 let (path, copy) = match memchr::memchr(0, path) {
64 let (path, copy) = match memchr::memchr(0, path) {
65 None => (path, None),
65 None => (path, None),
66 Some(i) => (&path[..i], Some(&path[(i + 1)..])),
66 Some(i) => (&path[..i], Some(&path[(i + 1)..])),
67 };
67 };
68
68
69 if let Some(copy_path) = copy {
69 if let Some(copy_path) = copy {
70 copies.push((HgPath::new(path), HgPath::new(copy_path)));
70 copies.push((HgPath::new(path), HgPath::new(copy_path)));
71 };
71 };
72 entries.push((
72 entries.push((
73 HgPath::new(path),
73 HgPath::new(path),
74 DirstateEntry {
74 DirstateEntry {
75 state,
75 state,
76 mode,
76 mode,
77 size,
77 size,
78 mtime,
78 mtime,
79 },
79 },
80 ));
80 ));
81 curr_pos = curr_pos + MIN_ENTRY_SIZE + (path_len);
81 curr_pos = curr_pos + MIN_ENTRY_SIZE + (path_len);
82 }
82 }
83 Ok((parents, entries, copies))
83 Ok((parents, entries, copies))
84 }
84 }
85
85
86 /// `now` is the duration in seconds since the Unix epoch
86 /// `now` is the duration in seconds since the Unix epoch
87 #[cfg(not(feature = "dirstate-tree"))]
87 #[cfg(not(feature = "dirstate-tree"))]
88 pub fn pack_dirstate(
88 pub fn pack_dirstate(
89 state_map: &mut StateMap,
89 state_map: &mut StateMap,
90 copy_map: &CopyMap,
90 copy_map: &CopyMap,
91 parents: DirstateParents,
91 parents: DirstateParents,
92 now: Duration,
92 now: Duration,
93 ) -> Result<Vec<u8>, DirstatePackError> {
93 ) -> Result<Vec<u8>, DirstatePackError> {
94 // TODO move away from i32 before 2038.
94 // TODO move away from i32 before 2038.
95 let now: i32 = now.as_secs().try_into().expect("time overflow");
95 let now: i32 = now.as_secs().try_into().expect("time overflow");
96
96
97 let expected_size: usize = state_map
97 let expected_size: usize = state_map
98 .iter()
98 .iter()
99 .map(|(filename, _)| {
99 .map(|(filename, _)| {
100 let mut length = MIN_ENTRY_SIZE + filename.len();
100 let mut length = MIN_ENTRY_SIZE + filename.len();
101 if let Some(copy) = copy_map.get(filename) {
101 if let Some(copy) = copy_map.get(filename) {
102 length += copy.len() + 1;
102 length += copy.len() + 1;
103 }
103 }
104 length
104 length
105 })
105 })
106 .sum();
106 .sum();
107 let expected_size = expected_size + PARENT_SIZE * 2;
107 let expected_size = expected_size + PARENT_SIZE * 2;
108
108
109 let mut packed = Vec::with_capacity(expected_size);
109 let mut packed = Vec::with_capacity(expected_size);
110 let mut new_state_map = vec![];
111
110
112 packed.extend(&parents.p1);
111 packed.extend(&parents.p1);
113 packed.extend(&parents.p2);
112 packed.extend(&parents.p2);
114
113
115 for (filename, entry) in state_map.iter() {
114 for (filename, entry) in state_map.iter_mut() {
116 let new_filename = filename.to_owned();
115 let new_filename = filename.to_owned();
117 let mut new_mtime: i32 = entry.mtime;
116 let mut new_mtime: i32 = entry.mtime;
118 if entry.state == EntryState::Normal && entry.mtime == now {
117 if entry.state == EntryState::Normal && entry.mtime == now {
119 // The file was last modified "simultaneously" with the current
118 // The file was last modified "simultaneously" with the current
120 // write to dirstate (i.e. within the same second for file-
119 // write to dirstate (i.e. within the same second for file-
121 // systems with a granularity of 1 sec). This commonly happens
120 // systems with a granularity of 1 sec). This commonly happens
122 // for at least a couple of files on 'update'.
121 // for at least a couple of files on 'update'.
123 // The user could change the file without changing its size
122 // The user could change the file without changing its size
124 // within the same second. Invalidate the file's mtime in
123 // within the same second. Invalidate the file's mtime in
125 // dirstate, forcing future 'status' calls to compare the
124 // dirstate, forcing future 'status' calls to compare the
126 // contents of the file if the size is the same. This prevents
125 // contents of the file if the size is the same. This prevents
127 // mistakenly treating such files as clean.
126 // mistakenly treating such files as clean.
128 new_mtime = -1;
127 new_mtime = -1;
129 new_state_map.push((
128 *entry = DirstateEntry {
130 filename.to_owned(),
129 mtime: new_mtime,
131 DirstateEntry {
130 ..*entry
132 mtime: new_mtime,
131 };
133 ..*entry
134 },
135 ));
136 }
132 }
137 let mut new_filename = new_filename.into_vec();
133 let mut new_filename = new_filename.into_vec();
138 if let Some(copy) = copy_map.get(filename) {
134 if let Some(copy) = copy_map.get(filename) {
139 new_filename.push(b'\0');
135 new_filename.push(b'\0');
140 new_filename.extend(copy.bytes());
136 new_filename.extend(copy.bytes());
141 }
137 }
142
138
143 packed.write_u8(entry.state.into())?;
139 packed.write_u8(entry.state.into())?;
144 packed.write_i32::<BigEndian>(entry.mode)?;
140 packed.write_i32::<BigEndian>(entry.mode)?;
145 packed.write_i32::<BigEndian>(entry.size)?;
141 packed.write_i32::<BigEndian>(entry.size)?;
146 packed.write_i32::<BigEndian>(new_mtime)?;
142 packed.write_i32::<BigEndian>(new_mtime)?;
147 packed.write_i32::<BigEndian>(new_filename.len() as i32)?;
143 packed.write_i32::<BigEndian>(new_filename.len() as i32)?;
148 packed.extend(new_filename)
144 packed.extend(new_filename)
149 }
145 }
150
146
151 if packed.len() != expected_size {
147 if packed.len() != expected_size {
152 return Err(DirstatePackError::BadSize(expected_size, packed.len()));
148 return Err(DirstatePackError::BadSize(expected_size, packed.len()));
153 }
149 }
154
150
155 state_map.extend(new_state_map);
156
157 Ok(packed)
151 Ok(packed)
158 }
152 }
159 /// `now` is the duration in seconds since the Unix epoch
153 /// `now` is the duration in seconds since the Unix epoch
160 #[cfg(feature = "dirstate-tree")]
154 #[cfg(feature = "dirstate-tree")]
161 pub fn pack_dirstate(
155 pub fn pack_dirstate(
162 state_map: &mut StateMap,
156 state_map: &mut StateMap,
163 copy_map: &CopyMap,
157 copy_map: &CopyMap,
164 parents: DirstateParents,
158 parents: DirstateParents,
165 now: Duration,
159 now: Duration,
166 ) -> Result<Vec<u8>, DirstatePackError> {
160 ) -> Result<Vec<u8>, DirstatePackError> {
167 // TODO move away from i32 before 2038.
161 // TODO move away from i32 before 2038.
168 let now: i32 = now.as_secs().try_into().expect("time overflow");
162 let now: i32 = now.as_secs().try_into().expect("time overflow");
169
163
170 let expected_size: usize = state_map
164 let expected_size: usize = state_map
171 .iter()
165 .iter()
172 .map(|(filename, _)| {
166 .map(|(filename, _)| {
173 let mut length = MIN_ENTRY_SIZE + filename.len();
167 let mut length = MIN_ENTRY_SIZE + filename.len();
174 if let Some(copy) = copy_map.get(&filename) {
168 if let Some(copy) = copy_map.get(&filename) {
175 length += copy.len() + 1;
169 length += copy.len() + 1;
176 }
170 }
177 length
171 length
178 })
172 })
179 .sum();
173 .sum();
180 let expected_size = expected_size + PARENT_SIZE * 2;
174 let expected_size = expected_size + PARENT_SIZE * 2;
181
175
182 let mut packed = Vec::with_capacity(expected_size);
176 let mut packed = Vec::with_capacity(expected_size);
183 let mut new_state_map = vec![];
177 let mut new_state_map = vec![];
184
178
185 packed.extend(&parents.p1);
179 packed.extend(&parents.p1);
186 packed.extend(&parents.p2);
180 packed.extend(&parents.p2);
187
181
188 for (filename, entry) in state_map.iter() {
182 for (filename, entry) in state_map.iter() {
189 let new_filename = filename.to_owned();
183 let new_filename = filename.to_owned();
190 let mut new_mtime: i32 = entry.mtime;
184 let mut new_mtime: i32 = entry.mtime;
191 if entry.state == EntryState::Normal && entry.mtime == now {
185 if entry.state == EntryState::Normal && entry.mtime == now {
192 // The file was last modified "simultaneously" with the current
186 // The file was last modified "simultaneously" with the current
193 // write to dirstate (i.e. within the same second for file-
187 // write to dirstate (i.e. within the same second for file-
194 // systems with a granularity of 1 sec). This commonly happens
188 // systems with a granularity of 1 sec). This commonly happens
195 // for at least a couple of files on 'update'.
189 // for at least a couple of files on 'update'.
196 // The user could change the file without changing its size
190 // The user could change the file without changing its size
197 // within the same second. Invalidate the file's mtime in
191 // within the same second. Invalidate the file's mtime in
198 // dirstate, forcing future 'status' calls to compare the
192 // dirstate, forcing future 'status' calls to compare the
199 // contents of the file if the size is the same. This prevents
193 // contents of the file if the size is the same. This prevents
200 // mistakenly treating such files as clean.
194 // mistakenly treating such files as clean.
201 new_mtime = -1;
195 new_mtime = -1;
202 new_state_map.push((
196 new_state_map.push((
203 filename.to_owned(),
197 filename.to_owned(),
204 DirstateEntry {
198 DirstateEntry {
205 mtime: new_mtime,
199 mtime: new_mtime,
206 ..entry
200 ..entry
207 },
201 },
208 ));
202 ));
209 }
203 }
210 let mut new_filename = new_filename.into_vec();
204 let mut new_filename = new_filename.into_vec();
211 if let Some(copy) = copy_map.get(&filename) {
205 if let Some(copy) = copy_map.get(&filename) {
212 new_filename.push(b'\0');
206 new_filename.push(b'\0');
213 new_filename.extend(copy.bytes());
207 new_filename.extend(copy.bytes());
214 }
208 }
215
209
216 packed.write_u8(entry.state.into())?;
210 packed.write_u8(entry.state.into())?;
217 packed.write_i32::<BigEndian>(entry.mode)?;
211 packed.write_i32::<BigEndian>(entry.mode)?;
218 packed.write_i32::<BigEndian>(entry.size)?;
212 packed.write_i32::<BigEndian>(entry.size)?;
219 packed.write_i32::<BigEndian>(new_mtime)?;
213 packed.write_i32::<BigEndian>(new_mtime)?;
220 packed.write_i32::<BigEndian>(new_filename.len() as i32)?;
214 packed.write_i32::<BigEndian>(new_filename.len() as i32)?;
221 packed.extend(new_filename)
215 packed.extend(new_filename)
222 }
216 }
223
217
224 if packed.len() != expected_size {
218 if packed.len() != expected_size {
225 return Err(DirstatePackError::BadSize(expected_size, packed.len()));
219 return Err(DirstatePackError::BadSize(expected_size, packed.len()));
226 }
220 }
227
221
228 state_map.extend(new_state_map);
222 state_map.extend(new_state_map);
229
223
230 Ok(packed)
224 Ok(packed)
231 }
225 }
232
226
233 #[cfg(test)]
227 #[cfg(test)]
234 mod tests {
228 mod tests {
235 use super::*;
229 use super::*;
236 use crate::{utils::hg_path::HgPathBuf, FastHashMap};
230 use crate::{utils::hg_path::HgPathBuf, FastHashMap};
237 use pretty_assertions::assert_eq;
231 use pretty_assertions::assert_eq;
238
232
239 #[test]
233 #[test]
240 fn test_pack_dirstate_empty() {
234 fn test_pack_dirstate_empty() {
241 let mut state_map = StateMap::default();
235 let mut state_map = StateMap::default();
242 let copymap = FastHashMap::default();
236 let copymap = FastHashMap::default();
243 let parents = DirstateParents {
237 let parents = DirstateParents {
244 p1: *b"12345678910111213141",
238 p1: *b"12345678910111213141",
245 p2: *b"00000000000000000000",
239 p2: *b"00000000000000000000",
246 };
240 };
247 let now = Duration::new(15000000, 0);
241 let now = Duration::new(15000000, 0);
248 let expected = b"1234567891011121314100000000000000000000".to_vec();
242 let expected = b"1234567891011121314100000000000000000000".to_vec();
249
243
250 assert_eq!(
244 assert_eq!(
251 expected,
245 expected,
252 pack_dirstate(&mut state_map, &copymap, parents, now).unwrap()
246 pack_dirstate(&mut state_map, &copymap, parents, now).unwrap()
253 );
247 );
254
248
255 assert!(state_map.is_empty())
249 assert!(state_map.is_empty())
256 }
250 }
257 #[test]
251 #[test]
258 fn test_pack_dirstate_one_entry() {
252 fn test_pack_dirstate_one_entry() {
259 let expected_state_map: StateMap = [(
253 let expected_state_map: StateMap = [(
260 HgPathBuf::from_bytes(b"f1"),
254 HgPathBuf::from_bytes(b"f1"),
261 DirstateEntry {
255 DirstateEntry {
262 state: EntryState::Normal,
256 state: EntryState::Normal,
263 mode: 0o644,
257 mode: 0o644,
264 size: 0,
258 size: 0,
265 mtime: 791231220,
259 mtime: 791231220,
266 },
260 },
267 )]
261 )]
268 .iter()
262 .iter()
269 .cloned()
263 .cloned()
270 .collect();
264 .collect();
271 let mut state_map = expected_state_map.clone();
265 let mut state_map = expected_state_map.clone();
272
266
273 let copymap = FastHashMap::default();
267 let copymap = FastHashMap::default();
274 let parents = DirstateParents {
268 let parents = DirstateParents {
275 p1: *b"12345678910111213141",
269 p1: *b"12345678910111213141",
276 p2: *b"00000000000000000000",
270 p2: *b"00000000000000000000",
277 };
271 };
278 let now = Duration::new(15000000, 0);
272 let now = Duration::new(15000000, 0);
279 let expected = [
273 let expected = [
280 49, 50, 51, 52, 53, 54, 55, 56, 57, 49, 48, 49, 49, 49, 50, 49,
274 49, 50, 51, 52, 53, 54, 55, 56, 57, 49, 48, 49, 49, 49, 50, 49,
281 51, 49, 52, 49, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
275 51, 49, 52, 49, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
282 48, 48, 48, 48, 48, 48, 48, 48, 110, 0, 0, 1, 164, 0, 0, 0, 0, 47,
276 48, 48, 48, 48, 48, 48, 48, 48, 110, 0, 0, 1, 164, 0, 0, 0, 0, 47,
283 41, 58, 244, 0, 0, 0, 2, 102, 49,
277 41, 58, 244, 0, 0, 0, 2, 102, 49,
284 ]
278 ]
285 .to_vec();
279 .to_vec();
286
280
287 assert_eq!(
281 assert_eq!(
288 expected,
282 expected,
289 pack_dirstate(&mut state_map, &copymap, parents, now).unwrap()
283 pack_dirstate(&mut state_map, &copymap, parents, now).unwrap()
290 );
284 );
291
285
292 assert_eq!(expected_state_map, state_map);
286 assert_eq!(expected_state_map, state_map);
293 }
287 }
294 #[test]
288 #[test]
295 fn test_pack_dirstate_one_entry_with_copy() {
289 fn test_pack_dirstate_one_entry_with_copy() {
296 let expected_state_map: StateMap = [(
290 let expected_state_map: StateMap = [(
297 HgPathBuf::from_bytes(b"f1"),
291 HgPathBuf::from_bytes(b"f1"),
298 DirstateEntry {
292 DirstateEntry {
299 state: EntryState::Normal,
293 state: EntryState::Normal,
300 mode: 0o644,
294 mode: 0o644,
301 size: 0,
295 size: 0,
302 mtime: 791231220,
296 mtime: 791231220,
303 },
297 },
304 )]
298 )]
305 .iter()
299 .iter()
306 .cloned()
300 .cloned()
307 .collect();
301 .collect();
308 let mut state_map = expected_state_map.clone();
302 let mut state_map = expected_state_map.clone();
309 let mut copymap = FastHashMap::default();
303 let mut copymap = FastHashMap::default();
310 copymap.insert(
304 copymap.insert(
311 HgPathBuf::from_bytes(b"f1"),
305 HgPathBuf::from_bytes(b"f1"),
312 HgPathBuf::from_bytes(b"copyname"),
306 HgPathBuf::from_bytes(b"copyname"),
313 );
307 );
314 let parents = DirstateParents {
308 let parents = DirstateParents {
315 p1: *b"12345678910111213141",
309 p1: *b"12345678910111213141",
316 p2: *b"00000000000000000000",
310 p2: *b"00000000000000000000",
317 };
311 };
318 let now = Duration::new(15000000, 0);
312 let now = Duration::new(15000000, 0);
319 let expected = [
313 let expected = [
320 49, 50, 51, 52, 53, 54, 55, 56, 57, 49, 48, 49, 49, 49, 50, 49,
314 49, 50, 51, 52, 53, 54, 55, 56, 57, 49, 48, 49, 49, 49, 50, 49,
321 51, 49, 52, 49, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
315 51, 49, 52, 49, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
322 48, 48, 48, 48, 48, 48, 48, 48, 110, 0, 0, 1, 164, 0, 0, 0, 0, 47,
316 48, 48, 48, 48, 48, 48, 48, 48, 110, 0, 0, 1, 164, 0, 0, 0, 0, 47,
323 41, 58, 244, 0, 0, 0, 11, 102, 49, 0, 99, 111, 112, 121, 110, 97,
317 41, 58, 244, 0, 0, 0, 11, 102, 49, 0, 99, 111, 112, 121, 110, 97,
324 109, 101,
318 109, 101,
325 ]
319 ]
326 .to_vec();
320 .to_vec();
327
321
328 assert_eq!(
322 assert_eq!(
329 expected,
323 expected,
330 pack_dirstate(&mut state_map, &copymap, parents, now).unwrap()
324 pack_dirstate(&mut state_map, &copymap, parents, now).unwrap()
331 );
325 );
332 assert_eq!(expected_state_map, state_map);
326 assert_eq!(expected_state_map, state_map);
333 }
327 }
334
328
335 #[test]
329 #[test]
336 fn test_parse_pack_one_entry_with_copy() {
330 fn test_parse_pack_one_entry_with_copy() {
337 let mut state_map: StateMap = [(
331 let mut state_map: StateMap = [(
338 HgPathBuf::from_bytes(b"f1"),
332 HgPathBuf::from_bytes(b"f1"),
339 DirstateEntry {
333 DirstateEntry {
340 state: EntryState::Normal,
334 state: EntryState::Normal,
341 mode: 0o644,
335 mode: 0o644,
342 size: 0,
336 size: 0,
343 mtime: 791231220,
337 mtime: 791231220,
344 },
338 },
345 )]
339 )]
346 .iter()
340 .iter()
347 .cloned()
341 .cloned()
348 .collect();
342 .collect();
349 let mut copymap = FastHashMap::default();
343 let mut copymap = FastHashMap::default();
350 copymap.insert(
344 copymap.insert(
351 HgPathBuf::from_bytes(b"f1"),
345 HgPathBuf::from_bytes(b"f1"),
352 HgPathBuf::from_bytes(b"copyname"),
346 HgPathBuf::from_bytes(b"copyname"),
353 );
347 );
354 let parents = DirstateParents {
348 let parents = DirstateParents {
355 p1: *b"12345678910111213141",
349 p1: *b"12345678910111213141",
356 p2: *b"00000000000000000000",
350 p2: *b"00000000000000000000",
357 };
351 };
358 let now = Duration::new(15000000, 0);
352 let now = Duration::new(15000000, 0);
359 let result =
353 let result =
360 pack_dirstate(&mut state_map, &copymap, parents.clone(), now)
354 pack_dirstate(&mut state_map, &copymap, parents.clone(), now)
361 .unwrap();
355 .unwrap();
362
356
363 let (new_parents, entries, copies) =
357 let (new_parents, entries, copies) =
364 parse_dirstate(result.as_slice()).unwrap();
358 parse_dirstate(result.as_slice()).unwrap();
365 let new_state_map: StateMap = entries
359 let new_state_map: StateMap = entries
366 .into_iter()
360 .into_iter()
367 .map(|(path, entry)| (path.to_owned(), entry))
361 .map(|(path, entry)| (path.to_owned(), entry))
368 .collect();
362 .collect();
369 let new_copy_map: CopyMap = copies
363 let new_copy_map: CopyMap = copies
370 .into_iter()
364 .into_iter()
371 .map(|(path, copy)| (path.to_owned(), copy.to_owned()))
365 .map(|(path, copy)| (path.to_owned(), copy.to_owned()))
372 .collect();
366 .collect();
373
367
374 assert_eq!(
368 assert_eq!(
375 (parents, state_map, copymap),
369 (parents, state_map, copymap),
376 (new_parents, new_state_map, new_copy_map)
370 (new_parents, new_state_map, new_copy_map)
377 )
371 )
378 }
372 }
379
373
380 #[test]
374 #[test]
381 fn test_parse_pack_multiple_entries_with_copy() {
375 fn test_parse_pack_multiple_entries_with_copy() {
382 let mut state_map: StateMap = [
376 let mut state_map: StateMap = [
383 (
377 (
384 HgPathBuf::from_bytes(b"f1"),
378 HgPathBuf::from_bytes(b"f1"),
385 DirstateEntry {
379 DirstateEntry {
386 state: EntryState::Normal,
380 state: EntryState::Normal,
387 mode: 0o644,
381 mode: 0o644,
388 size: 0,
382 size: 0,
389 mtime: 791231220,
383 mtime: 791231220,
390 },
384 },
391 ),
385 ),
392 (
386 (
393 HgPathBuf::from_bytes(b"f2"),
387 HgPathBuf::from_bytes(b"f2"),
394 DirstateEntry {
388 DirstateEntry {
395 state: EntryState::Merged,
389 state: EntryState::Merged,
396 mode: 0o777,
390 mode: 0o777,
397 size: 1000,
391 size: 1000,
398 mtime: 791231220,
392 mtime: 791231220,
399 },
393 },
400 ),
394 ),
401 (
395 (
402 HgPathBuf::from_bytes(b"f3"),
396 HgPathBuf::from_bytes(b"f3"),
403 DirstateEntry {
397 DirstateEntry {
404 state: EntryState::Removed,
398 state: EntryState::Removed,
405 mode: 0o644,
399 mode: 0o644,
406 size: 234553,
400 size: 234553,
407 mtime: 791231220,
401 mtime: 791231220,
408 },
402 },
409 ),
403 ),
410 (
404 (
411 HgPathBuf::from_bytes(b"f4\xF6"),
405 HgPathBuf::from_bytes(b"f4\xF6"),
412 DirstateEntry {
406 DirstateEntry {
413 state: EntryState::Added,
407 state: EntryState::Added,
414 mode: 0o644,
408 mode: 0o644,
415 size: -1,
409 size: -1,
416 mtime: -1,
410 mtime: -1,
417 },
411 },
418 ),
412 ),
419 ]
413 ]
420 .iter()
414 .iter()
421 .cloned()
415 .cloned()
422 .collect();
416 .collect();
423 let mut copymap = FastHashMap::default();
417 let mut copymap = FastHashMap::default();
424 copymap.insert(
418 copymap.insert(
425 HgPathBuf::from_bytes(b"f1"),
419 HgPathBuf::from_bytes(b"f1"),
426 HgPathBuf::from_bytes(b"copyname"),
420 HgPathBuf::from_bytes(b"copyname"),
427 );
421 );
428 copymap.insert(
422 copymap.insert(
429 HgPathBuf::from_bytes(b"f4\xF6"),
423 HgPathBuf::from_bytes(b"f4\xF6"),
430 HgPathBuf::from_bytes(b"copyname2"),
424 HgPathBuf::from_bytes(b"copyname2"),
431 );
425 );
432 let parents = DirstateParents {
426 let parents = DirstateParents {
433 p1: *b"12345678910111213141",
427 p1: *b"12345678910111213141",
434 p2: *b"00000000000000000000",
428 p2: *b"00000000000000000000",
435 };
429 };
436 let now = Duration::new(15000000, 0);
430 let now = Duration::new(15000000, 0);
437 let result =
431 let result =
438 pack_dirstate(&mut state_map, &copymap, parents.clone(), now)
432 pack_dirstate(&mut state_map, &copymap, parents.clone(), now)
439 .unwrap();
433 .unwrap();
440
434
441 let (new_parents, entries, copies) =
435 let (new_parents, entries, copies) =
442 parse_dirstate(result.as_slice()).unwrap();
436 parse_dirstate(result.as_slice()).unwrap();
443 let new_state_map: StateMap = entries
437 let new_state_map: StateMap = entries
444 .into_iter()
438 .into_iter()
445 .map(|(path, entry)| (path.to_owned(), entry))
439 .map(|(path, entry)| (path.to_owned(), entry))
446 .collect();
440 .collect();
447 let new_copy_map: CopyMap = copies
441 let new_copy_map: CopyMap = copies
448 .into_iter()
442 .into_iter()
449 .map(|(path, copy)| (path.to_owned(), copy.to_owned()))
443 .map(|(path, copy)| (path.to_owned(), copy.to_owned()))
450 .collect();
444 .collect();
451
445
452 assert_eq!(
446 assert_eq!(
453 (parents, state_map, copymap),
447 (parents, state_map, copymap),
454 (new_parents, new_state_map, new_copy_map)
448 (new_parents, new_state_map, new_copy_map)
455 )
449 )
456 }
450 }
457
451
458 #[test]
452 #[test]
459 /// https://www.mercurial-scm.org/repo/hg/rev/af3f26b6bba4
453 /// https://www.mercurial-scm.org/repo/hg/rev/af3f26b6bba4
460 fn test_parse_pack_one_entry_with_copy_and_time_conflict() {
454 fn test_parse_pack_one_entry_with_copy_and_time_conflict() {
461 let mut state_map: StateMap = [(
455 let mut state_map: StateMap = [(
462 HgPathBuf::from_bytes(b"f1"),
456 HgPathBuf::from_bytes(b"f1"),
463 DirstateEntry {
457 DirstateEntry {
464 state: EntryState::Normal,
458 state: EntryState::Normal,
465 mode: 0o644,
459 mode: 0o644,
466 size: 0,
460 size: 0,
467 mtime: 15000000,
461 mtime: 15000000,
468 },
462 },
469 )]
463 )]
470 .iter()
464 .iter()
471 .cloned()
465 .cloned()
472 .collect();
466 .collect();
473 let mut copymap = FastHashMap::default();
467 let mut copymap = FastHashMap::default();
474 copymap.insert(
468 copymap.insert(
475 HgPathBuf::from_bytes(b"f1"),
469 HgPathBuf::from_bytes(b"f1"),
476 HgPathBuf::from_bytes(b"copyname"),
470 HgPathBuf::from_bytes(b"copyname"),
477 );
471 );
478 let parents = DirstateParents {
472 let parents = DirstateParents {
479 p1: *b"12345678910111213141",
473 p1: *b"12345678910111213141",
480 p2: *b"00000000000000000000",
474 p2: *b"00000000000000000000",
481 };
475 };
482 let now = Duration::new(15000000, 0);
476 let now = Duration::new(15000000, 0);
483 let result =
477 let result =
484 pack_dirstate(&mut state_map, &copymap, parents.clone(), now)
478 pack_dirstate(&mut state_map, &copymap, parents.clone(), now)
485 .unwrap();
479 .unwrap();
486
480
487 let (new_parents, entries, copies) =
481 let (new_parents, entries, copies) =
488 parse_dirstate(result.as_slice()).unwrap();
482 parse_dirstate(result.as_slice()).unwrap();
489 let new_state_map: StateMap = entries
483 let new_state_map: StateMap = entries
490 .into_iter()
484 .into_iter()
491 .map(|(path, entry)| (path.to_owned(), entry))
485 .map(|(path, entry)| (path.to_owned(), entry))
492 .collect();
486 .collect();
493 let new_copy_map: CopyMap = copies
487 let new_copy_map: CopyMap = copies
494 .into_iter()
488 .into_iter()
495 .map(|(path, copy)| (path.to_owned(), copy.to_owned()))
489 .map(|(path, copy)| (path.to_owned(), copy.to_owned()))
496 .collect();
490 .collect();
497
491
498 assert_eq!(
492 assert_eq!(
499 (
493 (
500 parents,
494 parents,
501 [(
495 [(
502 HgPathBuf::from_bytes(b"f1"),
496 HgPathBuf::from_bytes(b"f1"),
503 DirstateEntry {
497 DirstateEntry {
504 state: EntryState::Normal,
498 state: EntryState::Normal,
505 mode: 0o644,
499 mode: 0o644,
506 size: 0,
500 size: 0,
507 mtime: -1
501 mtime: -1
508 }
502 }
509 )]
503 )]
510 .iter()
504 .iter()
511 .cloned()
505 .cloned()
512 .collect::<StateMap>(),
506 .collect::<StateMap>(),
513 copymap,
507 copymap,
514 ),
508 ),
515 (new_parents, new_state_map, new_copy_map)
509 (new_parents, new_state_map, new_copy_map)
516 )
510 )
517 }
511 }
518 }
512 }
General Comments 0
You need to be logged in to leave comments. Login now