##// END OF EJS Templates
rust: Return owned instead of borrowed DirstateEntry in DirstateMap APIs...
Simon Sapin -
r48123:4ee9f419 default
parent child Browse files
Show More
@@ -1,133 +1,133 b''
1 // dirstate module
1 // dirstate module
2 //
2 //
3 // Copyright 2019 Raphaël Gomès <rgomes@octobus.net>
3 // Copyright 2019 Raphaël Gomès <rgomes@octobus.net>
4 //
4 //
5 // This software may be used and distributed according to the terms of the
5 // This software may be used and distributed according to the terms of the
6 // GNU General Public License version 2 or any later version.
6 // GNU General Public License version 2 or any later version.
7
7
8 use crate::errors::HgError;
8 use crate::errors::HgError;
9 use crate::revlog::Node;
9 use crate::revlog::Node;
10 use crate::utils::hg_path::{HgPath, HgPathBuf};
10 use crate::utils::hg_path::{HgPath, HgPathBuf};
11 use crate::FastHashMap;
11 use crate::FastHashMap;
12 use bytes_cast::{unaligned, BytesCast};
12 use bytes_cast::{unaligned, BytesCast};
13 use std::convert::TryFrom;
13 use std::convert::TryFrom;
14
14
15 pub mod dirs_multiset;
15 pub mod dirs_multiset;
16 pub mod dirstate_map;
16 pub mod dirstate_map;
17 pub mod parsers;
17 pub mod parsers;
18 pub mod status;
18 pub mod status;
19
19
20 #[derive(Debug, PartialEq, Clone, BytesCast)]
20 #[derive(Debug, PartialEq, Clone, BytesCast)]
21 #[repr(C)]
21 #[repr(C)]
22 pub struct DirstateParents {
22 pub struct DirstateParents {
23 pub p1: Node,
23 pub p1: Node,
24 pub p2: Node,
24 pub p2: Node,
25 }
25 }
26
26
27 /// The C implementation uses all signed types. This will be an issue
27 /// The C implementation uses all signed types. This will be an issue
28 /// either when 4GB+ source files are commonplace or in 2038, whichever
28 /// either when 4GB+ source files are commonplace or in 2038, whichever
29 /// comes first.
29 /// comes first.
30 #[derive(Debug, PartialEq, Copy, Clone)]
30 #[derive(Debug, PartialEq, Copy, Clone)]
31 pub struct DirstateEntry {
31 pub struct DirstateEntry {
32 pub state: EntryState,
32 pub state: EntryState,
33 pub mode: i32,
33 pub mode: i32,
34 pub mtime: i32,
34 pub mtime: i32,
35 pub size: i32,
35 pub size: i32,
36 }
36 }
37
37
38 impl DirstateEntry {
38 impl DirstateEntry {
39 pub fn is_non_normal(&self) -> bool {
39 pub fn is_non_normal(&self) -> bool {
40 self.state != EntryState::Normal || self.mtime == MTIME_UNSET
40 self.state != EntryState::Normal || self.mtime == MTIME_UNSET
41 }
41 }
42
42
43 pub fn is_from_other_parent(&self) -> bool {
43 pub fn is_from_other_parent(&self) -> bool {
44 self.state == EntryState::Normal && self.size == SIZE_FROM_OTHER_PARENT
44 self.state == EntryState::Normal && self.size == SIZE_FROM_OTHER_PARENT
45 }
45 }
46
46
47 // TODO: other platforms
47 // TODO: other platforms
48 #[cfg(unix)]
48 #[cfg(unix)]
49 pub fn mode_changed(
49 pub fn mode_changed(
50 &self,
50 &self,
51 filesystem_metadata: &std::fs::Metadata,
51 filesystem_metadata: &std::fs::Metadata,
52 ) -> bool {
52 ) -> bool {
53 use std::os::unix::fs::MetadataExt;
53 use std::os::unix::fs::MetadataExt;
54 const EXEC_BIT_MASK: u32 = 0o100;
54 const EXEC_BIT_MASK: u32 = 0o100;
55 let dirstate_exec_bit = (self.mode as u32) & EXEC_BIT_MASK;
55 let dirstate_exec_bit = (self.mode as u32) & EXEC_BIT_MASK;
56 let fs_exec_bit = filesystem_metadata.mode() & EXEC_BIT_MASK;
56 let fs_exec_bit = filesystem_metadata.mode() & EXEC_BIT_MASK;
57 dirstate_exec_bit != fs_exec_bit
57 dirstate_exec_bit != fs_exec_bit
58 }
58 }
59 }
59 }
60
60
61 #[derive(BytesCast)]
61 #[derive(BytesCast)]
62 #[repr(C)]
62 #[repr(C)]
63 struct RawEntry {
63 struct RawEntry {
64 state: u8,
64 state: u8,
65 mode: unaligned::I32Be,
65 mode: unaligned::I32Be,
66 size: unaligned::I32Be,
66 size: unaligned::I32Be,
67 mtime: unaligned::I32Be,
67 mtime: unaligned::I32Be,
68 length: unaligned::I32Be,
68 length: unaligned::I32Be,
69 }
69 }
70
70
71 const MTIME_UNSET: i32 = -1;
71 const MTIME_UNSET: i32 = -1;
72
72
73 /// A `DirstateEntry` with a size of `-2` means that it was merged from the
73 /// A `DirstateEntry` with a size of `-2` means that it was merged from the
74 /// other parent. This allows revert to pick the right status back during a
74 /// other parent. This allows revert to pick the right status back during a
75 /// merge.
75 /// merge.
76 pub const SIZE_FROM_OTHER_PARENT: i32 = -2;
76 pub const SIZE_FROM_OTHER_PARENT: i32 = -2;
77
77
78 pub type StateMap = FastHashMap<HgPathBuf, DirstateEntry>;
78 pub type StateMap = FastHashMap<HgPathBuf, DirstateEntry>;
79 pub type StateMapIter<'a> =
79 pub type StateMapIter<'a> =
80 Box<dyn Iterator<Item = (&'a HgPath, &'a DirstateEntry)> + Send + 'a>;
80 Box<dyn Iterator<Item = (&'a HgPath, DirstateEntry)> + Send + 'a>;
81
81
82 pub type CopyMap = FastHashMap<HgPathBuf, HgPathBuf>;
82 pub type CopyMap = FastHashMap<HgPathBuf, HgPathBuf>;
83 pub type CopyMapIter<'a> =
83 pub type CopyMapIter<'a> =
84 Box<dyn Iterator<Item = (&'a HgPath, &'a HgPath)> + Send + 'a>;
84 Box<dyn Iterator<Item = (&'a HgPath, &'a HgPath)> + Send + 'a>;
85
85
86 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
86 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
87 pub enum EntryState {
87 pub enum EntryState {
88 Normal,
88 Normal,
89 Added,
89 Added,
90 Removed,
90 Removed,
91 Merged,
91 Merged,
92 Unknown,
92 Unknown,
93 }
93 }
94
94
95 impl EntryState {
95 impl EntryState {
96 pub fn is_tracked(self) -> bool {
96 pub fn is_tracked(self) -> bool {
97 use EntryState::*;
97 use EntryState::*;
98 match self {
98 match self {
99 Normal | Added | Merged => true,
99 Normal | Added | Merged => true,
100 Removed | Unknown => false,
100 Removed | Unknown => false,
101 }
101 }
102 }
102 }
103 }
103 }
104
104
105 impl TryFrom<u8> for EntryState {
105 impl TryFrom<u8> for EntryState {
106 type Error = HgError;
106 type Error = HgError;
107
107
108 fn try_from(value: u8) -> Result<Self, Self::Error> {
108 fn try_from(value: u8) -> Result<Self, Self::Error> {
109 match value {
109 match value {
110 b'n' => Ok(EntryState::Normal),
110 b'n' => Ok(EntryState::Normal),
111 b'a' => Ok(EntryState::Added),
111 b'a' => Ok(EntryState::Added),
112 b'r' => Ok(EntryState::Removed),
112 b'r' => Ok(EntryState::Removed),
113 b'm' => Ok(EntryState::Merged),
113 b'm' => Ok(EntryState::Merged),
114 b'?' => Ok(EntryState::Unknown),
114 b'?' => Ok(EntryState::Unknown),
115 _ => Err(HgError::CorruptedRepository(format!(
115 _ => Err(HgError::CorruptedRepository(format!(
116 "Incorrect dirstate entry state {}",
116 "Incorrect dirstate entry state {}",
117 value
117 value
118 ))),
118 ))),
119 }
119 }
120 }
120 }
121 }
121 }
122
122
123 impl Into<u8> for EntryState {
123 impl Into<u8> for EntryState {
124 fn into(self) -> u8 {
124 fn into(self) -> u8 {
125 match self {
125 match self {
126 EntryState::Normal => b'n',
126 EntryState::Normal => b'n',
127 EntryState::Added => b'a',
127 EntryState::Added => b'a',
128 EntryState::Removed => b'r',
128 EntryState::Removed => b'r',
129 EntryState::Merged => b'm',
129 EntryState::Merged => b'm',
130 EntryState::Unknown => b'?',
130 EntryState::Unknown => b'?',
131 }
131 }
132 }
132 }
133 }
133 }
@@ -1,427 +1,427 b''
1 // dirs_multiset.rs
1 // dirs_multiset.rs
2 //
2 //
3 // Copyright 2019 Raphaël Gomès <rgomes@octobus.net>
3 // Copyright 2019 Raphaël Gomès <rgomes@octobus.net>
4 //
4 //
5 // This software may be used and distributed according to the terms of the
5 // This software may be used and distributed according to the terms of the
6 // GNU General Public License version 2 or any later version.
6 // GNU General Public License version 2 or any later version.
7
7
8 //! A multiset of directory names.
8 //! A multiset of directory names.
9 //!
9 //!
10 //! Used to counts the references to directories in a manifest or dirstate.
10 //! Used to counts the references to directories in a manifest or dirstate.
11 use crate::{
11 use crate::{
12 dirstate::EntryState,
12 dirstate::EntryState,
13 utils::{
13 utils::{
14 files,
14 files,
15 hg_path::{HgPath, HgPathBuf, HgPathError},
15 hg_path::{HgPath, HgPathBuf, HgPathError},
16 },
16 },
17 DirstateEntry, DirstateMapError, FastHashMap,
17 DirstateEntry, DirstateMapError, FastHashMap,
18 };
18 };
19 use std::collections::{hash_map, hash_map::Entry, HashMap, HashSet};
19 use std::collections::{hash_map, hash_map::Entry, HashMap, HashSet};
20
20
21 // could be encapsulated if we care API stability more seriously
21 // could be encapsulated if we care API stability more seriously
22 pub type DirsMultisetIter<'a> = hash_map::Keys<'a, HgPathBuf, u32>;
22 pub type DirsMultisetIter<'a> = hash_map::Keys<'a, HgPathBuf, u32>;
23
23
24 #[derive(PartialEq, Debug)]
24 #[derive(PartialEq, Debug)]
25 pub struct DirsMultiset {
25 pub struct DirsMultiset {
26 inner: FastHashMap<HgPathBuf, u32>,
26 inner: FastHashMap<HgPathBuf, u32>,
27 }
27 }
28
28
29 impl DirsMultiset {
29 impl DirsMultiset {
30 /// Initializes the multiset from a dirstate.
30 /// Initializes the multiset from a dirstate.
31 ///
31 ///
32 /// If `skip_state` is provided, skips dirstate entries with equal state.
32 /// If `skip_state` is provided, skips dirstate entries with equal state.
33 pub fn from_dirstate<'a, I, P>(
33 pub fn from_dirstate<I, P>(
34 dirstate: I,
34 dirstate: I,
35 skip_state: Option<EntryState>,
35 skip_state: Option<EntryState>,
36 ) -> Result<Self, DirstateMapError>
36 ) -> Result<Self, DirstateMapError>
37 where
37 where
38 I: IntoIterator<Item = (P, &'a DirstateEntry)>,
38 I: IntoIterator<Item = (P, DirstateEntry)>,
39 P: AsRef<HgPath>,
39 P: AsRef<HgPath>,
40 {
40 {
41 let mut multiset = DirsMultiset {
41 let mut multiset = DirsMultiset {
42 inner: FastHashMap::default(),
42 inner: FastHashMap::default(),
43 };
43 };
44 for (filename, entry) in dirstate {
44 for (filename, entry) in dirstate {
45 let filename = filename.as_ref();
45 let filename = filename.as_ref();
46 // This `if` is optimized out of the loop
46 // This `if` is optimized out of the loop
47 if let Some(skip) = skip_state {
47 if let Some(skip) = skip_state {
48 if skip != entry.state {
48 if skip != entry.state {
49 multiset.add_path(filename)?;
49 multiset.add_path(filename)?;
50 }
50 }
51 } else {
51 } else {
52 multiset.add_path(filename)?;
52 multiset.add_path(filename)?;
53 }
53 }
54 }
54 }
55
55
56 Ok(multiset)
56 Ok(multiset)
57 }
57 }
58
58
59 /// Initializes the multiset from a manifest.
59 /// Initializes the multiset from a manifest.
60 pub fn from_manifest(
60 pub fn from_manifest(
61 manifest: &[impl AsRef<HgPath>],
61 manifest: &[impl AsRef<HgPath>],
62 ) -> Result<Self, DirstateMapError> {
62 ) -> Result<Self, DirstateMapError> {
63 let mut multiset = DirsMultiset {
63 let mut multiset = DirsMultiset {
64 inner: FastHashMap::default(),
64 inner: FastHashMap::default(),
65 };
65 };
66
66
67 for filename in manifest {
67 for filename in manifest {
68 multiset.add_path(filename.as_ref())?;
68 multiset.add_path(filename.as_ref())?;
69 }
69 }
70
70
71 Ok(multiset)
71 Ok(multiset)
72 }
72 }
73
73
74 /// Increases the count of deepest directory contained in the path.
74 /// Increases the count of deepest directory contained in the path.
75 ///
75 ///
76 /// If the directory is not yet in the map, adds its parents.
76 /// If the directory is not yet in the map, adds its parents.
77 pub fn add_path(
77 pub fn add_path(
78 &mut self,
78 &mut self,
79 path: impl AsRef<HgPath>,
79 path: impl AsRef<HgPath>,
80 ) -> Result<(), DirstateMapError> {
80 ) -> Result<(), DirstateMapError> {
81 for subpath in files::find_dirs(path.as_ref()) {
81 for subpath in files::find_dirs(path.as_ref()) {
82 if subpath.as_bytes().last() == Some(&b'/') {
82 if subpath.as_bytes().last() == Some(&b'/') {
83 // TODO Remove this once PathAuditor is certified
83 // TODO Remove this once PathAuditor is certified
84 // as the only entrypoint for path data
84 // as the only entrypoint for path data
85 let second_slash_index = subpath.len() - 1;
85 let second_slash_index = subpath.len() - 1;
86
86
87 return Err(DirstateMapError::InvalidPath(
87 return Err(DirstateMapError::InvalidPath(
88 HgPathError::ConsecutiveSlashes {
88 HgPathError::ConsecutiveSlashes {
89 bytes: path.as_ref().as_bytes().to_owned(),
89 bytes: path.as_ref().as_bytes().to_owned(),
90 second_slash_index,
90 second_slash_index,
91 },
91 },
92 ));
92 ));
93 }
93 }
94 if let Some(val) = self.inner.get_mut(subpath) {
94 if let Some(val) = self.inner.get_mut(subpath) {
95 *val += 1;
95 *val += 1;
96 break;
96 break;
97 }
97 }
98 self.inner.insert(subpath.to_owned(), 1);
98 self.inner.insert(subpath.to_owned(), 1);
99 }
99 }
100 Ok(())
100 Ok(())
101 }
101 }
102
102
103 /// Decreases the count of deepest directory contained in the path.
103 /// Decreases the count of deepest directory contained in the path.
104 ///
104 ///
105 /// If it is the only reference, decreases all parents until one is
105 /// If it is the only reference, decreases all parents until one is
106 /// removed.
106 /// removed.
107 /// If the directory is not in the map, something horrible has happened.
107 /// If the directory is not in the map, something horrible has happened.
108 pub fn delete_path(
108 pub fn delete_path(
109 &mut self,
109 &mut self,
110 path: impl AsRef<HgPath>,
110 path: impl AsRef<HgPath>,
111 ) -> Result<(), DirstateMapError> {
111 ) -> Result<(), DirstateMapError> {
112 for subpath in files::find_dirs(path.as_ref()) {
112 for subpath in files::find_dirs(path.as_ref()) {
113 match self.inner.entry(subpath.to_owned()) {
113 match self.inner.entry(subpath.to_owned()) {
114 Entry::Occupied(mut entry) => {
114 Entry::Occupied(mut entry) => {
115 let val = *entry.get();
115 let val = *entry.get();
116 if val > 1 {
116 if val > 1 {
117 entry.insert(val - 1);
117 entry.insert(val - 1);
118 break;
118 break;
119 }
119 }
120 entry.remove();
120 entry.remove();
121 }
121 }
122 Entry::Vacant(_) => {
122 Entry::Vacant(_) => {
123 return Err(DirstateMapError::PathNotFound(
123 return Err(DirstateMapError::PathNotFound(
124 path.as_ref().to_owned(),
124 path.as_ref().to_owned(),
125 ))
125 ))
126 }
126 }
127 };
127 };
128 }
128 }
129
129
130 Ok(())
130 Ok(())
131 }
131 }
132
132
133 pub fn contains(&self, key: impl AsRef<HgPath>) -> bool {
133 pub fn contains(&self, key: impl AsRef<HgPath>) -> bool {
134 self.inner.contains_key(key.as_ref())
134 self.inner.contains_key(key.as_ref())
135 }
135 }
136
136
137 pub fn iter(&self) -> DirsMultisetIter {
137 pub fn iter(&self) -> DirsMultisetIter {
138 self.inner.keys()
138 self.inner.keys()
139 }
139 }
140
140
141 pub fn len(&self) -> usize {
141 pub fn len(&self) -> usize {
142 self.inner.len()
142 self.inner.len()
143 }
143 }
144
144
145 pub fn is_empty(&self) -> bool {
145 pub fn is_empty(&self) -> bool {
146 self.len() == 0
146 self.len() == 0
147 }
147 }
148 }
148 }
149
149
150 /// This is basically a reimplementation of `DirsMultiset` that stores the
150 /// This is basically a reimplementation of `DirsMultiset` that stores the
151 /// children instead of just a count of them, plus a small optional
151 /// children instead of just a count of them, plus a small optional
152 /// optimization to avoid some directories we don't need.
152 /// optimization to avoid some directories we don't need.
153 #[derive(PartialEq, Debug)]
153 #[derive(PartialEq, Debug)]
154 pub struct DirsChildrenMultiset<'a> {
154 pub struct DirsChildrenMultiset<'a> {
155 inner: FastHashMap<&'a HgPath, HashSet<&'a HgPath>>,
155 inner: FastHashMap<&'a HgPath, HashSet<&'a HgPath>>,
156 only_include: Option<HashSet<&'a HgPath>>,
156 only_include: Option<HashSet<&'a HgPath>>,
157 }
157 }
158
158
159 impl<'a> DirsChildrenMultiset<'a> {
159 impl<'a> DirsChildrenMultiset<'a> {
160 pub fn new(
160 pub fn new(
161 paths: impl Iterator<Item = &'a HgPathBuf>,
161 paths: impl Iterator<Item = &'a HgPathBuf>,
162 only_include: Option<&'a HashSet<impl AsRef<HgPath> + 'a>>,
162 only_include: Option<&'a HashSet<impl AsRef<HgPath> + 'a>>,
163 ) -> Self {
163 ) -> Self {
164 let mut new = Self {
164 let mut new = Self {
165 inner: HashMap::default(),
165 inner: HashMap::default(),
166 only_include: only_include
166 only_include: only_include
167 .map(|s| s.iter().map(AsRef::as_ref).collect()),
167 .map(|s| s.iter().map(AsRef::as_ref).collect()),
168 };
168 };
169
169
170 for path in paths {
170 for path in paths {
171 new.add_path(path)
171 new.add_path(path)
172 }
172 }
173
173
174 new
174 new
175 }
175 }
176 fn add_path(&mut self, path: &'a (impl AsRef<HgPath> + 'a)) {
176 fn add_path(&mut self, path: &'a (impl AsRef<HgPath> + 'a)) {
177 if path.as_ref().is_empty() {
177 if path.as_ref().is_empty() {
178 return;
178 return;
179 }
179 }
180 for (directory, basename) in files::find_dirs_with_base(path.as_ref())
180 for (directory, basename) in files::find_dirs_with_base(path.as_ref())
181 {
181 {
182 if !self.is_dir_included(directory) {
182 if !self.is_dir_included(directory) {
183 continue;
183 continue;
184 }
184 }
185 self.inner
185 self.inner
186 .entry(directory)
186 .entry(directory)
187 .and_modify(|e| {
187 .and_modify(|e| {
188 e.insert(basename);
188 e.insert(basename);
189 })
189 })
190 .or_insert_with(|| {
190 .or_insert_with(|| {
191 let mut set = HashSet::new();
191 let mut set = HashSet::new();
192 set.insert(basename);
192 set.insert(basename);
193 set
193 set
194 });
194 });
195 }
195 }
196 }
196 }
197 fn is_dir_included(&self, dir: impl AsRef<HgPath>) -> bool {
197 fn is_dir_included(&self, dir: impl AsRef<HgPath>) -> bool {
198 match &self.only_include {
198 match &self.only_include {
199 None => false,
199 None => false,
200 Some(i) => i.contains(dir.as_ref()),
200 Some(i) => i.contains(dir.as_ref()),
201 }
201 }
202 }
202 }
203
203
204 pub fn get(
204 pub fn get(
205 &self,
205 &self,
206 path: impl AsRef<HgPath>,
206 path: impl AsRef<HgPath>,
207 ) -> Option<&HashSet<&'a HgPath>> {
207 ) -> Option<&HashSet<&'a HgPath>> {
208 self.inner.get(path.as_ref())
208 self.inner.get(path.as_ref())
209 }
209 }
210 }
210 }
211
211
212 #[cfg(test)]
212 #[cfg(test)]
213 mod tests {
213 mod tests {
214 use super::*;
214 use super::*;
215 use crate::StateMap;
215 use crate::StateMap;
216
216
217 #[test]
217 #[test]
218 fn test_delete_path_path_not_found() {
218 fn test_delete_path_path_not_found() {
219 let manifest: Vec<HgPathBuf> = vec![];
219 let manifest: Vec<HgPathBuf> = vec![];
220 let mut map = DirsMultiset::from_manifest(&manifest).unwrap();
220 let mut map = DirsMultiset::from_manifest(&manifest).unwrap();
221 let path = HgPathBuf::from_bytes(b"doesnotexist/");
221 let path = HgPathBuf::from_bytes(b"doesnotexist/");
222 assert_eq!(
222 assert_eq!(
223 Err(DirstateMapError::PathNotFound(path.to_owned())),
223 Err(DirstateMapError::PathNotFound(path.to_owned())),
224 map.delete_path(&path)
224 map.delete_path(&path)
225 );
225 );
226 }
226 }
227
227
228 #[test]
228 #[test]
229 fn test_delete_path_empty_path() {
229 fn test_delete_path_empty_path() {
230 let mut map =
230 let mut map =
231 DirsMultiset::from_manifest(&vec![HgPathBuf::new()]).unwrap();
231 DirsMultiset::from_manifest(&vec![HgPathBuf::new()]).unwrap();
232 let path = HgPath::new(b"");
232 let path = HgPath::new(b"");
233 assert_eq!(Ok(()), map.delete_path(path));
233 assert_eq!(Ok(()), map.delete_path(path));
234 assert_eq!(
234 assert_eq!(
235 Err(DirstateMapError::PathNotFound(path.to_owned())),
235 Err(DirstateMapError::PathNotFound(path.to_owned())),
236 map.delete_path(path)
236 map.delete_path(path)
237 );
237 );
238 }
238 }
239
239
240 #[test]
240 #[test]
241 fn test_delete_path_successful() {
241 fn test_delete_path_successful() {
242 let mut map = DirsMultiset {
242 let mut map = DirsMultiset {
243 inner: [("", 5), ("a", 3), ("a/b", 2), ("a/c", 1)]
243 inner: [("", 5), ("a", 3), ("a/b", 2), ("a/c", 1)]
244 .iter()
244 .iter()
245 .map(|(k, v)| (HgPathBuf::from_bytes(k.as_bytes()), *v))
245 .map(|(k, v)| (HgPathBuf::from_bytes(k.as_bytes()), *v))
246 .collect(),
246 .collect(),
247 };
247 };
248
248
249 assert_eq!(Ok(()), map.delete_path(HgPath::new(b"a/b/")));
249 assert_eq!(Ok(()), map.delete_path(HgPath::new(b"a/b/")));
250 eprintln!("{:?}", map);
250 eprintln!("{:?}", map);
251 assert_eq!(Ok(()), map.delete_path(HgPath::new(b"a/b/")));
251 assert_eq!(Ok(()), map.delete_path(HgPath::new(b"a/b/")));
252 eprintln!("{:?}", map);
252 eprintln!("{:?}", map);
253 assert_eq!(
253 assert_eq!(
254 Err(DirstateMapError::PathNotFound(HgPathBuf::from_bytes(
254 Err(DirstateMapError::PathNotFound(HgPathBuf::from_bytes(
255 b"a/b/"
255 b"a/b/"
256 ))),
256 ))),
257 map.delete_path(HgPath::new(b"a/b/"))
257 map.delete_path(HgPath::new(b"a/b/"))
258 );
258 );
259
259
260 assert_eq!(2, *map.inner.get(HgPath::new(b"a")).unwrap());
260 assert_eq!(2, *map.inner.get(HgPath::new(b"a")).unwrap());
261 assert_eq!(1, *map.inner.get(HgPath::new(b"a/c")).unwrap());
261 assert_eq!(1, *map.inner.get(HgPath::new(b"a/c")).unwrap());
262 eprintln!("{:?}", map);
262 eprintln!("{:?}", map);
263 assert_eq!(Ok(()), map.delete_path(HgPath::new(b"a/")));
263 assert_eq!(Ok(()), map.delete_path(HgPath::new(b"a/")));
264 eprintln!("{:?}", map);
264 eprintln!("{:?}", map);
265
265
266 assert_eq!(Ok(()), map.delete_path(HgPath::new(b"a/c/")));
266 assert_eq!(Ok(()), map.delete_path(HgPath::new(b"a/c/")));
267 assert_eq!(
267 assert_eq!(
268 Err(DirstateMapError::PathNotFound(HgPathBuf::from_bytes(
268 Err(DirstateMapError::PathNotFound(HgPathBuf::from_bytes(
269 b"a/c/"
269 b"a/c/"
270 ))),
270 ))),
271 map.delete_path(HgPath::new(b"a/c/"))
271 map.delete_path(HgPath::new(b"a/c/"))
272 );
272 );
273 }
273 }
274
274
275 #[test]
275 #[test]
276 fn test_add_path_empty_path() {
276 fn test_add_path_empty_path() {
277 let manifest: Vec<HgPathBuf> = vec![];
277 let manifest: Vec<HgPathBuf> = vec![];
278 let mut map = DirsMultiset::from_manifest(&manifest).unwrap();
278 let mut map = DirsMultiset::from_manifest(&manifest).unwrap();
279 let path = HgPath::new(b"");
279 let path = HgPath::new(b"");
280 map.add_path(path).unwrap();
280 map.add_path(path).unwrap();
281
281
282 assert_eq!(1, map.len());
282 assert_eq!(1, map.len());
283 }
283 }
284
284
285 #[test]
285 #[test]
286 fn test_add_path_successful() {
286 fn test_add_path_successful() {
287 let manifest: Vec<HgPathBuf> = vec![];
287 let manifest: Vec<HgPathBuf> = vec![];
288 let mut map = DirsMultiset::from_manifest(&manifest).unwrap();
288 let mut map = DirsMultiset::from_manifest(&manifest).unwrap();
289
289
290 map.add_path(HgPath::new(b"a/")).unwrap();
290 map.add_path(HgPath::new(b"a/")).unwrap();
291 assert_eq!(1, *map.inner.get(HgPath::new(b"a")).unwrap());
291 assert_eq!(1, *map.inner.get(HgPath::new(b"a")).unwrap());
292 assert_eq!(1, *map.inner.get(HgPath::new(b"")).unwrap());
292 assert_eq!(1, *map.inner.get(HgPath::new(b"")).unwrap());
293 assert_eq!(2, map.len());
293 assert_eq!(2, map.len());
294
294
295 // Non directory should be ignored
295 // Non directory should be ignored
296 map.add_path(HgPath::new(b"a")).unwrap();
296 map.add_path(HgPath::new(b"a")).unwrap();
297 assert_eq!(1, *map.inner.get(HgPath::new(b"a")).unwrap());
297 assert_eq!(1, *map.inner.get(HgPath::new(b"a")).unwrap());
298 assert_eq!(2, map.len());
298 assert_eq!(2, map.len());
299
299
300 // Non directory will still add its base
300 // Non directory will still add its base
301 map.add_path(HgPath::new(b"a/b")).unwrap();
301 map.add_path(HgPath::new(b"a/b")).unwrap();
302 assert_eq!(2, *map.inner.get(HgPath::new(b"a")).unwrap());
302 assert_eq!(2, *map.inner.get(HgPath::new(b"a")).unwrap());
303 assert_eq!(2, map.len());
303 assert_eq!(2, map.len());
304
304
305 // Duplicate path works
305 // Duplicate path works
306 map.add_path(HgPath::new(b"a/")).unwrap();
306 map.add_path(HgPath::new(b"a/")).unwrap();
307 assert_eq!(3, *map.inner.get(HgPath::new(b"a")).unwrap());
307 assert_eq!(3, *map.inner.get(HgPath::new(b"a")).unwrap());
308
308
309 // Nested dir adds to its base
309 // Nested dir adds to its base
310 map.add_path(HgPath::new(b"a/b/")).unwrap();
310 map.add_path(HgPath::new(b"a/b/")).unwrap();
311 assert_eq!(4, *map.inner.get(HgPath::new(b"a")).unwrap());
311 assert_eq!(4, *map.inner.get(HgPath::new(b"a")).unwrap());
312 assert_eq!(1, *map.inner.get(HgPath::new(b"a/b")).unwrap());
312 assert_eq!(1, *map.inner.get(HgPath::new(b"a/b")).unwrap());
313
313
314 // but not its base's base, because it already existed
314 // but not its base's base, because it already existed
315 map.add_path(HgPath::new(b"a/b/c/")).unwrap();
315 map.add_path(HgPath::new(b"a/b/c/")).unwrap();
316 assert_eq!(4, *map.inner.get(HgPath::new(b"a")).unwrap());
316 assert_eq!(4, *map.inner.get(HgPath::new(b"a")).unwrap());
317 assert_eq!(2, *map.inner.get(HgPath::new(b"a/b")).unwrap());
317 assert_eq!(2, *map.inner.get(HgPath::new(b"a/b")).unwrap());
318
318
319 map.add_path(HgPath::new(b"a/c/")).unwrap();
319 map.add_path(HgPath::new(b"a/c/")).unwrap();
320 assert_eq!(1, *map.inner.get(HgPath::new(b"a/c")).unwrap());
320 assert_eq!(1, *map.inner.get(HgPath::new(b"a/c")).unwrap());
321
321
322 let expected = DirsMultiset {
322 let expected = DirsMultiset {
323 inner: [("", 2), ("a", 5), ("a/b", 2), ("a/b/c", 1), ("a/c", 1)]
323 inner: [("", 2), ("a", 5), ("a/b", 2), ("a/b/c", 1), ("a/c", 1)]
324 .iter()
324 .iter()
325 .map(|(k, v)| (HgPathBuf::from_bytes(k.as_bytes()), *v))
325 .map(|(k, v)| (HgPathBuf::from_bytes(k.as_bytes()), *v))
326 .collect(),
326 .collect(),
327 };
327 };
328 assert_eq!(map, expected);
328 assert_eq!(map, expected);
329 }
329 }
330
330
331 #[test]
331 #[test]
332 fn test_dirsmultiset_new_empty() {
332 fn test_dirsmultiset_new_empty() {
333 let manifest: Vec<HgPathBuf> = vec![];
333 let manifest: Vec<HgPathBuf> = vec![];
334 let new = DirsMultiset::from_manifest(&manifest).unwrap();
334 let new = DirsMultiset::from_manifest(&manifest).unwrap();
335 let expected = DirsMultiset {
335 let expected = DirsMultiset {
336 inner: FastHashMap::default(),
336 inner: FastHashMap::default(),
337 };
337 };
338 assert_eq!(expected, new);
338 assert_eq!(expected, new);
339
339
340 let new =
340 let new =
341 DirsMultiset::from_dirstate(&StateMap::default(), None).unwrap();
341 DirsMultiset::from_dirstate(StateMap::default(), None).unwrap();
342 let expected = DirsMultiset {
342 let expected = DirsMultiset {
343 inner: FastHashMap::default(),
343 inner: FastHashMap::default(),
344 };
344 };
345 assert_eq!(expected, new);
345 assert_eq!(expected, new);
346 }
346 }
347
347
348 #[test]
348 #[test]
349 fn test_dirsmultiset_new_no_skip() {
349 fn test_dirsmultiset_new_no_skip() {
350 let input_vec: Vec<HgPathBuf> = ["a/", "b/", "a/c", "a/d/"]
350 let input_vec: Vec<HgPathBuf> = ["a/", "b/", "a/c", "a/d/"]
351 .iter()
351 .iter()
352 .map(|e| HgPathBuf::from_bytes(e.as_bytes()))
352 .map(|e| HgPathBuf::from_bytes(e.as_bytes()))
353 .collect();
353 .collect();
354 let expected_inner = [("", 2), ("a", 3), ("b", 1), ("a/d", 1)]
354 let expected_inner = [("", 2), ("a", 3), ("b", 1), ("a/d", 1)]
355 .iter()
355 .iter()
356 .map(|(k, v)| (HgPathBuf::from_bytes(k.as_bytes()), *v))
356 .map(|(k, v)| (HgPathBuf::from_bytes(k.as_bytes()), *v))
357 .collect();
357 .collect();
358
358
359 let new = DirsMultiset::from_manifest(&input_vec).unwrap();
359 let new = DirsMultiset::from_manifest(&input_vec).unwrap();
360 let expected = DirsMultiset {
360 let expected = DirsMultiset {
361 inner: expected_inner,
361 inner: expected_inner,
362 };
362 };
363 assert_eq!(expected, new);
363 assert_eq!(expected, new);
364
364
365 let input_map: HashMap<_, _> = ["b/x", "a/c", "a/d/x"]
365 let input_map: HashMap<_, _> = ["b/x", "a/c", "a/d/x"]
366 .iter()
366 .iter()
367 .map(|f| {
367 .map(|f| {
368 (
368 (
369 HgPathBuf::from_bytes(f.as_bytes()),
369 HgPathBuf::from_bytes(f.as_bytes()),
370 DirstateEntry {
370 DirstateEntry {
371 state: EntryState::Normal,
371 state: EntryState::Normal,
372 mode: 0,
372 mode: 0,
373 mtime: 0,
373 mtime: 0,
374 size: 0,
374 size: 0,
375 },
375 },
376 )
376 )
377 })
377 })
378 .collect();
378 .collect();
379 let expected_inner = [("", 2), ("a", 2), ("b", 1), ("a/d", 1)]
379 let expected_inner = [("", 2), ("a", 2), ("b", 1), ("a/d", 1)]
380 .iter()
380 .iter()
381 .map(|(k, v)| (HgPathBuf::from_bytes(k.as_bytes()), *v))
381 .map(|(k, v)| (HgPathBuf::from_bytes(k.as_bytes()), *v))
382 .collect();
382 .collect();
383
383
384 let new = DirsMultiset::from_dirstate(&input_map, None).unwrap();
384 let new = DirsMultiset::from_dirstate(input_map, None).unwrap();
385 let expected = DirsMultiset {
385 let expected = DirsMultiset {
386 inner: expected_inner,
386 inner: expected_inner,
387 };
387 };
388 assert_eq!(expected, new);
388 assert_eq!(expected, new);
389 }
389 }
390
390
391 #[test]
391 #[test]
392 fn test_dirsmultiset_new_skip() {
392 fn test_dirsmultiset_new_skip() {
393 let input_map: HashMap<_, _> = [
393 let input_map: HashMap<_, _> = [
394 ("a/", EntryState::Normal),
394 ("a/", EntryState::Normal),
395 ("a/b", EntryState::Normal),
395 ("a/b", EntryState::Normal),
396 ("a/c", EntryState::Removed),
396 ("a/c", EntryState::Removed),
397 ("a/d", EntryState::Merged),
397 ("a/d", EntryState::Merged),
398 ]
398 ]
399 .iter()
399 .iter()
400 .map(|(f, state)| {
400 .map(|(f, state)| {
401 (
401 (
402 HgPathBuf::from_bytes(f.as_bytes()),
402 HgPathBuf::from_bytes(f.as_bytes()),
403 DirstateEntry {
403 DirstateEntry {
404 state: *state,
404 state: *state,
405 mode: 0,
405 mode: 0,
406 mtime: 0,
406 mtime: 0,
407 size: 0,
407 size: 0,
408 },
408 },
409 )
409 )
410 })
410 })
411 .collect();
411 .collect();
412
412
413 // "a" incremented with "a/c" and "a/d/"
413 // "a" incremented with "a/c" and "a/d/"
414 let expected_inner = [("", 1), ("a", 2)]
414 let expected_inner = [("", 1), ("a", 2)]
415 .iter()
415 .iter()
416 .map(|(k, v)| (HgPathBuf::from_bytes(k.as_bytes()), *v))
416 .map(|(k, v)| (HgPathBuf::from_bytes(k.as_bytes()), *v))
417 .collect();
417 .collect();
418
418
419 let new =
419 let new =
420 DirsMultiset::from_dirstate(&input_map, Some(EntryState::Normal))
420 DirsMultiset::from_dirstate(input_map, Some(EntryState::Normal))
421 .unwrap();
421 .unwrap();
422 let expected = DirsMultiset {
422 let expected = DirsMultiset {
423 inner: expected_inner,
423 inner: expected_inner,
424 };
424 };
425 assert_eq!(expected, new);
425 assert_eq!(expected, new);
426 }
426 }
427 }
427 }
@@ -1,407 +1,407 b''
1 // dirstate_map.rs
1 // dirstate_map.rs
2 //
2 //
3 // Copyright 2019 Raphaël Gomès <rgomes@octobus.net>
3 // Copyright 2019 Raphaël Gomès <rgomes@octobus.net>
4 //
4 //
5 // This software may be used and distributed according to the terms of the
5 // This software may be used and distributed according to the terms of the
6 // GNU General Public License version 2 or any later version.
6 // GNU General Public License version 2 or any later version.
7
7
8 use crate::dirstate::parsers::Timestamp;
8 use crate::dirstate::parsers::Timestamp;
9 use crate::{
9 use crate::{
10 dirstate::EntryState,
10 dirstate::EntryState,
11 pack_dirstate, parse_dirstate,
11 pack_dirstate, parse_dirstate,
12 utils::hg_path::{HgPath, HgPathBuf},
12 utils::hg_path::{HgPath, HgPathBuf},
13 CopyMap, DirsMultiset, DirstateEntry, DirstateError, DirstateMapError,
13 CopyMap, DirsMultiset, DirstateEntry, DirstateError, DirstateMapError,
14 DirstateParents, StateMap,
14 DirstateParents, StateMap,
15 };
15 };
16 use micro_timer::timed;
16 use micro_timer::timed;
17 use std::collections::HashSet;
17 use std::collections::HashSet;
18 use std::iter::FromIterator;
18 use std::iter::FromIterator;
19 use std::ops::Deref;
19 use std::ops::Deref;
20
20
21 #[derive(Default)]
21 #[derive(Default)]
22 pub struct DirstateMap {
22 pub struct DirstateMap {
23 state_map: StateMap,
23 state_map: StateMap,
24 pub copy_map: CopyMap,
24 pub copy_map: CopyMap,
25 pub dirs: Option<DirsMultiset>,
25 pub dirs: Option<DirsMultiset>,
26 pub all_dirs: Option<DirsMultiset>,
26 pub all_dirs: Option<DirsMultiset>,
27 non_normal_set: Option<HashSet<HgPathBuf>>,
27 non_normal_set: Option<HashSet<HgPathBuf>>,
28 other_parent_set: Option<HashSet<HgPathBuf>>,
28 other_parent_set: Option<HashSet<HgPathBuf>>,
29 }
29 }
30
30
31 /// Should only really be used in python interface code, for clarity
31 /// Should only really be used in python interface code, for clarity
32 impl Deref for DirstateMap {
32 impl Deref for DirstateMap {
33 type Target = StateMap;
33 type Target = StateMap;
34
34
35 fn deref(&self) -> &Self::Target {
35 fn deref(&self) -> &Self::Target {
36 &self.state_map
36 &self.state_map
37 }
37 }
38 }
38 }
39
39
40 impl FromIterator<(HgPathBuf, DirstateEntry)> for DirstateMap {
40 impl FromIterator<(HgPathBuf, DirstateEntry)> for DirstateMap {
41 fn from_iter<I: IntoIterator<Item = (HgPathBuf, DirstateEntry)>>(
41 fn from_iter<I: IntoIterator<Item = (HgPathBuf, DirstateEntry)>>(
42 iter: I,
42 iter: I,
43 ) -> Self {
43 ) -> Self {
44 Self {
44 Self {
45 state_map: iter.into_iter().collect(),
45 state_map: iter.into_iter().collect(),
46 ..Self::default()
46 ..Self::default()
47 }
47 }
48 }
48 }
49 }
49 }
50
50
51 impl DirstateMap {
51 impl DirstateMap {
52 pub fn new() -> Self {
52 pub fn new() -> Self {
53 Self::default()
53 Self::default()
54 }
54 }
55
55
56 pub fn clear(&mut self) {
56 pub fn clear(&mut self) {
57 self.state_map = StateMap::default();
57 self.state_map = StateMap::default();
58 self.copy_map.clear();
58 self.copy_map.clear();
59 self.non_normal_set = None;
59 self.non_normal_set = None;
60 self.other_parent_set = None;
60 self.other_parent_set = None;
61 }
61 }
62
62
63 /// Add a tracked file to the dirstate
63 /// Add a tracked file to the dirstate
64 pub fn add_file(
64 pub fn add_file(
65 &mut self,
65 &mut self,
66 filename: &HgPath,
66 filename: &HgPath,
67 old_state: EntryState,
67 old_state: EntryState,
68 entry: DirstateEntry,
68 entry: DirstateEntry,
69 ) -> Result<(), DirstateMapError> {
69 ) -> Result<(), DirstateMapError> {
70 if old_state == EntryState::Unknown || old_state == EntryState::Removed
70 if old_state == EntryState::Unknown || old_state == EntryState::Removed
71 {
71 {
72 if let Some(ref mut dirs) = self.dirs {
72 if let Some(ref mut dirs) = self.dirs {
73 dirs.add_path(filename)?;
73 dirs.add_path(filename)?;
74 }
74 }
75 }
75 }
76 if old_state == EntryState::Unknown {
76 if old_state == EntryState::Unknown {
77 if let Some(ref mut all_dirs) = self.all_dirs {
77 if let Some(ref mut all_dirs) = self.all_dirs {
78 all_dirs.add_path(filename)?;
78 all_dirs.add_path(filename)?;
79 }
79 }
80 }
80 }
81 self.state_map.insert(filename.to_owned(), entry.to_owned());
81 self.state_map.insert(filename.to_owned(), entry.to_owned());
82
82
83 if entry.is_non_normal() {
83 if entry.is_non_normal() {
84 self.get_non_normal_other_parent_entries()
84 self.get_non_normal_other_parent_entries()
85 .0
85 .0
86 .insert(filename.to_owned());
86 .insert(filename.to_owned());
87 }
87 }
88
88
89 if entry.is_from_other_parent() {
89 if entry.is_from_other_parent() {
90 self.get_non_normal_other_parent_entries()
90 self.get_non_normal_other_parent_entries()
91 .1
91 .1
92 .insert(filename.to_owned());
92 .insert(filename.to_owned());
93 }
93 }
94 Ok(())
94 Ok(())
95 }
95 }
96
96
97 /// Mark a file as removed in the dirstate.
97 /// Mark a file as removed in the dirstate.
98 ///
98 ///
99 /// The `size` parameter is used to store sentinel values that indicate
99 /// The `size` parameter is used to store sentinel values that indicate
100 /// the file's previous state. In the future, we should refactor this
100 /// the file's previous state. In the future, we should refactor this
101 /// to be more explicit about what that state is.
101 /// to be more explicit about what that state is.
102 pub fn remove_file(
102 pub fn remove_file(
103 &mut self,
103 &mut self,
104 filename: &HgPath,
104 filename: &HgPath,
105 old_state: EntryState,
105 old_state: EntryState,
106 size: i32,
106 size: i32,
107 ) -> Result<(), DirstateMapError> {
107 ) -> Result<(), DirstateMapError> {
108 if old_state != EntryState::Unknown && old_state != EntryState::Removed
108 if old_state != EntryState::Unknown && old_state != EntryState::Removed
109 {
109 {
110 if let Some(ref mut dirs) = self.dirs {
110 if let Some(ref mut dirs) = self.dirs {
111 dirs.delete_path(filename)?;
111 dirs.delete_path(filename)?;
112 }
112 }
113 }
113 }
114 if old_state == EntryState::Unknown {
114 if old_state == EntryState::Unknown {
115 if let Some(ref mut all_dirs) = self.all_dirs {
115 if let Some(ref mut all_dirs) = self.all_dirs {
116 all_dirs.add_path(filename)?;
116 all_dirs.add_path(filename)?;
117 }
117 }
118 }
118 }
119
119
120 self.state_map.insert(
120 self.state_map.insert(
121 filename.to_owned(),
121 filename.to_owned(),
122 DirstateEntry {
122 DirstateEntry {
123 state: EntryState::Removed,
123 state: EntryState::Removed,
124 mode: 0,
124 mode: 0,
125 size,
125 size,
126 mtime: 0,
126 mtime: 0,
127 },
127 },
128 );
128 );
129 self.get_non_normal_other_parent_entries()
129 self.get_non_normal_other_parent_entries()
130 .0
130 .0
131 .insert(filename.to_owned());
131 .insert(filename.to_owned());
132 Ok(())
132 Ok(())
133 }
133 }
134
134
135 /// Remove a file from the dirstate.
135 /// Remove a file from the dirstate.
136 /// Returns `true` if the file was previously recorded.
136 /// Returns `true` if the file was previously recorded.
137 pub fn drop_file(
137 pub fn drop_file(
138 &mut self,
138 &mut self,
139 filename: &HgPath,
139 filename: &HgPath,
140 old_state: EntryState,
140 old_state: EntryState,
141 ) -> Result<bool, DirstateMapError> {
141 ) -> Result<bool, DirstateMapError> {
142 let exists = self.state_map.remove(filename).is_some();
142 let exists = self.state_map.remove(filename).is_some();
143
143
144 if exists {
144 if exists {
145 if old_state != EntryState::Removed {
145 if old_state != EntryState::Removed {
146 if let Some(ref mut dirs) = self.dirs {
146 if let Some(ref mut dirs) = self.dirs {
147 dirs.delete_path(filename)?;
147 dirs.delete_path(filename)?;
148 }
148 }
149 }
149 }
150 if let Some(ref mut all_dirs) = self.all_dirs {
150 if let Some(ref mut all_dirs) = self.all_dirs {
151 all_dirs.delete_path(filename)?;
151 all_dirs.delete_path(filename)?;
152 }
152 }
153 }
153 }
154 self.get_non_normal_other_parent_entries()
154 self.get_non_normal_other_parent_entries()
155 .0
155 .0
156 .remove(filename);
156 .remove(filename);
157
157
158 Ok(exists)
158 Ok(exists)
159 }
159 }
160
160
161 pub fn clear_ambiguous_times(
161 pub fn clear_ambiguous_times(
162 &mut self,
162 &mut self,
163 filenames: Vec<HgPathBuf>,
163 filenames: Vec<HgPathBuf>,
164 now: i32,
164 now: i32,
165 ) {
165 ) {
166 for filename in filenames {
166 for filename in filenames {
167 if let Some(entry) = self.state_map.get_mut(&filename) {
167 if let Some(entry) = self.state_map.get_mut(&filename) {
168 if entry.clear_ambiguous_mtime(now) {
168 if entry.clear_ambiguous_mtime(now) {
169 self.get_non_normal_other_parent_entries()
169 self.get_non_normal_other_parent_entries()
170 .0
170 .0
171 .insert(filename.to_owned());
171 .insert(filename.to_owned());
172 }
172 }
173 }
173 }
174 }
174 }
175 }
175 }
176
176
177 pub fn non_normal_entries_remove(&mut self, key: impl AsRef<HgPath>) {
177 pub fn non_normal_entries_remove(&mut self, key: impl AsRef<HgPath>) {
178 self.get_non_normal_other_parent_entries()
178 self.get_non_normal_other_parent_entries()
179 .0
179 .0
180 .remove(key.as_ref());
180 .remove(key.as_ref());
181 }
181 }
182
182
183 pub fn non_normal_entries_union(
183 pub fn non_normal_entries_union(
184 &mut self,
184 &mut self,
185 other: HashSet<HgPathBuf>,
185 other: HashSet<HgPathBuf>,
186 ) -> Vec<HgPathBuf> {
186 ) -> Vec<HgPathBuf> {
187 self.get_non_normal_other_parent_entries()
187 self.get_non_normal_other_parent_entries()
188 .0
188 .0
189 .union(&other)
189 .union(&other)
190 .map(ToOwned::to_owned)
190 .map(ToOwned::to_owned)
191 .collect()
191 .collect()
192 }
192 }
193
193
194 pub fn get_non_normal_other_parent_entries(
194 pub fn get_non_normal_other_parent_entries(
195 &mut self,
195 &mut self,
196 ) -> (&mut HashSet<HgPathBuf>, &mut HashSet<HgPathBuf>) {
196 ) -> (&mut HashSet<HgPathBuf>, &mut HashSet<HgPathBuf>) {
197 self.set_non_normal_other_parent_entries(false);
197 self.set_non_normal_other_parent_entries(false);
198 (
198 (
199 self.non_normal_set.as_mut().unwrap(),
199 self.non_normal_set.as_mut().unwrap(),
200 self.other_parent_set.as_mut().unwrap(),
200 self.other_parent_set.as_mut().unwrap(),
201 )
201 )
202 }
202 }
203
203
204 /// Useful to get immutable references to those sets in contexts where
204 /// Useful to get immutable references to those sets in contexts where
205 /// you only have an immutable reference to the `DirstateMap`, like when
205 /// you only have an immutable reference to the `DirstateMap`, like when
206 /// sharing references with Python.
206 /// sharing references with Python.
207 ///
207 ///
208 /// TODO, get rid of this along with the other "setter/getter" stuff when
208 /// TODO, get rid of this along with the other "setter/getter" stuff when
209 /// a nice typestate plan is defined.
209 /// a nice typestate plan is defined.
210 ///
210 ///
211 /// # Panics
211 /// # Panics
212 ///
212 ///
213 /// Will panic if either set is `None`.
213 /// Will panic if either set is `None`.
214 pub fn get_non_normal_other_parent_entries_panic(
214 pub fn get_non_normal_other_parent_entries_panic(
215 &self,
215 &self,
216 ) -> (&HashSet<HgPathBuf>, &HashSet<HgPathBuf>) {
216 ) -> (&HashSet<HgPathBuf>, &HashSet<HgPathBuf>) {
217 (
217 (
218 self.non_normal_set.as_ref().unwrap(),
218 self.non_normal_set.as_ref().unwrap(),
219 self.other_parent_set.as_ref().unwrap(),
219 self.other_parent_set.as_ref().unwrap(),
220 )
220 )
221 }
221 }
222
222
223 pub fn set_non_normal_other_parent_entries(&mut self, force: bool) {
223 pub fn set_non_normal_other_parent_entries(&mut self, force: bool) {
224 if !force
224 if !force
225 && self.non_normal_set.is_some()
225 && self.non_normal_set.is_some()
226 && self.other_parent_set.is_some()
226 && self.other_parent_set.is_some()
227 {
227 {
228 return;
228 return;
229 }
229 }
230 let mut non_normal = HashSet::new();
230 let mut non_normal = HashSet::new();
231 let mut other_parent = HashSet::new();
231 let mut other_parent = HashSet::new();
232
232
233 for (filename, entry) in self.state_map.iter() {
233 for (filename, entry) in self.state_map.iter() {
234 if entry.is_non_normal() {
234 if entry.is_non_normal() {
235 non_normal.insert(filename.to_owned());
235 non_normal.insert(filename.to_owned());
236 }
236 }
237 if entry.is_from_other_parent() {
237 if entry.is_from_other_parent() {
238 other_parent.insert(filename.to_owned());
238 other_parent.insert(filename.to_owned());
239 }
239 }
240 }
240 }
241 self.non_normal_set = Some(non_normal);
241 self.non_normal_set = Some(non_normal);
242 self.other_parent_set = Some(other_parent);
242 self.other_parent_set = Some(other_parent);
243 }
243 }
244
244
245 /// Both of these setters and their uses appear to be the simplest way to
245 /// Both of these setters and their uses appear to be the simplest way to
246 /// emulate a Python lazy property, but it is ugly and unidiomatic.
246 /// emulate a Python lazy property, but it is ugly and unidiomatic.
247 /// TODO One day, rewriting this struct using the typestate might be a
247 /// TODO One day, rewriting this struct using the typestate might be a
248 /// good idea.
248 /// good idea.
249 pub fn set_all_dirs(&mut self) -> Result<(), DirstateMapError> {
249 pub fn set_all_dirs(&mut self) -> Result<(), DirstateMapError> {
250 if self.all_dirs.is_none() {
250 if self.all_dirs.is_none() {
251 self.all_dirs = Some(DirsMultiset::from_dirstate(
251 self.all_dirs = Some(DirsMultiset::from_dirstate(
252 self.state_map.iter(),
252 self.state_map.iter().map(|(k, v)| (k, *v)),
253 None,
253 None,
254 )?);
254 )?);
255 }
255 }
256 Ok(())
256 Ok(())
257 }
257 }
258
258
259 pub fn set_dirs(&mut self) -> Result<(), DirstateMapError> {
259 pub fn set_dirs(&mut self) -> Result<(), DirstateMapError> {
260 if self.dirs.is_none() {
260 if self.dirs.is_none() {
261 self.dirs = Some(DirsMultiset::from_dirstate(
261 self.dirs = Some(DirsMultiset::from_dirstate(
262 self.state_map.iter(),
262 self.state_map.iter().map(|(k, v)| (k, *v)),
263 Some(EntryState::Removed),
263 Some(EntryState::Removed),
264 )?);
264 )?);
265 }
265 }
266 Ok(())
266 Ok(())
267 }
267 }
268
268
269 pub fn has_tracked_dir(
269 pub fn has_tracked_dir(
270 &mut self,
270 &mut self,
271 directory: &HgPath,
271 directory: &HgPath,
272 ) -> Result<bool, DirstateMapError> {
272 ) -> Result<bool, DirstateMapError> {
273 self.set_dirs()?;
273 self.set_dirs()?;
274 Ok(self.dirs.as_ref().unwrap().contains(directory))
274 Ok(self.dirs.as_ref().unwrap().contains(directory))
275 }
275 }
276
276
277 pub fn has_dir(
277 pub fn has_dir(
278 &mut self,
278 &mut self,
279 directory: &HgPath,
279 directory: &HgPath,
280 ) -> Result<bool, DirstateMapError> {
280 ) -> Result<bool, DirstateMapError> {
281 self.set_all_dirs()?;
281 self.set_all_dirs()?;
282 Ok(self.all_dirs.as_ref().unwrap().contains(directory))
282 Ok(self.all_dirs.as_ref().unwrap().contains(directory))
283 }
283 }
284
284
285 #[timed]
285 #[timed]
286 pub fn read(
286 pub fn read(
287 &mut self,
287 &mut self,
288 file_contents: &[u8],
288 file_contents: &[u8],
289 ) -> Result<Option<DirstateParents>, DirstateError> {
289 ) -> Result<Option<DirstateParents>, DirstateError> {
290 if file_contents.is_empty() {
290 if file_contents.is_empty() {
291 return Ok(None);
291 return Ok(None);
292 }
292 }
293
293
294 let (parents, entries, copies) = parse_dirstate(file_contents)?;
294 let (parents, entries, copies) = parse_dirstate(file_contents)?;
295 self.state_map.extend(
295 self.state_map.extend(
296 entries
296 entries
297 .into_iter()
297 .into_iter()
298 .map(|(path, entry)| (path.to_owned(), entry)),
298 .map(|(path, entry)| (path.to_owned(), entry)),
299 );
299 );
300 self.copy_map.extend(
300 self.copy_map.extend(
301 copies
301 copies
302 .into_iter()
302 .into_iter()
303 .map(|(path, copy)| (path.to_owned(), copy.to_owned())),
303 .map(|(path, copy)| (path.to_owned(), copy.to_owned())),
304 );
304 );
305 Ok(Some(parents.clone()))
305 Ok(Some(parents.clone()))
306 }
306 }
307
307
308 pub fn pack(
308 pub fn pack(
309 &mut self,
309 &mut self,
310 parents: DirstateParents,
310 parents: DirstateParents,
311 now: Timestamp,
311 now: Timestamp,
312 ) -> Result<Vec<u8>, DirstateError> {
312 ) -> Result<Vec<u8>, DirstateError> {
313 let packed =
313 let packed =
314 pack_dirstate(&mut self.state_map, &self.copy_map, parents, now)?;
314 pack_dirstate(&mut self.state_map, &self.copy_map, parents, now)?;
315
315
316 self.set_non_normal_other_parent_entries(true);
316 self.set_non_normal_other_parent_entries(true);
317 Ok(packed)
317 Ok(packed)
318 }
318 }
319 }
319 }
320
320
321 #[cfg(test)]
321 #[cfg(test)]
322 mod tests {
322 mod tests {
323 use super::*;
323 use super::*;
324
324
325 #[test]
325 #[test]
326 fn test_dirs_multiset() {
326 fn test_dirs_multiset() {
327 let mut map = DirstateMap::new();
327 let mut map = DirstateMap::new();
328 assert!(map.dirs.is_none());
328 assert!(map.dirs.is_none());
329 assert!(map.all_dirs.is_none());
329 assert!(map.all_dirs.is_none());
330
330
331 assert_eq!(map.has_dir(HgPath::new(b"nope")).unwrap(), false);
331 assert_eq!(map.has_dir(HgPath::new(b"nope")).unwrap(), false);
332 assert!(map.all_dirs.is_some());
332 assert!(map.all_dirs.is_some());
333 assert!(map.dirs.is_none());
333 assert!(map.dirs.is_none());
334
334
335 assert_eq!(map.has_tracked_dir(HgPath::new(b"nope")).unwrap(), false);
335 assert_eq!(map.has_tracked_dir(HgPath::new(b"nope")).unwrap(), false);
336 assert!(map.dirs.is_some());
336 assert!(map.dirs.is_some());
337 }
337 }
338
338
339 #[test]
339 #[test]
340 fn test_add_file() {
340 fn test_add_file() {
341 let mut map = DirstateMap::new();
341 let mut map = DirstateMap::new();
342
342
343 assert_eq!(0, map.len());
343 assert_eq!(0, map.len());
344
344
345 map.add_file(
345 map.add_file(
346 HgPath::new(b"meh"),
346 HgPath::new(b"meh"),
347 EntryState::Normal,
347 EntryState::Normal,
348 DirstateEntry {
348 DirstateEntry {
349 state: EntryState::Normal,
349 state: EntryState::Normal,
350 mode: 1337,
350 mode: 1337,
351 mtime: 1337,
351 mtime: 1337,
352 size: 1337,
352 size: 1337,
353 },
353 },
354 )
354 )
355 .unwrap();
355 .unwrap();
356
356
357 assert_eq!(1, map.len());
357 assert_eq!(1, map.len());
358 assert_eq!(0, map.get_non_normal_other_parent_entries().0.len());
358 assert_eq!(0, map.get_non_normal_other_parent_entries().0.len());
359 assert_eq!(0, map.get_non_normal_other_parent_entries().1.len());
359 assert_eq!(0, map.get_non_normal_other_parent_entries().1.len());
360 }
360 }
361
361
362 #[test]
362 #[test]
363 fn test_non_normal_other_parent_entries() {
363 fn test_non_normal_other_parent_entries() {
364 let mut map: DirstateMap = [
364 let mut map: DirstateMap = [
365 (b"f1", (EntryState::Removed, 1337, 1337, 1337)),
365 (b"f1", (EntryState::Removed, 1337, 1337, 1337)),
366 (b"f2", (EntryState::Normal, 1337, 1337, -1)),
366 (b"f2", (EntryState::Normal, 1337, 1337, -1)),
367 (b"f3", (EntryState::Normal, 1337, 1337, 1337)),
367 (b"f3", (EntryState::Normal, 1337, 1337, 1337)),
368 (b"f4", (EntryState::Normal, 1337, -2, 1337)),
368 (b"f4", (EntryState::Normal, 1337, -2, 1337)),
369 (b"f5", (EntryState::Added, 1337, 1337, 1337)),
369 (b"f5", (EntryState::Added, 1337, 1337, 1337)),
370 (b"f6", (EntryState::Added, 1337, 1337, -1)),
370 (b"f6", (EntryState::Added, 1337, 1337, -1)),
371 (b"f7", (EntryState::Merged, 1337, 1337, -1)),
371 (b"f7", (EntryState::Merged, 1337, 1337, -1)),
372 (b"f8", (EntryState::Merged, 1337, 1337, 1337)),
372 (b"f8", (EntryState::Merged, 1337, 1337, 1337)),
373 (b"f9", (EntryState::Merged, 1337, -2, 1337)),
373 (b"f9", (EntryState::Merged, 1337, -2, 1337)),
374 (b"fa", (EntryState::Added, 1337, -2, 1337)),
374 (b"fa", (EntryState::Added, 1337, -2, 1337)),
375 (b"fb", (EntryState::Removed, 1337, -2, 1337)),
375 (b"fb", (EntryState::Removed, 1337, -2, 1337)),
376 ]
376 ]
377 .iter()
377 .iter()
378 .map(|(fname, (state, mode, size, mtime))| {
378 .map(|(fname, (state, mode, size, mtime))| {
379 (
379 (
380 HgPathBuf::from_bytes(fname.as_ref()),
380 HgPathBuf::from_bytes(fname.as_ref()),
381 DirstateEntry {
381 DirstateEntry {
382 state: *state,
382 state: *state,
383 mode: *mode,
383 mode: *mode,
384 size: *size,
384 size: *size,
385 mtime: *mtime,
385 mtime: *mtime,
386 },
386 },
387 )
387 )
388 })
388 })
389 .collect();
389 .collect();
390
390
391 let mut non_normal = [
391 let mut non_normal = [
392 b"f1", b"f2", b"f5", b"f6", b"f7", b"f8", b"f9", b"fa", b"fb",
392 b"f1", b"f2", b"f5", b"f6", b"f7", b"f8", b"f9", b"fa", b"fb",
393 ]
393 ]
394 .iter()
394 .iter()
395 .map(|x| HgPathBuf::from_bytes(x.as_ref()))
395 .map(|x| HgPathBuf::from_bytes(x.as_ref()))
396 .collect();
396 .collect();
397
397
398 let mut other_parent = HashSet::new();
398 let mut other_parent = HashSet::new();
399 other_parent.insert(HgPathBuf::from_bytes(b"f4"));
399 other_parent.insert(HgPathBuf::from_bytes(b"f4"));
400 let entries = map.get_non_normal_other_parent_entries();
400 let entries = map.get_non_normal_other_parent_entries();
401
401
402 assert_eq!(
402 assert_eq!(
403 (&mut non_normal, &mut other_parent),
403 (&mut non_normal, &mut other_parent),
404 (entries.0, entries.1)
404 (entries.0, entries.1)
405 );
405 );
406 }
406 }
407 }
407 }
@@ -1,639 +1,639 b''
1 use bytes_cast::BytesCast;
1 use bytes_cast::BytesCast;
2 use micro_timer::timed;
2 use micro_timer::timed;
3 use std::borrow::Cow;
3 use std::borrow::Cow;
4 use std::convert::TryInto;
4 use std::convert::TryInto;
5 use std::path::PathBuf;
5 use std::path::PathBuf;
6
6
7 use super::on_disk;
7 use super::on_disk;
8 use super::path_with_basename::WithBasename;
8 use super::path_with_basename::WithBasename;
9 use crate::dirstate::parsers::pack_entry;
9 use crate::dirstate::parsers::pack_entry;
10 use crate::dirstate::parsers::packed_entry_size;
10 use crate::dirstate::parsers::packed_entry_size;
11 use crate::dirstate::parsers::parse_dirstate_entries;
11 use crate::dirstate::parsers::parse_dirstate_entries;
12 use crate::dirstate::parsers::Timestamp;
12 use crate::dirstate::parsers::Timestamp;
13 use crate::matchers::Matcher;
13 use crate::matchers::Matcher;
14 use crate::utils::hg_path::{HgPath, HgPathBuf};
14 use crate::utils::hg_path::{HgPath, HgPathBuf};
15 use crate::CopyMapIter;
15 use crate::CopyMapIter;
16 use crate::DirstateEntry;
16 use crate::DirstateEntry;
17 use crate::DirstateError;
17 use crate::DirstateError;
18 use crate::DirstateMapError;
18 use crate::DirstateMapError;
19 use crate::DirstateParents;
19 use crate::DirstateParents;
20 use crate::DirstateStatus;
20 use crate::DirstateStatus;
21 use crate::EntryState;
21 use crate::EntryState;
22 use crate::FastHashMap;
22 use crate::FastHashMap;
23 use crate::PatternFileWarning;
23 use crate::PatternFileWarning;
24 use crate::StateMapIter;
24 use crate::StateMapIter;
25 use crate::StatusError;
25 use crate::StatusError;
26 use crate::StatusOptions;
26 use crate::StatusOptions;
27
27
28 pub struct DirstateMap<'on_disk> {
28 pub struct DirstateMap<'on_disk> {
29 /// Contents of the `.hg/dirstate` file
29 /// Contents of the `.hg/dirstate` file
30 pub(super) on_disk: &'on_disk [u8],
30 pub(super) on_disk: &'on_disk [u8],
31
31
32 pub(super) root: ChildNodes<'on_disk>,
32 pub(super) root: ChildNodes<'on_disk>,
33
33
34 /// Number of nodes anywhere in the tree that have `.entry.is_some()`.
34 /// Number of nodes anywhere in the tree that have `.entry.is_some()`.
35 pub(super) nodes_with_entry_count: u32,
35 pub(super) nodes_with_entry_count: u32,
36
36
37 /// Number of nodes anywhere in the tree that have
37 /// Number of nodes anywhere in the tree that have
38 /// `.copy_source.is_some()`.
38 /// `.copy_source.is_some()`.
39 pub(super) nodes_with_copy_source_count: u32,
39 pub(super) nodes_with_copy_source_count: u32,
40 }
40 }
41
41
42 /// Using a plain `HgPathBuf` of the full path from the repository root as a
42 /// Using a plain `HgPathBuf` of the full path from the repository root as a
43 /// map key would also work: all paths in a given map have the same parent
43 /// map key would also work: all paths in a given map have the same parent
44 /// path, so comparing full paths gives the same result as comparing base
44 /// path, so comparing full paths gives the same result as comparing base
45 /// names. However `HashMap` would waste time always re-hashing the same
45 /// names. However `HashMap` would waste time always re-hashing the same
46 /// string prefix.
46 /// string prefix.
47 pub(super) type NodeKey<'on_disk> = WithBasename<Cow<'on_disk, HgPath>>;
47 pub(super) type NodeKey<'on_disk> = WithBasename<Cow<'on_disk, HgPath>>;
48 pub(super) type ChildNodes<'on_disk> =
48 pub(super) type ChildNodes<'on_disk> =
49 FastHashMap<NodeKey<'on_disk>, Node<'on_disk>>;
49 FastHashMap<NodeKey<'on_disk>, Node<'on_disk>>;
50
50
51 /// Represents a file or a directory
51 /// Represents a file or a directory
52 #[derive(Default)]
52 #[derive(Default)]
53 pub(super) struct Node<'on_disk> {
53 pub(super) struct Node<'on_disk> {
54 /// `None` for directories
54 /// `None` for directories
55 pub(super) entry: Option<DirstateEntry>,
55 pub(super) entry: Option<DirstateEntry>,
56
56
57 pub(super) copy_source: Option<Cow<'on_disk, HgPath>>,
57 pub(super) copy_source: Option<Cow<'on_disk, HgPath>>,
58
58
59 pub(super) children: ChildNodes<'on_disk>,
59 pub(super) children: ChildNodes<'on_disk>,
60
60
61 /// How many (non-inclusive) descendants of this node are tracked files
61 /// How many (non-inclusive) descendants of this node are tracked files
62 pub(super) tracked_descendants_count: u32,
62 pub(super) tracked_descendants_count: u32,
63 }
63 }
64
64
65 impl<'on_disk> Node<'on_disk> {
65 impl<'on_disk> Node<'on_disk> {
66 pub(super) fn state(&self) -> Option<EntryState> {
66 pub(super) fn state(&self) -> Option<EntryState> {
67 self.entry.as_ref().map(|entry| entry.state)
67 self.entry.as_ref().map(|entry| entry.state)
68 }
68 }
69
69
70 pub(super) fn sorted<'tree>(
70 pub(super) fn sorted<'tree>(
71 nodes: &'tree ChildNodes<'on_disk>,
71 nodes: &'tree ChildNodes<'on_disk>,
72 ) -> Vec<(&'tree NodeKey<'on_disk>, &'tree Self)> {
72 ) -> Vec<(&'tree NodeKey<'on_disk>, &'tree Self)> {
73 let mut vec: Vec<_> = nodes.iter().collect();
73 let mut vec: Vec<_> = nodes.iter().collect();
74 // `sort_unstable_by_key` doesn’t allow keys borrowing from the value:
74 // `sort_unstable_by_key` doesn’t allow keys borrowing from the value:
75 // https://github.com/rust-lang/rust/issues/34162
75 // https://github.com/rust-lang/rust/issues/34162
76 vec.sort_unstable_by(|(path1, _), (path2, _)| path1.cmp(path2));
76 vec.sort_unstable_by(|(path1, _), (path2, _)| path1.cmp(path2));
77 vec
77 vec
78 }
78 }
79 }
79 }
80
80
81 impl<'on_disk> DirstateMap<'on_disk> {
81 impl<'on_disk> DirstateMap<'on_disk> {
82 pub(super) fn empty(on_disk: &'on_disk [u8]) -> Self {
82 pub(super) fn empty(on_disk: &'on_disk [u8]) -> Self {
83 Self {
83 Self {
84 on_disk,
84 on_disk,
85 root: ChildNodes::default(),
85 root: ChildNodes::default(),
86 nodes_with_entry_count: 0,
86 nodes_with_entry_count: 0,
87 nodes_with_copy_source_count: 0,
87 nodes_with_copy_source_count: 0,
88 }
88 }
89 }
89 }
90
90
91 #[timed]
91 #[timed]
92 pub fn new_v2(
92 pub fn new_v2(
93 on_disk: &'on_disk [u8],
93 on_disk: &'on_disk [u8],
94 ) -> Result<(Self, Option<DirstateParents>), DirstateError> {
94 ) -> Result<(Self, Option<DirstateParents>), DirstateError> {
95 on_disk::read(on_disk)
95 on_disk::read(on_disk)
96 }
96 }
97
97
98 #[timed]
98 #[timed]
99 pub fn new_v1(
99 pub fn new_v1(
100 on_disk: &'on_disk [u8],
100 on_disk: &'on_disk [u8],
101 ) -> Result<(Self, Option<DirstateParents>), DirstateError> {
101 ) -> Result<(Self, Option<DirstateParents>), DirstateError> {
102 let mut map = Self::empty(on_disk);
102 let mut map = Self::empty(on_disk);
103 if map.on_disk.is_empty() {
103 if map.on_disk.is_empty() {
104 return Ok((map, None));
104 return Ok((map, None));
105 }
105 }
106
106
107 let parents = parse_dirstate_entries(
107 let parents = parse_dirstate_entries(
108 map.on_disk,
108 map.on_disk,
109 |path, entry, copy_source| {
109 |path, entry, copy_source| {
110 let tracked = entry.state.is_tracked();
110 let tracked = entry.state.is_tracked();
111 let node = Self::get_or_insert_node(
111 let node = Self::get_or_insert_node(
112 &mut map.root,
112 &mut map.root,
113 path,
113 path,
114 WithBasename::to_cow_borrowed,
114 WithBasename::to_cow_borrowed,
115 |ancestor| {
115 |ancestor| {
116 if tracked {
116 if tracked {
117 ancestor.tracked_descendants_count += 1
117 ancestor.tracked_descendants_count += 1
118 }
118 }
119 },
119 },
120 );
120 );
121 assert!(
121 assert!(
122 node.entry.is_none(),
122 node.entry.is_none(),
123 "duplicate dirstate entry in read"
123 "duplicate dirstate entry in read"
124 );
124 );
125 assert!(
125 assert!(
126 node.copy_source.is_none(),
126 node.copy_source.is_none(),
127 "duplicate dirstate entry in read"
127 "duplicate dirstate entry in read"
128 );
128 );
129 node.entry = Some(*entry);
129 node.entry = Some(*entry);
130 node.copy_source = copy_source.map(Cow::Borrowed);
130 node.copy_source = copy_source.map(Cow::Borrowed);
131 map.nodes_with_entry_count += 1;
131 map.nodes_with_entry_count += 1;
132 if copy_source.is_some() {
132 if copy_source.is_some() {
133 map.nodes_with_copy_source_count += 1
133 map.nodes_with_copy_source_count += 1
134 }
134 }
135 },
135 },
136 )?;
136 )?;
137 let parents = Some(parents.clone());
137 let parents = Some(parents.clone());
138
138
139 Ok((map, parents))
139 Ok((map, parents))
140 }
140 }
141
141
142 fn get_node(&self, path: &HgPath) -> Option<&Node> {
142 fn get_node(&self, path: &HgPath) -> Option<&Node> {
143 let mut children = &self.root;
143 let mut children = &self.root;
144 let mut components = path.components();
144 let mut components = path.components();
145 let mut component =
145 let mut component =
146 components.next().expect("expected at least one components");
146 components.next().expect("expected at least one components");
147 loop {
147 loop {
148 let child = children.get(component)?;
148 let child = children.get(component)?;
149 if let Some(next_component) = components.next() {
149 if let Some(next_component) = components.next() {
150 component = next_component;
150 component = next_component;
151 children = &child.children;
151 children = &child.children;
152 } else {
152 } else {
153 return Some(child);
153 return Some(child);
154 }
154 }
155 }
155 }
156 }
156 }
157
157
158 /// Returns a mutable reference to the node at `path` if it exists
158 /// Returns a mutable reference to the node at `path` if it exists
159 ///
159 ///
160 /// This takes `root` instead of `&mut self` so that callers can mutate
160 /// This takes `root` instead of `&mut self` so that callers can mutate
161 /// other fields while the returned borrow is still valid
161 /// other fields while the returned borrow is still valid
162 fn get_node_mut<'tree>(
162 fn get_node_mut<'tree>(
163 root: &'tree mut ChildNodes<'on_disk>,
163 root: &'tree mut ChildNodes<'on_disk>,
164 path: &HgPath,
164 path: &HgPath,
165 ) -> Option<&'tree mut Node<'on_disk>> {
165 ) -> Option<&'tree mut Node<'on_disk>> {
166 let mut children = root;
166 let mut children = root;
167 let mut components = path.components();
167 let mut components = path.components();
168 let mut component =
168 let mut component =
169 components.next().expect("expected at least one components");
169 components.next().expect("expected at least one components");
170 loop {
170 loop {
171 let child = children.get_mut(component)?;
171 let child = children.get_mut(component)?;
172 if let Some(next_component) = components.next() {
172 if let Some(next_component) = components.next() {
173 component = next_component;
173 component = next_component;
174 children = &mut child.children;
174 children = &mut child.children;
175 } else {
175 } else {
176 return Some(child);
176 return Some(child);
177 }
177 }
178 }
178 }
179 }
179 }
180
180
181 fn get_or_insert_node<'tree, 'path>(
181 fn get_or_insert_node<'tree, 'path>(
182 root: &'tree mut ChildNodes<'on_disk>,
182 root: &'tree mut ChildNodes<'on_disk>,
183 path: &'path HgPath,
183 path: &'path HgPath,
184 to_cow: impl Fn(
184 to_cow: impl Fn(
185 WithBasename<&'path HgPath>,
185 WithBasename<&'path HgPath>,
186 ) -> WithBasename<Cow<'on_disk, HgPath>>,
186 ) -> WithBasename<Cow<'on_disk, HgPath>>,
187 mut each_ancestor: impl FnMut(&mut Node),
187 mut each_ancestor: impl FnMut(&mut Node),
188 ) -> &'tree mut Node<'on_disk> {
188 ) -> &'tree mut Node<'on_disk> {
189 let mut child_nodes = root;
189 let mut child_nodes = root;
190 let mut inclusive_ancestor_paths =
190 let mut inclusive_ancestor_paths =
191 WithBasename::inclusive_ancestors_of(path);
191 WithBasename::inclusive_ancestors_of(path);
192 let mut ancestor_path = inclusive_ancestor_paths
192 let mut ancestor_path = inclusive_ancestor_paths
193 .next()
193 .next()
194 .expect("expected at least one inclusive ancestor");
194 .expect("expected at least one inclusive ancestor");
195 loop {
195 loop {
196 // TODO: can we avoid allocating an owned key in cases where the
196 // TODO: can we avoid allocating an owned key in cases where the
197 // map already contains that key, without introducing double
197 // map already contains that key, without introducing double
198 // lookup?
198 // lookup?
199 let child_node =
199 let child_node =
200 child_nodes.entry(to_cow(ancestor_path)).or_default();
200 child_nodes.entry(to_cow(ancestor_path)).or_default();
201 if let Some(next) = inclusive_ancestor_paths.next() {
201 if let Some(next) = inclusive_ancestor_paths.next() {
202 each_ancestor(child_node);
202 each_ancestor(child_node);
203 ancestor_path = next;
203 ancestor_path = next;
204 child_nodes = &mut child_node.children;
204 child_nodes = &mut child_node.children;
205 } else {
205 } else {
206 return child_node;
206 return child_node;
207 }
207 }
208 }
208 }
209 }
209 }
210
210
211 fn add_or_remove_file(
211 fn add_or_remove_file(
212 &mut self,
212 &mut self,
213 path: &HgPath,
213 path: &HgPath,
214 old_state: EntryState,
214 old_state: EntryState,
215 new_entry: DirstateEntry,
215 new_entry: DirstateEntry,
216 ) {
216 ) {
217 let tracked_count_increment =
217 let tracked_count_increment =
218 match (old_state.is_tracked(), new_entry.state.is_tracked()) {
218 match (old_state.is_tracked(), new_entry.state.is_tracked()) {
219 (false, true) => 1,
219 (false, true) => 1,
220 (true, false) => -1,
220 (true, false) => -1,
221 _ => 0,
221 _ => 0,
222 };
222 };
223
223
224 let node = Self::get_or_insert_node(
224 let node = Self::get_or_insert_node(
225 &mut self.root,
225 &mut self.root,
226 path,
226 path,
227 WithBasename::to_cow_owned,
227 WithBasename::to_cow_owned,
228 |ancestor| {
228 |ancestor| {
229 // We can’t use `+= increment` because the counter is unsigned,
229 // We can’t use `+= increment` because the counter is unsigned,
230 // and we want debug builds to detect accidental underflow
230 // and we want debug builds to detect accidental underflow
231 // through zero
231 // through zero
232 match tracked_count_increment {
232 match tracked_count_increment {
233 1 => ancestor.tracked_descendants_count += 1,
233 1 => ancestor.tracked_descendants_count += 1,
234 -1 => ancestor.tracked_descendants_count -= 1,
234 -1 => ancestor.tracked_descendants_count -= 1,
235 _ => {}
235 _ => {}
236 }
236 }
237 },
237 },
238 );
238 );
239 if node.entry.is_none() {
239 if node.entry.is_none() {
240 self.nodes_with_entry_count += 1
240 self.nodes_with_entry_count += 1
241 }
241 }
242 node.entry = Some(new_entry)
242 node.entry = Some(new_entry)
243 }
243 }
244
244
245 fn iter_nodes<'a>(
245 fn iter_nodes<'a>(
246 &'a self,
246 &'a self,
247 ) -> impl Iterator<Item = (&'a Cow<'on_disk, HgPath>, &'a Node)> + 'a {
247 ) -> impl Iterator<Item = (&'a Cow<'on_disk, HgPath>, &'a Node)> + 'a {
248 // Depth first tree traversal.
248 // Depth first tree traversal.
249 //
249 //
250 // If we could afford internal iteration and recursion,
250 // If we could afford internal iteration and recursion,
251 // this would look like:
251 // this would look like:
252 //
252 //
253 // ```
253 // ```
254 // fn traverse_children(
254 // fn traverse_children(
255 // children: &ChildNodes,
255 // children: &ChildNodes,
256 // each: &mut impl FnMut(&Node),
256 // each: &mut impl FnMut(&Node),
257 // ) {
257 // ) {
258 // for child in children.values() {
258 // for child in children.values() {
259 // traverse_children(&child.children, each);
259 // traverse_children(&child.children, each);
260 // each(child);
260 // each(child);
261 // }
261 // }
262 // }
262 // }
263 // ```
263 // ```
264 //
264 //
265 // However we want an external iterator and therefore can’t use the
265 // However we want an external iterator and therefore can’t use the
266 // call stack. Use an explicit stack instead:
266 // call stack. Use an explicit stack instead:
267 let mut stack = Vec::new();
267 let mut stack = Vec::new();
268 let mut iter = self.root.iter();
268 let mut iter = self.root.iter();
269 std::iter::from_fn(move || {
269 std::iter::from_fn(move || {
270 while let Some((key, child_node)) = iter.next() {
270 while let Some((key, child_node)) = iter.next() {
271 // Pseudo-recursion
271 // Pseudo-recursion
272 let new_iter = child_node.children.iter();
272 let new_iter = child_node.children.iter();
273 let old_iter = std::mem::replace(&mut iter, new_iter);
273 let old_iter = std::mem::replace(&mut iter, new_iter);
274 let key = key.full_path();
274 let key = key.full_path();
275 stack.push((key, child_node, old_iter));
275 stack.push((key, child_node, old_iter));
276 }
276 }
277 // Found the end of a `children.iter()` iterator.
277 // Found the end of a `children.iter()` iterator.
278 if let Some((key, child_node, next_iter)) = stack.pop() {
278 if let Some((key, child_node, next_iter)) = stack.pop() {
279 // "Return" from pseudo-recursion by restoring state from the
279 // "Return" from pseudo-recursion by restoring state from the
280 // explicit stack
280 // explicit stack
281 iter = next_iter;
281 iter = next_iter;
282
282
283 Some((key, child_node))
283 Some((key, child_node))
284 } else {
284 } else {
285 // Reached the bottom of the stack, we’re done
285 // Reached the bottom of the stack, we’re done
286 None
286 None
287 }
287 }
288 })
288 })
289 }
289 }
290
290
291 fn clear_known_ambiguous_mtimes(&mut self, paths: &[impl AsRef<HgPath>]) {
291 fn clear_known_ambiguous_mtimes(&mut self, paths: &[impl AsRef<HgPath>]) {
292 for path in paths {
292 for path in paths {
293 if let Some(node) =
293 if let Some(node) =
294 Self::get_node_mut(&mut self.root, path.as_ref())
294 Self::get_node_mut(&mut self.root, path.as_ref())
295 {
295 {
296 if let Some(entry) = node.entry.as_mut() {
296 if let Some(entry) = node.entry.as_mut() {
297 entry.clear_mtime();
297 entry.clear_mtime();
298 }
298 }
299 }
299 }
300 }
300 }
301 }
301 }
302 }
302 }
303
303
304 impl<'on_disk> super::dispatch::DirstateMapMethods for DirstateMap<'on_disk> {
304 impl<'on_disk> super::dispatch::DirstateMapMethods for DirstateMap<'on_disk> {
305 fn clear(&mut self) {
305 fn clear(&mut self) {
306 self.root.clear();
306 self.root.clear();
307 self.nodes_with_entry_count = 0;
307 self.nodes_with_entry_count = 0;
308 self.nodes_with_copy_source_count = 0;
308 self.nodes_with_copy_source_count = 0;
309 }
309 }
310
310
311 fn add_file(
311 fn add_file(
312 &mut self,
312 &mut self,
313 filename: &HgPath,
313 filename: &HgPath,
314 old_state: EntryState,
314 old_state: EntryState,
315 entry: DirstateEntry,
315 entry: DirstateEntry,
316 ) -> Result<(), DirstateMapError> {
316 ) -> Result<(), DirstateMapError> {
317 self.add_or_remove_file(filename, old_state, entry);
317 self.add_or_remove_file(filename, old_state, entry);
318 Ok(())
318 Ok(())
319 }
319 }
320
320
321 fn remove_file(
321 fn remove_file(
322 &mut self,
322 &mut self,
323 filename: &HgPath,
323 filename: &HgPath,
324 old_state: EntryState,
324 old_state: EntryState,
325 size: i32,
325 size: i32,
326 ) -> Result<(), DirstateMapError> {
326 ) -> Result<(), DirstateMapError> {
327 let entry = DirstateEntry {
327 let entry = DirstateEntry {
328 state: EntryState::Removed,
328 state: EntryState::Removed,
329 mode: 0,
329 mode: 0,
330 size,
330 size,
331 mtime: 0,
331 mtime: 0,
332 };
332 };
333 self.add_or_remove_file(filename, old_state, entry);
333 self.add_or_remove_file(filename, old_state, entry);
334 Ok(())
334 Ok(())
335 }
335 }
336
336
337 fn drop_file(
337 fn drop_file(
338 &mut self,
338 &mut self,
339 filename: &HgPath,
339 filename: &HgPath,
340 old_state: EntryState,
340 old_state: EntryState,
341 ) -> Result<bool, DirstateMapError> {
341 ) -> Result<bool, DirstateMapError> {
342 struct Dropped {
342 struct Dropped {
343 was_tracked: bool,
343 was_tracked: bool,
344 had_entry: bool,
344 had_entry: bool,
345 had_copy_source: bool,
345 had_copy_source: bool,
346 }
346 }
347 fn recur(nodes: &mut ChildNodes, path: &HgPath) -> Option<Dropped> {
347 fn recur(nodes: &mut ChildNodes, path: &HgPath) -> Option<Dropped> {
348 let (first_path_component, rest_of_path) =
348 let (first_path_component, rest_of_path) =
349 path.split_first_component();
349 path.split_first_component();
350 let node = nodes.get_mut(first_path_component)?;
350 let node = nodes.get_mut(first_path_component)?;
351 let dropped;
351 let dropped;
352 if let Some(rest) = rest_of_path {
352 if let Some(rest) = rest_of_path {
353 dropped = recur(&mut node.children, rest)?;
353 dropped = recur(&mut node.children, rest)?;
354 if dropped.was_tracked {
354 if dropped.was_tracked {
355 node.tracked_descendants_count -= 1;
355 node.tracked_descendants_count -= 1;
356 }
356 }
357 } else {
357 } else {
358 dropped = Dropped {
358 dropped = Dropped {
359 was_tracked: node
359 was_tracked: node
360 .entry
360 .entry
361 .as_ref()
361 .as_ref()
362 .map_or(false, |entry| entry.state.is_tracked()),
362 .map_or(false, |entry| entry.state.is_tracked()),
363 had_entry: node.entry.take().is_some(),
363 had_entry: node.entry.take().is_some(),
364 had_copy_source: node.copy_source.take().is_some(),
364 had_copy_source: node.copy_source.take().is_some(),
365 };
365 };
366 }
366 }
367 // After recursion, for both leaf (rest_of_path is None) nodes and
367 // After recursion, for both leaf (rest_of_path is None) nodes and
368 // parent nodes, remove a node if it just became empty.
368 // parent nodes, remove a node if it just became empty.
369 if node.entry.is_none()
369 if node.entry.is_none()
370 && node.copy_source.is_none()
370 && node.copy_source.is_none()
371 && node.children.is_empty()
371 && node.children.is_empty()
372 {
372 {
373 nodes.remove(first_path_component);
373 nodes.remove(first_path_component);
374 }
374 }
375 Some(dropped)
375 Some(dropped)
376 }
376 }
377
377
378 if let Some(dropped) = recur(&mut self.root, filename) {
378 if let Some(dropped) = recur(&mut self.root, filename) {
379 if dropped.had_entry {
379 if dropped.had_entry {
380 self.nodes_with_entry_count -= 1
380 self.nodes_with_entry_count -= 1
381 }
381 }
382 if dropped.had_copy_source {
382 if dropped.had_copy_source {
383 self.nodes_with_copy_source_count -= 1
383 self.nodes_with_copy_source_count -= 1
384 }
384 }
385 Ok(dropped.had_entry)
385 Ok(dropped.had_entry)
386 } else {
386 } else {
387 debug_assert!(!old_state.is_tracked());
387 debug_assert!(!old_state.is_tracked());
388 Ok(false)
388 Ok(false)
389 }
389 }
390 }
390 }
391
391
392 fn clear_ambiguous_times(&mut self, filenames: Vec<HgPathBuf>, now: i32) {
392 fn clear_ambiguous_times(&mut self, filenames: Vec<HgPathBuf>, now: i32) {
393 for filename in filenames {
393 for filename in filenames {
394 if let Some(node) = Self::get_node_mut(&mut self.root, &filename) {
394 if let Some(node) = Self::get_node_mut(&mut self.root, &filename) {
395 if let Some(entry) = node.entry.as_mut() {
395 if let Some(entry) = node.entry.as_mut() {
396 entry.clear_ambiguous_mtime(now);
396 entry.clear_ambiguous_mtime(now);
397 }
397 }
398 }
398 }
399 }
399 }
400 }
400 }
401
401
402 fn non_normal_entries_contains(&mut self, key: &HgPath) -> bool {
402 fn non_normal_entries_contains(&mut self, key: &HgPath) -> bool {
403 self.get_node(key)
403 self.get_node(key)
404 .and_then(|node| node.entry.as_ref())
404 .and_then(|node| node.entry.as_ref())
405 .map_or(false, DirstateEntry::is_non_normal)
405 .map_or(false, DirstateEntry::is_non_normal)
406 }
406 }
407
407
408 fn non_normal_entries_remove(&mut self, _key: &HgPath) {
408 fn non_normal_entries_remove(&mut self, _key: &HgPath) {
409 // Do nothing, this `DirstateMap` does not have a separate "non normal
409 // Do nothing, this `DirstateMap` does not have a separate "non normal
410 // entries" set that need to be kept up to date
410 // entries" set that need to be kept up to date
411 }
411 }
412
412
413 fn non_normal_or_other_parent_paths(
413 fn non_normal_or_other_parent_paths(
414 &mut self,
414 &mut self,
415 ) -> Box<dyn Iterator<Item = &HgPath> + '_> {
415 ) -> Box<dyn Iterator<Item = &HgPath> + '_> {
416 Box::new(self.iter_nodes().filter_map(|(path, node)| {
416 Box::new(self.iter_nodes().filter_map(|(path, node)| {
417 node.entry
417 node.entry
418 .as_ref()
418 .as_ref()
419 .filter(|entry| {
419 .filter(|entry| {
420 entry.is_non_normal() || entry.is_from_other_parent()
420 entry.is_non_normal() || entry.is_from_other_parent()
421 })
421 })
422 .map(|_| &**path)
422 .map(|_| &**path)
423 }))
423 }))
424 }
424 }
425
425
426 fn set_non_normal_other_parent_entries(&mut self, _force: bool) {
426 fn set_non_normal_other_parent_entries(&mut self, _force: bool) {
427 // Do nothing, this `DirstateMap` does not have a separate "non normal
427 // Do nothing, this `DirstateMap` does not have a separate "non normal
428 // entries" and "from other parent" sets that need to be recomputed
428 // entries" and "from other parent" sets that need to be recomputed
429 }
429 }
430
430
431 fn iter_non_normal_paths(
431 fn iter_non_normal_paths(
432 &mut self,
432 &mut self,
433 ) -> Box<dyn Iterator<Item = &HgPath> + Send + '_> {
433 ) -> Box<dyn Iterator<Item = &HgPath> + Send + '_> {
434 self.iter_non_normal_paths_panic()
434 self.iter_non_normal_paths_panic()
435 }
435 }
436
436
437 fn iter_non_normal_paths_panic(
437 fn iter_non_normal_paths_panic(
438 &self,
438 &self,
439 ) -> Box<dyn Iterator<Item = &HgPath> + Send + '_> {
439 ) -> Box<dyn Iterator<Item = &HgPath> + Send + '_> {
440 Box::new(self.iter_nodes().filter_map(|(path, node)| {
440 Box::new(self.iter_nodes().filter_map(|(path, node)| {
441 node.entry
441 node.entry
442 .as_ref()
442 .as_ref()
443 .filter(|entry| entry.is_non_normal())
443 .filter(|entry| entry.is_non_normal())
444 .map(|_| &**path)
444 .map(|_| &**path)
445 }))
445 }))
446 }
446 }
447
447
448 fn iter_other_parent_paths(
448 fn iter_other_parent_paths(
449 &mut self,
449 &mut self,
450 ) -> Box<dyn Iterator<Item = &HgPath> + Send + '_> {
450 ) -> Box<dyn Iterator<Item = &HgPath> + Send + '_> {
451 Box::new(self.iter_nodes().filter_map(|(path, node)| {
451 Box::new(self.iter_nodes().filter_map(|(path, node)| {
452 node.entry
452 node.entry
453 .as_ref()
453 .as_ref()
454 .filter(|entry| entry.is_from_other_parent())
454 .filter(|entry| entry.is_from_other_parent())
455 .map(|_| &**path)
455 .map(|_| &**path)
456 }))
456 }))
457 }
457 }
458
458
459 fn has_tracked_dir(
459 fn has_tracked_dir(
460 &mut self,
460 &mut self,
461 directory: &HgPath,
461 directory: &HgPath,
462 ) -> Result<bool, DirstateMapError> {
462 ) -> Result<bool, DirstateMapError> {
463 if let Some(node) = self.get_node(directory) {
463 if let Some(node) = self.get_node(directory) {
464 // A node without a `DirstateEntry` was created to hold child
464 // A node without a `DirstateEntry` was created to hold child
465 // nodes, and is therefore a directory.
465 // nodes, and is therefore a directory.
466 Ok(node.entry.is_none() && node.tracked_descendants_count > 0)
466 Ok(node.entry.is_none() && node.tracked_descendants_count > 0)
467 } else {
467 } else {
468 Ok(false)
468 Ok(false)
469 }
469 }
470 }
470 }
471
471
472 fn has_dir(
472 fn has_dir(
473 &mut self,
473 &mut self,
474 directory: &HgPath,
474 directory: &HgPath,
475 ) -> Result<bool, DirstateMapError> {
475 ) -> Result<bool, DirstateMapError> {
476 if let Some(node) = self.get_node(directory) {
476 if let Some(node) = self.get_node(directory) {
477 // A node without a `DirstateEntry` was created to hold child
477 // A node without a `DirstateEntry` was created to hold child
478 // nodes, and is therefore a directory.
478 // nodes, and is therefore a directory.
479 Ok(node.entry.is_none())
479 Ok(node.entry.is_none())
480 } else {
480 } else {
481 Ok(false)
481 Ok(false)
482 }
482 }
483 }
483 }
484
484
485 #[timed]
485 #[timed]
486 fn pack_v1(
486 fn pack_v1(
487 &mut self,
487 &mut self,
488 parents: DirstateParents,
488 parents: DirstateParents,
489 now: Timestamp,
489 now: Timestamp,
490 ) -> Result<Vec<u8>, DirstateError> {
490 ) -> Result<Vec<u8>, DirstateError> {
491 let now: i32 = now.0.try_into().expect("time overflow");
491 let now: i32 = now.0.try_into().expect("time overflow");
492 let mut ambiguous_mtimes = Vec::new();
492 let mut ambiguous_mtimes = Vec::new();
493 // Optizimation (to be measured?): pre-compute size to avoid `Vec`
493 // Optizimation (to be measured?): pre-compute size to avoid `Vec`
494 // reallocations
494 // reallocations
495 let mut size = parents.as_bytes().len();
495 let mut size = parents.as_bytes().len();
496 for (path, node) in self.iter_nodes() {
496 for (path, node) in self.iter_nodes() {
497 if let Some(entry) = &node.entry {
497 if let Some(entry) = &node.entry {
498 size += packed_entry_size(
498 size += packed_entry_size(
499 path,
499 path,
500 node.copy_source.as_ref().map(|p| &**p),
500 node.copy_source.as_ref().map(|p| &**p),
501 );
501 );
502 if entry.mtime_is_ambiguous(now) {
502 if entry.mtime_is_ambiguous(now) {
503 ambiguous_mtimes.push(path.clone())
503 ambiguous_mtimes.push(path.clone())
504 }
504 }
505 }
505 }
506 }
506 }
507 self.clear_known_ambiguous_mtimes(&ambiguous_mtimes);
507 self.clear_known_ambiguous_mtimes(&ambiguous_mtimes);
508
508
509 let mut packed = Vec::with_capacity(size);
509 let mut packed = Vec::with_capacity(size);
510 packed.extend(parents.as_bytes());
510 packed.extend(parents.as_bytes());
511
511
512 for (path, node) in self.iter_nodes() {
512 for (path, node) in self.iter_nodes() {
513 if let Some(entry) = &node.entry {
513 if let Some(entry) = &node.entry {
514 pack_entry(
514 pack_entry(
515 path,
515 path,
516 entry,
516 entry,
517 node.copy_source.as_ref().map(|p| &**p),
517 node.copy_source.as_ref().map(|p| &**p),
518 &mut packed,
518 &mut packed,
519 );
519 );
520 }
520 }
521 }
521 }
522 Ok(packed)
522 Ok(packed)
523 }
523 }
524
524
525 #[timed]
525 #[timed]
526 fn pack_v2(
526 fn pack_v2(
527 &mut self,
527 &mut self,
528 parents: DirstateParents,
528 parents: DirstateParents,
529 now: Timestamp,
529 now: Timestamp,
530 ) -> Result<Vec<u8>, DirstateError> {
530 ) -> Result<Vec<u8>, DirstateError> {
531 // TODO:Β how do we want to handle this in 2038?
531 // TODO:Β how do we want to handle this in 2038?
532 let now: i32 = now.0.try_into().expect("time overflow");
532 let now: i32 = now.0.try_into().expect("time overflow");
533 let mut paths = Vec::new();
533 let mut paths = Vec::new();
534 for (path, node) in self.iter_nodes() {
534 for (path, node) in self.iter_nodes() {
535 if let Some(entry) = &node.entry {
535 if let Some(entry) = &node.entry {
536 if entry.mtime_is_ambiguous(now) {
536 if entry.mtime_is_ambiguous(now) {
537 paths.push(path.clone())
537 paths.push(path.clone())
538 }
538 }
539 }
539 }
540 }
540 }
541 // Borrow of `self` ends here since we collect cloned paths
541 // Borrow of `self` ends here since we collect cloned paths
542
542
543 self.clear_known_ambiguous_mtimes(&paths);
543 self.clear_known_ambiguous_mtimes(&paths);
544
544
545 on_disk::write(self, parents)
545 on_disk::write(self, parents)
546 }
546 }
547
547
548 fn set_all_dirs(&mut self) -> Result<(), DirstateMapError> {
548 fn set_all_dirs(&mut self) -> Result<(), DirstateMapError> {
549 // Do nothing, this `DirstateMap` does not a separate `all_dirs` that
549 // Do nothing, this `DirstateMap` does not a separate `all_dirs` that
550 // needs to be recomputed
550 // needs to be recomputed
551 Ok(())
551 Ok(())
552 }
552 }
553
553
554 fn set_dirs(&mut self) -> Result<(), DirstateMapError> {
554 fn set_dirs(&mut self) -> Result<(), DirstateMapError> {
555 // Do nothing, this `DirstateMap` does not a separate `dirs` that needs
555 // Do nothing, this `DirstateMap` does not a separate `dirs` that needs
556 // to be recomputed
556 // to be recomputed
557 Ok(())
557 Ok(())
558 }
558 }
559
559
560 fn status<'a>(
560 fn status<'a>(
561 &'a mut self,
561 &'a mut self,
562 matcher: &'a (dyn Matcher + Sync),
562 matcher: &'a (dyn Matcher + Sync),
563 root_dir: PathBuf,
563 root_dir: PathBuf,
564 ignore_files: Vec<PathBuf>,
564 ignore_files: Vec<PathBuf>,
565 options: StatusOptions,
565 options: StatusOptions,
566 ) -> Result<(DirstateStatus<'a>, Vec<PatternFileWarning>), StatusError>
566 ) -> Result<(DirstateStatus<'a>, Vec<PatternFileWarning>), StatusError>
567 {
567 {
568 super::status::status(self, matcher, root_dir, ignore_files, options)
568 super::status::status(self, matcher, root_dir, ignore_files, options)
569 }
569 }
570
570
571 fn copy_map_len(&self) -> usize {
571 fn copy_map_len(&self) -> usize {
572 self.nodes_with_copy_source_count as usize
572 self.nodes_with_copy_source_count as usize
573 }
573 }
574
574
575 fn copy_map_iter(&self) -> CopyMapIter<'_> {
575 fn copy_map_iter(&self) -> CopyMapIter<'_> {
576 Box::new(self.iter_nodes().filter_map(|(path, node)| {
576 Box::new(self.iter_nodes().filter_map(|(path, node)| {
577 node.copy_source
577 node.copy_source
578 .as_ref()
578 .as_ref()
579 .map(|copy_source| (&**path, &**copy_source))
579 .map(|copy_source| (&**path, &**copy_source))
580 }))
580 }))
581 }
581 }
582
582
583 fn copy_map_contains_key(&self, key: &HgPath) -> bool {
583 fn copy_map_contains_key(&self, key: &HgPath) -> bool {
584 if let Some(node) = self.get_node(key) {
584 if let Some(node) = self.get_node(key) {
585 node.copy_source.is_some()
585 node.copy_source.is_some()
586 } else {
586 } else {
587 false
587 false
588 }
588 }
589 }
589 }
590
590
591 fn copy_map_get(&self, key: &HgPath) -> Option<&HgPath> {
591 fn copy_map_get(&self, key: &HgPath) -> Option<&HgPath> {
592 self.get_node(key)?.copy_source.as_ref().map(|p| &**p)
592 self.get_node(key)?.copy_source.as_ref().map(|p| &**p)
593 }
593 }
594
594
595 fn copy_map_remove(&mut self, key: &HgPath) -> Option<HgPathBuf> {
595 fn copy_map_remove(&mut self, key: &HgPath) -> Option<HgPathBuf> {
596 let count = &mut self.nodes_with_copy_source_count;
596 let count = &mut self.nodes_with_copy_source_count;
597 Self::get_node_mut(&mut self.root, key).and_then(|node| {
597 Self::get_node_mut(&mut self.root, key).and_then(|node| {
598 if node.copy_source.is_some() {
598 if node.copy_source.is_some() {
599 *count -= 1
599 *count -= 1
600 }
600 }
601 node.copy_source.take().map(Cow::into_owned)
601 node.copy_source.take().map(Cow::into_owned)
602 })
602 })
603 }
603 }
604
604
605 fn copy_map_insert(
605 fn copy_map_insert(
606 &mut self,
606 &mut self,
607 key: HgPathBuf,
607 key: HgPathBuf,
608 value: HgPathBuf,
608 value: HgPathBuf,
609 ) -> Option<HgPathBuf> {
609 ) -> Option<HgPathBuf> {
610 let node = Self::get_or_insert_node(
610 let node = Self::get_or_insert_node(
611 &mut self.root,
611 &mut self.root,
612 &key,
612 &key,
613 WithBasename::to_cow_owned,
613 WithBasename::to_cow_owned,
614 |_ancestor| {},
614 |_ancestor| {},
615 );
615 );
616 if node.copy_source.is_none() {
616 if node.copy_source.is_none() {
617 self.nodes_with_copy_source_count += 1
617 self.nodes_with_copy_source_count += 1
618 }
618 }
619 node.copy_source.replace(value.into()).map(Cow::into_owned)
619 node.copy_source.replace(value.into()).map(Cow::into_owned)
620 }
620 }
621
621
622 fn len(&self) -> usize {
622 fn len(&self) -> usize {
623 self.nodes_with_entry_count as usize
623 self.nodes_with_entry_count as usize
624 }
624 }
625
625
626 fn contains_key(&self, key: &HgPath) -> bool {
626 fn contains_key(&self, key: &HgPath) -> bool {
627 self.get(key).is_some()
627 self.get(key).is_some()
628 }
628 }
629
629
630 fn get(&self, key: &HgPath) -> Option<&DirstateEntry> {
630 fn get(&self, key: &HgPath) -> Option<DirstateEntry> {
631 self.get_node(key)?.entry.as_ref()
631 self.get_node(key)?.entry
632 }
632 }
633
633
634 fn iter(&self) -> StateMapIter<'_> {
634 fn iter(&self) -> StateMapIter<'_> {
635 Box::new(self.iter_nodes().filter_map(|(path, node)| {
635 Box::new(self.iter_nodes().filter_map(|(path, node)| {
636 node.entry.as_ref().map(|entry| (&**path, entry))
636 node.entry.map(|entry| (&**path, entry))
637 }))
637 }))
638 }
638 }
639 }
639 }
@@ -1,300 +1,300 b''
1 use std::path::PathBuf;
1 use std::path::PathBuf;
2
2
3 use crate::dirstate::parsers::Timestamp;
3 use crate::dirstate::parsers::Timestamp;
4 use crate::matchers::Matcher;
4 use crate::matchers::Matcher;
5 use crate::utils::hg_path::{HgPath, HgPathBuf};
5 use crate::utils::hg_path::{HgPath, HgPathBuf};
6 use crate::CopyMapIter;
6 use crate::CopyMapIter;
7 use crate::DirstateEntry;
7 use crate::DirstateEntry;
8 use crate::DirstateError;
8 use crate::DirstateError;
9 use crate::DirstateMap;
9 use crate::DirstateMap;
10 use crate::DirstateMapError;
10 use crate::DirstateMapError;
11 use crate::DirstateParents;
11 use crate::DirstateParents;
12 use crate::DirstateStatus;
12 use crate::DirstateStatus;
13 use crate::EntryState;
13 use crate::EntryState;
14 use crate::PatternFileWarning;
14 use crate::PatternFileWarning;
15 use crate::StateMapIter;
15 use crate::StateMapIter;
16 use crate::StatusError;
16 use crate::StatusError;
17 use crate::StatusOptions;
17 use crate::StatusOptions;
18
18
19 pub trait DirstateMapMethods {
19 pub trait DirstateMapMethods {
20 fn clear(&mut self);
20 fn clear(&mut self);
21
21
22 fn add_file(
22 fn add_file(
23 &mut self,
23 &mut self,
24 filename: &HgPath,
24 filename: &HgPath,
25 old_state: EntryState,
25 old_state: EntryState,
26 entry: DirstateEntry,
26 entry: DirstateEntry,
27 ) -> Result<(), DirstateMapError>;
27 ) -> Result<(), DirstateMapError>;
28
28
29 fn remove_file(
29 fn remove_file(
30 &mut self,
30 &mut self,
31 filename: &HgPath,
31 filename: &HgPath,
32 old_state: EntryState,
32 old_state: EntryState,
33 size: i32,
33 size: i32,
34 ) -> Result<(), DirstateMapError>;
34 ) -> Result<(), DirstateMapError>;
35
35
36 fn drop_file(
36 fn drop_file(
37 &mut self,
37 &mut self,
38 filename: &HgPath,
38 filename: &HgPath,
39 old_state: EntryState,
39 old_state: EntryState,
40 ) -> Result<bool, DirstateMapError>;
40 ) -> Result<bool, DirstateMapError>;
41
41
42 fn clear_ambiguous_times(&mut self, filenames: Vec<HgPathBuf>, now: i32);
42 fn clear_ambiguous_times(&mut self, filenames: Vec<HgPathBuf>, now: i32);
43
43
44 fn non_normal_entries_contains(&mut self, key: &HgPath) -> bool;
44 fn non_normal_entries_contains(&mut self, key: &HgPath) -> bool;
45
45
46 fn non_normal_entries_remove(&mut self, key: &HgPath);
46 fn non_normal_entries_remove(&mut self, key: &HgPath);
47
47
48 fn non_normal_or_other_parent_paths(
48 fn non_normal_or_other_parent_paths(
49 &mut self,
49 &mut self,
50 ) -> Box<dyn Iterator<Item = &HgPath> + '_>;
50 ) -> Box<dyn Iterator<Item = &HgPath> + '_>;
51
51
52 fn set_non_normal_other_parent_entries(&mut self, force: bool);
52 fn set_non_normal_other_parent_entries(&mut self, force: bool);
53
53
54 fn iter_non_normal_paths(
54 fn iter_non_normal_paths(
55 &mut self,
55 &mut self,
56 ) -> Box<dyn Iterator<Item = &HgPath> + Send + '_>;
56 ) -> Box<dyn Iterator<Item = &HgPath> + Send + '_>;
57
57
58 fn iter_non_normal_paths_panic(
58 fn iter_non_normal_paths_panic(
59 &self,
59 &self,
60 ) -> Box<dyn Iterator<Item = &HgPath> + Send + '_>;
60 ) -> Box<dyn Iterator<Item = &HgPath> + Send + '_>;
61
61
62 fn iter_other_parent_paths(
62 fn iter_other_parent_paths(
63 &mut self,
63 &mut self,
64 ) -> Box<dyn Iterator<Item = &HgPath> + Send + '_>;
64 ) -> Box<dyn Iterator<Item = &HgPath> + Send + '_>;
65
65
66 fn has_tracked_dir(
66 fn has_tracked_dir(
67 &mut self,
67 &mut self,
68 directory: &HgPath,
68 directory: &HgPath,
69 ) -> Result<bool, DirstateMapError>;
69 ) -> Result<bool, DirstateMapError>;
70
70
71 fn has_dir(
71 fn has_dir(
72 &mut self,
72 &mut self,
73 directory: &HgPath,
73 directory: &HgPath,
74 ) -> Result<bool, DirstateMapError>;
74 ) -> Result<bool, DirstateMapError>;
75
75
76 fn pack_v1(
76 fn pack_v1(
77 &mut self,
77 &mut self,
78 parents: DirstateParents,
78 parents: DirstateParents,
79 now: Timestamp,
79 now: Timestamp,
80 ) -> Result<Vec<u8>, DirstateError>;
80 ) -> Result<Vec<u8>, DirstateError>;
81
81
82 fn pack_v2(
82 fn pack_v2(
83 &mut self,
83 &mut self,
84 parents: DirstateParents,
84 parents: DirstateParents,
85 now: Timestamp,
85 now: Timestamp,
86 ) -> Result<Vec<u8>, DirstateError>;
86 ) -> Result<Vec<u8>, DirstateError>;
87
87
88 fn set_all_dirs(&mut self) -> Result<(), DirstateMapError>;
88 fn set_all_dirs(&mut self) -> Result<(), DirstateMapError>;
89
89
90 fn set_dirs(&mut self) -> Result<(), DirstateMapError>;
90 fn set_dirs(&mut self) -> Result<(), DirstateMapError>;
91
91
92 fn status<'a>(
92 fn status<'a>(
93 &'a mut self,
93 &'a mut self,
94 matcher: &'a (dyn Matcher + Sync),
94 matcher: &'a (dyn Matcher + Sync),
95 root_dir: PathBuf,
95 root_dir: PathBuf,
96 ignore_files: Vec<PathBuf>,
96 ignore_files: Vec<PathBuf>,
97 options: StatusOptions,
97 options: StatusOptions,
98 ) -> Result<(DirstateStatus<'a>, Vec<PatternFileWarning>), StatusError>;
98 ) -> Result<(DirstateStatus<'a>, Vec<PatternFileWarning>), StatusError>;
99
99
100 fn copy_map_len(&self) -> usize;
100 fn copy_map_len(&self) -> usize;
101
101
102 fn copy_map_iter(&self) -> CopyMapIter<'_>;
102 fn copy_map_iter(&self) -> CopyMapIter<'_>;
103
103
104 fn copy_map_contains_key(&self, key: &HgPath) -> bool;
104 fn copy_map_contains_key(&self, key: &HgPath) -> bool;
105
105
106 fn copy_map_get(&self, key: &HgPath) -> Option<&HgPath>;
106 fn copy_map_get(&self, key: &HgPath) -> Option<&HgPath>;
107
107
108 fn copy_map_remove(&mut self, key: &HgPath) -> Option<HgPathBuf>;
108 fn copy_map_remove(&mut self, key: &HgPath) -> Option<HgPathBuf>;
109
109
110 fn copy_map_insert(
110 fn copy_map_insert(
111 &mut self,
111 &mut self,
112 key: HgPathBuf,
112 key: HgPathBuf,
113 value: HgPathBuf,
113 value: HgPathBuf,
114 ) -> Option<HgPathBuf>;
114 ) -> Option<HgPathBuf>;
115
115
116 fn len(&self) -> usize;
116 fn len(&self) -> usize;
117
117
118 fn contains_key(&self, key: &HgPath) -> bool;
118 fn contains_key(&self, key: &HgPath) -> bool;
119
119
120 fn get(&self, key: &HgPath) -> Option<&DirstateEntry>;
120 fn get(&self, key: &HgPath) -> Option<DirstateEntry>;
121
121
122 fn iter(&self) -> StateMapIter<'_>;
122 fn iter(&self) -> StateMapIter<'_>;
123 }
123 }
124
124
125 impl DirstateMapMethods for DirstateMap {
125 impl DirstateMapMethods for DirstateMap {
126 fn clear(&mut self) {
126 fn clear(&mut self) {
127 self.clear()
127 self.clear()
128 }
128 }
129
129
130 fn add_file(
130 fn add_file(
131 &mut self,
131 &mut self,
132 filename: &HgPath,
132 filename: &HgPath,
133 old_state: EntryState,
133 old_state: EntryState,
134 entry: DirstateEntry,
134 entry: DirstateEntry,
135 ) -> Result<(), DirstateMapError> {
135 ) -> Result<(), DirstateMapError> {
136 self.add_file(filename, old_state, entry)
136 self.add_file(filename, old_state, entry)
137 }
137 }
138
138
139 fn remove_file(
139 fn remove_file(
140 &mut self,
140 &mut self,
141 filename: &HgPath,
141 filename: &HgPath,
142 old_state: EntryState,
142 old_state: EntryState,
143 size: i32,
143 size: i32,
144 ) -> Result<(), DirstateMapError> {
144 ) -> Result<(), DirstateMapError> {
145 self.remove_file(filename, old_state, size)
145 self.remove_file(filename, old_state, size)
146 }
146 }
147
147
148 fn drop_file(
148 fn drop_file(
149 &mut self,
149 &mut self,
150 filename: &HgPath,
150 filename: &HgPath,
151 old_state: EntryState,
151 old_state: EntryState,
152 ) -> Result<bool, DirstateMapError> {
152 ) -> Result<bool, DirstateMapError> {
153 self.drop_file(filename, old_state)
153 self.drop_file(filename, old_state)
154 }
154 }
155
155
156 fn clear_ambiguous_times(&mut self, filenames: Vec<HgPathBuf>, now: i32) {
156 fn clear_ambiguous_times(&mut self, filenames: Vec<HgPathBuf>, now: i32) {
157 self.clear_ambiguous_times(filenames, now)
157 self.clear_ambiguous_times(filenames, now)
158 }
158 }
159
159
160 fn non_normal_entries_contains(&mut self, key: &HgPath) -> bool {
160 fn non_normal_entries_contains(&mut self, key: &HgPath) -> bool {
161 let (non_normal, _other_parent) =
161 let (non_normal, _other_parent) =
162 self.get_non_normal_other_parent_entries();
162 self.get_non_normal_other_parent_entries();
163 non_normal.contains(key)
163 non_normal.contains(key)
164 }
164 }
165
165
166 fn non_normal_entries_remove(&mut self, key: &HgPath) {
166 fn non_normal_entries_remove(&mut self, key: &HgPath) {
167 self.non_normal_entries_remove(key)
167 self.non_normal_entries_remove(key)
168 }
168 }
169
169
170 fn non_normal_or_other_parent_paths(
170 fn non_normal_or_other_parent_paths(
171 &mut self,
171 &mut self,
172 ) -> Box<dyn Iterator<Item = &HgPath> + '_> {
172 ) -> Box<dyn Iterator<Item = &HgPath> + '_> {
173 let (non_normal, other_parent) =
173 let (non_normal, other_parent) =
174 self.get_non_normal_other_parent_entries();
174 self.get_non_normal_other_parent_entries();
175 Box::new(non_normal.union(other_parent).map(|p| &**p))
175 Box::new(non_normal.union(other_parent).map(|p| &**p))
176 }
176 }
177
177
178 fn set_non_normal_other_parent_entries(&mut self, force: bool) {
178 fn set_non_normal_other_parent_entries(&mut self, force: bool) {
179 self.set_non_normal_other_parent_entries(force)
179 self.set_non_normal_other_parent_entries(force)
180 }
180 }
181
181
182 fn iter_non_normal_paths(
182 fn iter_non_normal_paths(
183 &mut self,
183 &mut self,
184 ) -> Box<dyn Iterator<Item = &HgPath> + Send + '_> {
184 ) -> Box<dyn Iterator<Item = &HgPath> + Send + '_> {
185 let (non_normal, _other_parent) =
185 let (non_normal, _other_parent) =
186 self.get_non_normal_other_parent_entries();
186 self.get_non_normal_other_parent_entries();
187 Box::new(non_normal.iter().map(|p| &**p))
187 Box::new(non_normal.iter().map(|p| &**p))
188 }
188 }
189
189
190 fn iter_non_normal_paths_panic(
190 fn iter_non_normal_paths_panic(
191 &self,
191 &self,
192 ) -> Box<dyn Iterator<Item = &HgPath> + Send + '_> {
192 ) -> Box<dyn Iterator<Item = &HgPath> + Send + '_> {
193 let (non_normal, _other_parent) =
193 let (non_normal, _other_parent) =
194 self.get_non_normal_other_parent_entries_panic();
194 self.get_non_normal_other_parent_entries_panic();
195 Box::new(non_normal.iter().map(|p| &**p))
195 Box::new(non_normal.iter().map(|p| &**p))
196 }
196 }
197
197
198 fn iter_other_parent_paths(
198 fn iter_other_parent_paths(
199 &mut self,
199 &mut self,
200 ) -> Box<dyn Iterator<Item = &HgPath> + Send + '_> {
200 ) -> Box<dyn Iterator<Item = &HgPath> + Send + '_> {
201 let (_non_normal, other_parent) =
201 let (_non_normal, other_parent) =
202 self.get_non_normal_other_parent_entries();
202 self.get_non_normal_other_parent_entries();
203 Box::new(other_parent.iter().map(|p| &**p))
203 Box::new(other_parent.iter().map(|p| &**p))
204 }
204 }
205
205
206 fn has_tracked_dir(
206 fn has_tracked_dir(
207 &mut self,
207 &mut self,
208 directory: &HgPath,
208 directory: &HgPath,
209 ) -> Result<bool, DirstateMapError> {
209 ) -> Result<bool, DirstateMapError> {
210 self.has_tracked_dir(directory)
210 self.has_tracked_dir(directory)
211 }
211 }
212
212
213 fn has_dir(
213 fn has_dir(
214 &mut self,
214 &mut self,
215 directory: &HgPath,
215 directory: &HgPath,
216 ) -> Result<bool, DirstateMapError> {
216 ) -> Result<bool, DirstateMapError> {
217 self.has_dir(directory)
217 self.has_dir(directory)
218 }
218 }
219
219
220 fn pack_v1(
220 fn pack_v1(
221 &mut self,
221 &mut self,
222 parents: DirstateParents,
222 parents: DirstateParents,
223 now: Timestamp,
223 now: Timestamp,
224 ) -> Result<Vec<u8>, DirstateError> {
224 ) -> Result<Vec<u8>, DirstateError> {
225 self.pack(parents, now)
225 self.pack(parents, now)
226 }
226 }
227
227
228 fn pack_v2(
228 fn pack_v2(
229 &mut self,
229 &mut self,
230 _parents: DirstateParents,
230 _parents: DirstateParents,
231 _now: Timestamp,
231 _now: Timestamp,
232 ) -> Result<Vec<u8>, DirstateError> {
232 ) -> Result<Vec<u8>, DirstateError> {
233 panic!(
233 panic!(
234 "should have used dirstate_tree::DirstateMap to use the v2 format"
234 "should have used dirstate_tree::DirstateMap to use the v2 format"
235 )
235 )
236 }
236 }
237
237
238 fn set_all_dirs(&mut self) -> Result<(), DirstateMapError> {
238 fn set_all_dirs(&mut self) -> Result<(), DirstateMapError> {
239 self.set_all_dirs()
239 self.set_all_dirs()
240 }
240 }
241
241
242 fn set_dirs(&mut self) -> Result<(), DirstateMapError> {
242 fn set_dirs(&mut self) -> Result<(), DirstateMapError> {
243 self.set_dirs()
243 self.set_dirs()
244 }
244 }
245
245
246 fn status<'a>(
246 fn status<'a>(
247 &'a mut self,
247 &'a mut self,
248 matcher: &'a (dyn Matcher + Sync),
248 matcher: &'a (dyn Matcher + Sync),
249 root_dir: PathBuf,
249 root_dir: PathBuf,
250 ignore_files: Vec<PathBuf>,
250 ignore_files: Vec<PathBuf>,
251 options: StatusOptions,
251 options: StatusOptions,
252 ) -> Result<(DirstateStatus<'a>, Vec<PatternFileWarning>), StatusError>
252 ) -> Result<(DirstateStatus<'a>, Vec<PatternFileWarning>), StatusError>
253 {
253 {
254 crate::status(self, matcher, root_dir, ignore_files, options)
254 crate::status(self, matcher, root_dir, ignore_files, options)
255 }
255 }
256
256
257 fn copy_map_len(&self) -> usize {
257 fn copy_map_len(&self) -> usize {
258 self.copy_map.len()
258 self.copy_map.len()
259 }
259 }
260
260
261 fn copy_map_iter(&self) -> CopyMapIter<'_> {
261 fn copy_map_iter(&self) -> CopyMapIter<'_> {
262 Box::new(self.copy_map.iter().map(|(key, value)| (&**key, &**value)))
262 Box::new(self.copy_map.iter().map(|(key, value)| (&**key, &**value)))
263 }
263 }
264
264
265 fn copy_map_contains_key(&self, key: &HgPath) -> bool {
265 fn copy_map_contains_key(&self, key: &HgPath) -> bool {
266 self.copy_map.contains_key(key)
266 self.copy_map.contains_key(key)
267 }
267 }
268
268
269 fn copy_map_get(&self, key: &HgPath) -> Option<&HgPath> {
269 fn copy_map_get(&self, key: &HgPath) -> Option<&HgPath> {
270 self.copy_map.get(key).map(|p| &**p)
270 self.copy_map.get(key).map(|p| &**p)
271 }
271 }
272
272
273 fn copy_map_remove(&mut self, key: &HgPath) -> Option<HgPathBuf> {
273 fn copy_map_remove(&mut self, key: &HgPath) -> Option<HgPathBuf> {
274 self.copy_map.remove(key)
274 self.copy_map.remove(key)
275 }
275 }
276
276
277 fn copy_map_insert(
277 fn copy_map_insert(
278 &mut self,
278 &mut self,
279 key: HgPathBuf,
279 key: HgPathBuf,
280 value: HgPathBuf,
280 value: HgPathBuf,
281 ) -> Option<HgPathBuf> {
281 ) -> Option<HgPathBuf> {
282 self.copy_map.insert(key, value)
282 self.copy_map.insert(key, value)
283 }
283 }
284
284
285 fn len(&self) -> usize {
285 fn len(&self) -> usize {
286 (&**self).len()
286 (&**self).len()
287 }
287 }
288
288
289 fn contains_key(&self, key: &HgPath) -> bool {
289 fn contains_key(&self, key: &HgPath) -> bool {
290 (&**self).contains_key(key)
290 (&**self).contains_key(key)
291 }
291 }
292
292
293 fn get(&self, key: &HgPath) -> Option<&DirstateEntry> {
293 fn get(&self, key: &HgPath) -> Option<DirstateEntry> {
294 (&**self).get(key)
294 (&**self).get(key).cloned()
295 }
295 }
296
296
297 fn iter(&self) -> StateMapIter<'_> {
297 fn iter(&self) -> StateMapIter<'_> {
298 Box::new((&**self).iter().map(|(key, value)| (&**key, value)))
298 Box::new((&**self).iter().map(|(key, value)| (&**key, *value)))
299 }
299 }
300 }
300 }
@@ -1,140 +1,141 b''
1 // dirs_multiset.rs
1 // dirs_multiset.rs
2 //
2 //
3 // Copyright 2019 Raphaël Gomès <rgomes@octobus.net>
3 // Copyright 2019 Raphaël Gomès <rgomes@octobus.net>
4 //
4 //
5 // This software may be used and distributed according to the terms of the
5 // This software may be used and distributed according to the terms of the
6 // GNU General Public License version 2 or any later version.
6 // GNU General Public License version 2 or any later version.
7
7
8 //! Bindings for the `hg::dirstate::dirs_multiset` file provided by the
8 //! Bindings for the `hg::dirstate::dirs_multiset` file provided by the
9 //! `hg-core` package.
9 //! `hg-core` package.
10
10
11 use std::cell::RefCell;
11 use std::cell::RefCell;
12 use std::convert::TryInto;
12 use std::convert::TryInto;
13
13
14 use cpython::{
14 use cpython::{
15 exc, ObjectProtocol, PyBytes, PyClone, PyDict, PyErr, PyObject, PyResult,
15 exc, ObjectProtocol, PyBytes, PyClone, PyDict, PyErr, PyObject, PyResult,
16 Python, UnsafePyLeaked,
16 Python, UnsafePyLeaked,
17 };
17 };
18
18
19 use crate::dirstate::extract_dirstate;
19 use crate::dirstate::extract_dirstate;
20 use hg::{
20 use hg::{
21 errors::HgError,
21 errors::HgError,
22 utils::hg_path::{HgPath, HgPathBuf},
22 utils::hg_path::{HgPath, HgPathBuf},
23 DirsMultiset, DirsMultisetIter, DirstateMapError, EntryState,
23 DirsMultiset, DirsMultisetIter, DirstateMapError, EntryState,
24 };
24 };
25
25
26 py_class!(pub class Dirs |py| {
26 py_class!(pub class Dirs |py| {
27 @shared data inner: DirsMultiset;
27 @shared data inner: DirsMultiset;
28
28
29 // `map` is either a `dict` or a flat iterator (usually a `set`, sometimes
29 // `map` is either a `dict` or a flat iterator (usually a `set`, sometimes
30 // a `list`)
30 // a `list`)
31 def __new__(
31 def __new__(
32 _cls,
32 _cls,
33 map: PyObject,
33 map: PyObject,
34 skip: Option<PyObject> = None
34 skip: Option<PyObject> = None
35 ) -> PyResult<Self> {
35 ) -> PyResult<Self> {
36 let mut skip_state: Option<EntryState> = None;
36 let mut skip_state: Option<EntryState> = None;
37 if let Some(skip) = skip {
37 if let Some(skip) = skip {
38 skip_state = Some(
38 skip_state = Some(
39 skip.extract::<PyBytes>(py)?.data(py)[0]
39 skip.extract::<PyBytes>(py)?.data(py)[0]
40 .try_into()
40 .try_into()
41 .map_err(|e: HgError| {
41 .map_err(|e: HgError| {
42 PyErr::new::<exc::ValueError, _>(py, e.to_string())
42 PyErr::new::<exc::ValueError, _>(py, e.to_string())
43 })?,
43 })?,
44 );
44 );
45 }
45 }
46 let inner = if let Ok(map) = map.cast_as::<PyDict>(py) {
46 let inner = if let Ok(map) = map.cast_as::<PyDict>(py) {
47 let dirstate = extract_dirstate(py, &map)?;
47 let dirstate = extract_dirstate(py, &map)?;
48 DirsMultiset::from_dirstate(&dirstate, skip_state)
48 let dirstate = dirstate.iter().map(|(k, v)| (k, *v));
49 DirsMultiset::from_dirstate(dirstate, skip_state)
49 .map_err(|e: DirstateMapError| {
50 .map_err(|e: DirstateMapError| {
50 PyErr::new::<exc::ValueError, _>(py, e.to_string())
51 PyErr::new::<exc::ValueError, _>(py, e.to_string())
51 })?
52 })?
52 } else {
53 } else {
53 let map: Result<Vec<HgPathBuf>, PyErr> = map
54 let map: Result<Vec<HgPathBuf>, PyErr> = map
54 .iter(py)?
55 .iter(py)?
55 .map(|o| {
56 .map(|o| {
56 Ok(HgPathBuf::from_bytes(
57 Ok(HgPathBuf::from_bytes(
57 o?.extract::<PyBytes>(py)?.data(py),
58 o?.extract::<PyBytes>(py)?.data(py),
58 ))
59 ))
59 })
60 })
60 .collect();
61 .collect();
61 DirsMultiset::from_manifest(&map?)
62 DirsMultiset::from_manifest(&map?)
62 .map_err(|e| {
63 .map_err(|e| {
63 PyErr::new::<exc::ValueError, _>(py, e.to_string())
64 PyErr::new::<exc::ValueError, _>(py, e.to_string())
64 })?
65 })?
65 };
66 };
66
67
67 Self::create_instance(py, inner)
68 Self::create_instance(py, inner)
68 }
69 }
69
70
70 def addpath(&self, path: PyObject) -> PyResult<PyObject> {
71 def addpath(&self, path: PyObject) -> PyResult<PyObject> {
71 self.inner(py).borrow_mut().add_path(
72 self.inner(py).borrow_mut().add_path(
72 HgPath::new(path.extract::<PyBytes>(py)?.data(py)),
73 HgPath::new(path.extract::<PyBytes>(py)?.data(py)),
73 ).and(Ok(py.None())).or_else(|e| {
74 ).and(Ok(py.None())).or_else(|e| {
74 match e {
75 match e {
75 DirstateMapError::EmptyPath => {
76 DirstateMapError::EmptyPath => {
76 Ok(py.None())
77 Ok(py.None())
77 },
78 },
78 e => {
79 e => {
79 Err(PyErr::new::<exc::ValueError, _>(
80 Err(PyErr::new::<exc::ValueError, _>(
80 py,
81 py,
81 e.to_string(),
82 e.to_string(),
82 ))
83 ))
83 }
84 }
84 }
85 }
85 })
86 })
86 }
87 }
87
88
88 def delpath(&self, path: PyObject) -> PyResult<PyObject> {
89 def delpath(&self, path: PyObject) -> PyResult<PyObject> {
89 self.inner(py).borrow_mut().delete_path(
90 self.inner(py).borrow_mut().delete_path(
90 HgPath::new(path.extract::<PyBytes>(py)?.data(py)),
91 HgPath::new(path.extract::<PyBytes>(py)?.data(py)),
91 )
92 )
92 .and(Ok(py.None()))
93 .and(Ok(py.None()))
93 .or_else(|e| {
94 .or_else(|e| {
94 match e {
95 match e {
95 DirstateMapError::EmptyPath => {
96 DirstateMapError::EmptyPath => {
96 Ok(py.None())
97 Ok(py.None())
97 },
98 },
98 e => {
99 e => {
99 Err(PyErr::new::<exc::ValueError, _>(
100 Err(PyErr::new::<exc::ValueError, _>(
100 py,
101 py,
101 e.to_string(),
102 e.to_string(),
102 ))
103 ))
103 }
104 }
104 }
105 }
105 })
106 })
106 }
107 }
107 def __iter__(&self) -> PyResult<DirsMultisetKeysIterator> {
108 def __iter__(&self) -> PyResult<DirsMultisetKeysIterator> {
108 let leaked_ref = self.inner(py).leak_immutable();
109 let leaked_ref = self.inner(py).leak_immutable();
109 DirsMultisetKeysIterator::from_inner(
110 DirsMultisetKeysIterator::from_inner(
110 py,
111 py,
111 unsafe { leaked_ref.map(py, |o| o.iter()) },
112 unsafe { leaked_ref.map(py, |o| o.iter()) },
112 )
113 )
113 }
114 }
114
115
115 def __contains__(&self, item: PyObject) -> PyResult<bool> {
116 def __contains__(&self, item: PyObject) -> PyResult<bool> {
116 Ok(self.inner(py).borrow().contains(HgPath::new(
117 Ok(self.inner(py).borrow().contains(HgPath::new(
117 item.extract::<PyBytes>(py)?.data(py).as_ref(),
118 item.extract::<PyBytes>(py)?.data(py).as_ref(),
118 )))
119 )))
119 }
120 }
120 });
121 });
121
122
122 impl Dirs {
123 impl Dirs {
123 pub fn from_inner(py: Python, d: DirsMultiset) -> PyResult<Self> {
124 pub fn from_inner(py: Python, d: DirsMultiset) -> PyResult<Self> {
124 Self::create_instance(py, d)
125 Self::create_instance(py, d)
125 }
126 }
126
127
127 fn translate_key(
128 fn translate_key(
128 py: Python,
129 py: Python,
129 res: &HgPathBuf,
130 res: &HgPathBuf,
130 ) -> PyResult<Option<PyBytes>> {
131 ) -> PyResult<Option<PyBytes>> {
131 Ok(Some(PyBytes::new(py, res.as_bytes())))
132 Ok(Some(PyBytes::new(py, res.as_bytes())))
132 }
133 }
133 }
134 }
134
135
135 py_shared_iterator!(
136 py_shared_iterator!(
136 DirsMultisetKeysIterator,
137 DirsMultisetKeysIterator,
137 UnsafePyLeaked<DirsMultisetIter<'static>>,
138 UnsafePyLeaked<DirsMultisetIter<'static>>,
138 Dirs::translate_key,
139 Dirs::translate_key,
139 Option<PyBytes>
140 Option<PyBytes>
140 );
141 );
@@ -1,564 +1,564 b''
1 // dirstate_map.rs
1 // dirstate_map.rs
2 //
2 //
3 // Copyright 2019 Raphaël Gomès <rgomes@octobus.net>
3 // Copyright 2019 Raphaël Gomès <rgomes@octobus.net>
4 //
4 //
5 // This software may be used and distributed according to the terms of the
5 // This software may be used and distributed according to the terms of the
6 // GNU General Public License version 2 or any later version.
6 // GNU General Public License version 2 or any later version.
7
7
8 //! Bindings for the `hg::dirstate::dirstate_map` file provided by the
8 //! Bindings for the `hg::dirstate::dirstate_map` file provided by the
9 //! `hg-core` package.
9 //! `hg-core` package.
10
10
11 use std::cell::{RefCell, RefMut};
11 use std::cell::{RefCell, RefMut};
12 use std::convert::TryInto;
12 use std::convert::TryInto;
13
13
14 use cpython::{
14 use cpython::{
15 exc, ObjectProtocol, PyBool, PyBytes, PyClone, PyDict, PyErr, PyList,
15 exc, ObjectProtocol, PyBool, PyBytes, PyClone, PyDict, PyErr, PyList,
16 PyObject, PyResult, PySet, PyString, Python, PythonObject, ToPyObject,
16 PyObject, PyResult, PySet, PyString, Python, PythonObject, ToPyObject,
17 UnsafePyLeaked,
17 UnsafePyLeaked,
18 };
18 };
19
19
20 use crate::{
20 use crate::{
21 dirstate::copymap::{CopyMap, CopyMapItemsIterator, CopyMapKeysIterator},
21 dirstate::copymap::{CopyMap, CopyMapItemsIterator, CopyMapKeysIterator},
22 dirstate::non_normal_entries::{
22 dirstate::non_normal_entries::{
23 NonNormalEntries, NonNormalEntriesIterator,
23 NonNormalEntries, NonNormalEntriesIterator,
24 },
24 },
25 dirstate::owning::OwningDirstateMap,
25 dirstate::owning::OwningDirstateMap,
26 dirstate::{dirs_multiset::Dirs, make_dirstate_tuple},
26 dirstate::{dirs_multiset::Dirs, make_dirstate_tuple},
27 parsers::dirstate_parents_to_pytuple,
27 parsers::dirstate_parents_to_pytuple,
28 };
28 };
29 use hg::{
29 use hg::{
30 dirstate::parsers::Timestamp,
30 dirstate::parsers::Timestamp,
31 dirstate_tree::dispatch::DirstateMapMethods,
31 dirstate_tree::dispatch::DirstateMapMethods,
32 errors::HgError,
32 errors::HgError,
33 revlog::Node,
33 revlog::Node,
34 utils::files::normalize_case,
34 utils::files::normalize_case,
35 utils::hg_path::{HgPath, HgPathBuf},
35 utils::hg_path::{HgPath, HgPathBuf},
36 DirsMultiset, DirstateEntry, DirstateError,
36 DirsMultiset, DirstateEntry, DirstateError,
37 DirstateMap as RustDirstateMap, DirstateMapError, DirstateParents,
37 DirstateMap as RustDirstateMap, DirstateMapError, DirstateParents,
38 EntryState, StateMapIter,
38 EntryState, StateMapIter,
39 };
39 };
40
40
41 // TODO
41 // TODO
42 // This object needs to share references to multiple members of its Rust
42 // This object needs to share references to multiple members of its Rust
43 // inner struct, namely `copy_map`, `dirs` and `all_dirs`.
43 // inner struct, namely `copy_map`, `dirs` and `all_dirs`.
44 // Right now `CopyMap` is done, but it needs to have an explicit reference
44 // Right now `CopyMap` is done, but it needs to have an explicit reference
45 // to `RustDirstateMap` which itself needs to have an encapsulation for
45 // to `RustDirstateMap` which itself needs to have an encapsulation for
46 // every method in `CopyMap` (copymapcopy, etc.).
46 // every method in `CopyMap` (copymapcopy, etc.).
47 // This is ugly and hard to maintain.
47 // This is ugly and hard to maintain.
48 // The same logic applies to `dirs` and `all_dirs`, however the `Dirs`
48 // The same logic applies to `dirs` and `all_dirs`, however the `Dirs`
49 // `py_class!` is already implemented and does not mention
49 // `py_class!` is already implemented and does not mention
50 // `RustDirstateMap`, rightfully so.
50 // `RustDirstateMap`, rightfully so.
51 // All attributes also have to have a separate refcount data attribute for
51 // All attributes also have to have a separate refcount data attribute for
52 // leaks, with all methods that go along for reference sharing.
52 // leaks, with all methods that go along for reference sharing.
53 py_class!(pub class DirstateMap |py| {
53 py_class!(pub class DirstateMap |py| {
54 @shared data inner: Box<dyn DirstateMapMethods + Send>;
54 @shared data inner: Box<dyn DirstateMapMethods + Send>;
55
55
56 /// Returns a `(dirstate_map, parents)` tuple
56 /// Returns a `(dirstate_map, parents)` tuple
57 @staticmethod
57 @staticmethod
58 def new(
58 def new(
59 use_dirstate_tree: bool,
59 use_dirstate_tree: bool,
60 use_dirstate_v2: bool,
60 use_dirstate_v2: bool,
61 on_disk: PyBytes,
61 on_disk: PyBytes,
62 ) -> PyResult<PyObject> {
62 ) -> PyResult<PyObject> {
63 let dirstate_error = |e: DirstateError| {
63 let dirstate_error = |e: DirstateError| {
64 PyErr::new::<exc::OSError, _>(py, format!("Dirstate error: {:?}", e))
64 PyErr::new::<exc::OSError, _>(py, format!("Dirstate error: {:?}", e))
65 };
65 };
66 let (inner, parents) = if use_dirstate_tree || use_dirstate_v2 {
66 let (inner, parents) = if use_dirstate_tree || use_dirstate_v2 {
67 let (map, parents) =
67 let (map, parents) =
68 OwningDirstateMap::new(py, on_disk, use_dirstate_v2)
68 OwningDirstateMap::new(py, on_disk, use_dirstate_v2)
69 .map_err(dirstate_error)?;
69 .map_err(dirstate_error)?;
70 (Box::new(map) as _, parents)
70 (Box::new(map) as _, parents)
71 } else {
71 } else {
72 let bytes = on_disk.data(py);
72 let bytes = on_disk.data(py);
73 let mut map = RustDirstateMap::default();
73 let mut map = RustDirstateMap::default();
74 let parents = map.read(bytes).map_err(dirstate_error)?;
74 let parents = map.read(bytes).map_err(dirstate_error)?;
75 (Box::new(map) as _, parents)
75 (Box::new(map) as _, parents)
76 };
76 };
77 let map = Self::create_instance(py, inner)?;
77 let map = Self::create_instance(py, inner)?;
78 let parents = parents.map(|p| dirstate_parents_to_pytuple(py, &p));
78 let parents = parents.map(|p| dirstate_parents_to_pytuple(py, &p));
79 Ok((map, parents).to_py_object(py).into_object())
79 Ok((map, parents).to_py_object(py).into_object())
80 }
80 }
81
81
82 def clear(&self) -> PyResult<PyObject> {
82 def clear(&self) -> PyResult<PyObject> {
83 self.inner(py).borrow_mut().clear();
83 self.inner(py).borrow_mut().clear();
84 Ok(py.None())
84 Ok(py.None())
85 }
85 }
86
86
87 def get(
87 def get(
88 &self,
88 &self,
89 key: PyObject,
89 key: PyObject,
90 default: Option<PyObject> = None
90 default: Option<PyObject> = None
91 ) -> PyResult<Option<PyObject>> {
91 ) -> PyResult<Option<PyObject>> {
92 let key = key.extract::<PyBytes>(py)?;
92 let key = key.extract::<PyBytes>(py)?;
93 match self.inner(py).borrow().get(HgPath::new(key.data(py))) {
93 match self.inner(py).borrow().get(HgPath::new(key.data(py))) {
94 Some(entry) => {
94 Some(entry) => {
95 Ok(Some(make_dirstate_tuple(py, entry)?))
95 Ok(Some(make_dirstate_tuple(py, &entry)?))
96 },
96 },
97 None => Ok(default)
97 None => Ok(default)
98 }
98 }
99 }
99 }
100
100
101 def addfile(
101 def addfile(
102 &self,
102 &self,
103 f: PyObject,
103 f: PyObject,
104 oldstate: PyObject,
104 oldstate: PyObject,
105 state: PyObject,
105 state: PyObject,
106 mode: PyObject,
106 mode: PyObject,
107 size: PyObject,
107 size: PyObject,
108 mtime: PyObject
108 mtime: PyObject
109 ) -> PyResult<PyObject> {
109 ) -> PyResult<PyObject> {
110 self.inner(py).borrow_mut().add_file(
110 self.inner(py).borrow_mut().add_file(
111 HgPath::new(f.extract::<PyBytes>(py)?.data(py)),
111 HgPath::new(f.extract::<PyBytes>(py)?.data(py)),
112 oldstate.extract::<PyBytes>(py)?.data(py)[0]
112 oldstate.extract::<PyBytes>(py)?.data(py)[0]
113 .try_into()
113 .try_into()
114 .map_err(|e: HgError| {
114 .map_err(|e: HgError| {
115 PyErr::new::<exc::ValueError, _>(py, e.to_string())
115 PyErr::new::<exc::ValueError, _>(py, e.to_string())
116 })?,
116 })?,
117 DirstateEntry {
117 DirstateEntry {
118 state: state.extract::<PyBytes>(py)?.data(py)[0]
118 state: state.extract::<PyBytes>(py)?.data(py)[0]
119 .try_into()
119 .try_into()
120 .map_err(|e: HgError| {
120 .map_err(|e: HgError| {
121 PyErr::new::<exc::ValueError, _>(py, e.to_string())
121 PyErr::new::<exc::ValueError, _>(py, e.to_string())
122 })?,
122 })?,
123 mode: mode.extract(py)?,
123 mode: mode.extract(py)?,
124 size: size.extract(py)?,
124 size: size.extract(py)?,
125 mtime: mtime.extract(py)?,
125 mtime: mtime.extract(py)?,
126 },
126 },
127 ).and(Ok(py.None())).or_else(|e: DirstateMapError| {
127 ).and(Ok(py.None())).or_else(|e: DirstateMapError| {
128 Err(PyErr::new::<exc::ValueError, _>(py, e.to_string()))
128 Err(PyErr::new::<exc::ValueError, _>(py, e.to_string()))
129 })
129 })
130 }
130 }
131
131
132 def removefile(
132 def removefile(
133 &self,
133 &self,
134 f: PyObject,
134 f: PyObject,
135 oldstate: PyObject,
135 oldstate: PyObject,
136 size: PyObject
136 size: PyObject
137 ) -> PyResult<PyObject> {
137 ) -> PyResult<PyObject> {
138 self.inner(py).borrow_mut()
138 self.inner(py).borrow_mut()
139 .remove_file(
139 .remove_file(
140 HgPath::new(f.extract::<PyBytes>(py)?.data(py)),
140 HgPath::new(f.extract::<PyBytes>(py)?.data(py)),
141 oldstate.extract::<PyBytes>(py)?.data(py)[0]
141 oldstate.extract::<PyBytes>(py)?.data(py)[0]
142 .try_into()
142 .try_into()
143 .map_err(|e: HgError| {
143 .map_err(|e: HgError| {
144 PyErr::new::<exc::ValueError, _>(py, e.to_string())
144 PyErr::new::<exc::ValueError, _>(py, e.to_string())
145 })?,
145 })?,
146 size.extract(py)?,
146 size.extract(py)?,
147 )
147 )
148 .or_else(|_| {
148 .or_else(|_| {
149 Err(PyErr::new::<exc::OSError, _>(
149 Err(PyErr::new::<exc::OSError, _>(
150 py,
150 py,
151 "Dirstate error".to_string(),
151 "Dirstate error".to_string(),
152 ))
152 ))
153 })?;
153 })?;
154 Ok(py.None())
154 Ok(py.None())
155 }
155 }
156
156
157 def dropfile(
157 def dropfile(
158 &self,
158 &self,
159 f: PyObject,
159 f: PyObject,
160 oldstate: PyObject
160 oldstate: PyObject
161 ) -> PyResult<PyBool> {
161 ) -> PyResult<PyBool> {
162 self.inner(py).borrow_mut()
162 self.inner(py).borrow_mut()
163 .drop_file(
163 .drop_file(
164 HgPath::new(f.extract::<PyBytes>(py)?.data(py)),
164 HgPath::new(f.extract::<PyBytes>(py)?.data(py)),
165 oldstate.extract::<PyBytes>(py)?.data(py)[0]
165 oldstate.extract::<PyBytes>(py)?.data(py)[0]
166 .try_into()
166 .try_into()
167 .map_err(|e: HgError| {
167 .map_err(|e: HgError| {
168 PyErr::new::<exc::ValueError, _>(py, e.to_string())
168 PyErr::new::<exc::ValueError, _>(py, e.to_string())
169 })?,
169 })?,
170 )
170 )
171 .and_then(|b| Ok(b.to_py_object(py)))
171 .and_then(|b| Ok(b.to_py_object(py)))
172 .or_else(|e| {
172 .or_else(|e| {
173 Err(PyErr::new::<exc::OSError, _>(
173 Err(PyErr::new::<exc::OSError, _>(
174 py,
174 py,
175 format!("Dirstate error: {}", e.to_string()),
175 format!("Dirstate error: {}", e.to_string()),
176 ))
176 ))
177 })
177 })
178 }
178 }
179
179
180 def clearambiguoustimes(
180 def clearambiguoustimes(
181 &self,
181 &self,
182 files: PyObject,
182 files: PyObject,
183 now: PyObject
183 now: PyObject
184 ) -> PyResult<PyObject> {
184 ) -> PyResult<PyObject> {
185 let files: PyResult<Vec<HgPathBuf>> = files
185 let files: PyResult<Vec<HgPathBuf>> = files
186 .iter(py)?
186 .iter(py)?
187 .map(|filename| {
187 .map(|filename| {
188 Ok(HgPathBuf::from_bytes(
188 Ok(HgPathBuf::from_bytes(
189 filename?.extract::<PyBytes>(py)?.data(py),
189 filename?.extract::<PyBytes>(py)?.data(py),
190 ))
190 ))
191 })
191 })
192 .collect();
192 .collect();
193 self.inner(py).borrow_mut()
193 self.inner(py).borrow_mut()
194 .clear_ambiguous_times(files?, now.extract(py)?);
194 .clear_ambiguous_times(files?, now.extract(py)?);
195 Ok(py.None())
195 Ok(py.None())
196 }
196 }
197
197
198 def other_parent_entries(&self) -> PyResult<PyObject> {
198 def other_parent_entries(&self) -> PyResult<PyObject> {
199 let mut inner_shared = self.inner(py).borrow_mut();
199 let mut inner_shared = self.inner(py).borrow_mut();
200 let set = PySet::empty(py)?;
200 let set = PySet::empty(py)?;
201 for path in inner_shared.iter_other_parent_paths() {
201 for path in inner_shared.iter_other_parent_paths() {
202 set.add(py, PyBytes::new(py, path.as_bytes()))?;
202 set.add(py, PyBytes::new(py, path.as_bytes()))?;
203 }
203 }
204 Ok(set.into_object())
204 Ok(set.into_object())
205 }
205 }
206
206
207 def non_normal_entries(&self) -> PyResult<NonNormalEntries> {
207 def non_normal_entries(&self) -> PyResult<NonNormalEntries> {
208 NonNormalEntries::from_inner(py, self.clone_ref(py))
208 NonNormalEntries::from_inner(py, self.clone_ref(py))
209 }
209 }
210
210
211 def non_normal_entries_contains(&self, key: PyObject) -> PyResult<bool> {
211 def non_normal_entries_contains(&self, key: PyObject) -> PyResult<bool> {
212 let key = key.extract::<PyBytes>(py)?;
212 let key = key.extract::<PyBytes>(py)?;
213 Ok(self
213 Ok(self
214 .inner(py)
214 .inner(py)
215 .borrow_mut()
215 .borrow_mut()
216 .non_normal_entries_contains(HgPath::new(key.data(py))))
216 .non_normal_entries_contains(HgPath::new(key.data(py))))
217 }
217 }
218
218
219 def non_normal_entries_display(&self) -> PyResult<PyString> {
219 def non_normal_entries_display(&self) -> PyResult<PyString> {
220 Ok(
220 Ok(
221 PyString::new(
221 PyString::new(
222 py,
222 py,
223 &format!(
223 &format!(
224 "NonNormalEntries: {}",
224 "NonNormalEntries: {}",
225 hg::utils::join_display(
225 hg::utils::join_display(
226 self
226 self
227 .inner(py)
227 .inner(py)
228 .borrow_mut()
228 .borrow_mut()
229 .iter_non_normal_paths(),
229 .iter_non_normal_paths(),
230 ", "
230 ", "
231 )
231 )
232 )
232 )
233 )
233 )
234 )
234 )
235 }
235 }
236
236
237 def non_normal_entries_remove(&self, key: PyObject) -> PyResult<PyObject> {
237 def non_normal_entries_remove(&self, key: PyObject) -> PyResult<PyObject> {
238 let key = key.extract::<PyBytes>(py)?;
238 let key = key.extract::<PyBytes>(py)?;
239 self
239 self
240 .inner(py)
240 .inner(py)
241 .borrow_mut()
241 .borrow_mut()
242 .non_normal_entries_remove(HgPath::new(key.data(py)));
242 .non_normal_entries_remove(HgPath::new(key.data(py)));
243 Ok(py.None())
243 Ok(py.None())
244 }
244 }
245
245
246 def non_normal_or_other_parent_paths(&self) -> PyResult<PyList> {
246 def non_normal_or_other_parent_paths(&self) -> PyResult<PyList> {
247 let mut inner = self.inner(py).borrow_mut();
247 let mut inner = self.inner(py).borrow_mut();
248
248
249 let ret = PyList::new(py, &[]);
249 let ret = PyList::new(py, &[]);
250 for filename in inner.non_normal_or_other_parent_paths() {
250 for filename in inner.non_normal_or_other_parent_paths() {
251 let as_pystring = PyBytes::new(py, filename.as_bytes());
251 let as_pystring = PyBytes::new(py, filename.as_bytes());
252 ret.append(py, as_pystring.into_object());
252 ret.append(py, as_pystring.into_object());
253 }
253 }
254 Ok(ret)
254 Ok(ret)
255 }
255 }
256
256
257 def non_normal_entries_iter(&self) -> PyResult<NonNormalEntriesIterator> {
257 def non_normal_entries_iter(&self) -> PyResult<NonNormalEntriesIterator> {
258 // Make sure the sets are defined before we no longer have a mutable
258 // Make sure the sets are defined before we no longer have a mutable
259 // reference to the dmap.
259 // reference to the dmap.
260 self.inner(py)
260 self.inner(py)
261 .borrow_mut()
261 .borrow_mut()
262 .set_non_normal_other_parent_entries(false);
262 .set_non_normal_other_parent_entries(false);
263
263
264 let leaked_ref = self.inner(py).leak_immutable();
264 let leaked_ref = self.inner(py).leak_immutable();
265
265
266 NonNormalEntriesIterator::from_inner(py, unsafe {
266 NonNormalEntriesIterator::from_inner(py, unsafe {
267 leaked_ref.map(py, |o| {
267 leaked_ref.map(py, |o| {
268 o.iter_non_normal_paths_panic()
268 o.iter_non_normal_paths_panic()
269 })
269 })
270 })
270 })
271 }
271 }
272
272
273 def hastrackeddir(&self, d: PyObject) -> PyResult<PyBool> {
273 def hastrackeddir(&self, d: PyObject) -> PyResult<PyBool> {
274 let d = d.extract::<PyBytes>(py)?;
274 let d = d.extract::<PyBytes>(py)?;
275 Ok(self.inner(py).borrow_mut()
275 Ok(self.inner(py).borrow_mut()
276 .has_tracked_dir(HgPath::new(d.data(py)))
276 .has_tracked_dir(HgPath::new(d.data(py)))
277 .map_err(|e| {
277 .map_err(|e| {
278 PyErr::new::<exc::ValueError, _>(py, e.to_string())
278 PyErr::new::<exc::ValueError, _>(py, e.to_string())
279 })?
279 })?
280 .to_py_object(py))
280 .to_py_object(py))
281 }
281 }
282
282
283 def hasdir(&self, d: PyObject) -> PyResult<PyBool> {
283 def hasdir(&self, d: PyObject) -> PyResult<PyBool> {
284 let d = d.extract::<PyBytes>(py)?;
284 let d = d.extract::<PyBytes>(py)?;
285 Ok(self.inner(py).borrow_mut()
285 Ok(self.inner(py).borrow_mut()
286 .has_dir(HgPath::new(d.data(py)))
286 .has_dir(HgPath::new(d.data(py)))
287 .map_err(|e| {
287 .map_err(|e| {
288 PyErr::new::<exc::ValueError, _>(py, e.to_string())
288 PyErr::new::<exc::ValueError, _>(py, e.to_string())
289 })?
289 })?
290 .to_py_object(py))
290 .to_py_object(py))
291 }
291 }
292
292
293 def write(
293 def write(
294 &self,
294 &self,
295 use_dirstate_v2: bool,
295 use_dirstate_v2: bool,
296 p1: PyObject,
296 p1: PyObject,
297 p2: PyObject,
297 p2: PyObject,
298 now: PyObject
298 now: PyObject
299 ) -> PyResult<PyBytes> {
299 ) -> PyResult<PyBytes> {
300 let now = Timestamp(now.extract(py)?);
300 let now = Timestamp(now.extract(py)?);
301 let parents = DirstateParents {
301 let parents = DirstateParents {
302 p1: extract_node_id(py, &p1)?,
302 p1: extract_node_id(py, &p1)?,
303 p2: extract_node_id(py, &p2)?,
303 p2: extract_node_id(py, &p2)?,
304 };
304 };
305
305
306 let mut inner = self.inner(py).borrow_mut();
306 let mut inner = self.inner(py).borrow_mut();
307 let result = if use_dirstate_v2 {
307 let result = if use_dirstate_v2 {
308 inner.pack_v2(parents, now)
308 inner.pack_v2(parents, now)
309 } else {
309 } else {
310 inner.pack_v1(parents, now)
310 inner.pack_v1(parents, now)
311 };
311 };
312 match result {
312 match result {
313 Ok(packed) => Ok(PyBytes::new(py, &packed)),
313 Ok(packed) => Ok(PyBytes::new(py, &packed)),
314 Err(_) => Err(PyErr::new::<exc::OSError, _>(
314 Err(_) => Err(PyErr::new::<exc::OSError, _>(
315 py,
315 py,
316 "Dirstate error".to_string(),
316 "Dirstate error".to_string(),
317 )),
317 )),
318 }
318 }
319 }
319 }
320
320
321 def filefoldmapasdict(&self) -> PyResult<PyDict> {
321 def filefoldmapasdict(&self) -> PyResult<PyDict> {
322 let dict = PyDict::new(py);
322 let dict = PyDict::new(py);
323 for (path, entry) in self.inner(py).borrow_mut().iter() {
323 for (path, entry) in self.inner(py).borrow_mut().iter() {
324 if entry.state != EntryState::Removed {
324 if entry.state != EntryState::Removed {
325 let key = normalize_case(path);
325 let key = normalize_case(path);
326 let value = path;
326 let value = path;
327 dict.set_item(
327 dict.set_item(
328 py,
328 py,
329 PyBytes::new(py, key.as_bytes()).into_object(),
329 PyBytes::new(py, key.as_bytes()).into_object(),
330 PyBytes::new(py, value.as_bytes()).into_object(),
330 PyBytes::new(py, value.as_bytes()).into_object(),
331 )?;
331 )?;
332 }
332 }
333 }
333 }
334 Ok(dict)
334 Ok(dict)
335 }
335 }
336
336
337 def __len__(&self) -> PyResult<usize> {
337 def __len__(&self) -> PyResult<usize> {
338 Ok(self.inner(py).borrow().len())
338 Ok(self.inner(py).borrow().len())
339 }
339 }
340
340
341 def __contains__(&self, key: PyObject) -> PyResult<bool> {
341 def __contains__(&self, key: PyObject) -> PyResult<bool> {
342 let key = key.extract::<PyBytes>(py)?;
342 let key = key.extract::<PyBytes>(py)?;
343 Ok(self.inner(py).borrow().contains_key(HgPath::new(key.data(py))))
343 Ok(self.inner(py).borrow().contains_key(HgPath::new(key.data(py))))
344 }
344 }
345
345
346 def __getitem__(&self, key: PyObject) -> PyResult<PyObject> {
346 def __getitem__(&self, key: PyObject) -> PyResult<PyObject> {
347 let key = key.extract::<PyBytes>(py)?;
347 let key = key.extract::<PyBytes>(py)?;
348 let key = HgPath::new(key.data(py));
348 let key = HgPath::new(key.data(py));
349 match self.inner(py).borrow().get(key) {
349 match self.inner(py).borrow().get(key) {
350 Some(entry) => {
350 Some(entry) => {
351 Ok(make_dirstate_tuple(py, entry)?)
351 Ok(make_dirstate_tuple(py, &entry)?)
352 },
352 },
353 None => Err(PyErr::new::<exc::KeyError, _>(
353 None => Err(PyErr::new::<exc::KeyError, _>(
354 py,
354 py,
355 String::from_utf8_lossy(key.as_bytes()),
355 String::from_utf8_lossy(key.as_bytes()),
356 )),
356 )),
357 }
357 }
358 }
358 }
359
359
360 def keys(&self) -> PyResult<DirstateMapKeysIterator> {
360 def keys(&self) -> PyResult<DirstateMapKeysIterator> {
361 let leaked_ref = self.inner(py).leak_immutable();
361 let leaked_ref = self.inner(py).leak_immutable();
362 DirstateMapKeysIterator::from_inner(
362 DirstateMapKeysIterator::from_inner(
363 py,
363 py,
364 unsafe { leaked_ref.map(py, |o| o.iter()) },
364 unsafe { leaked_ref.map(py, |o| o.iter()) },
365 )
365 )
366 }
366 }
367
367
368 def items(&self) -> PyResult<DirstateMapItemsIterator> {
368 def items(&self) -> PyResult<DirstateMapItemsIterator> {
369 let leaked_ref = self.inner(py).leak_immutable();
369 let leaked_ref = self.inner(py).leak_immutable();
370 DirstateMapItemsIterator::from_inner(
370 DirstateMapItemsIterator::from_inner(
371 py,
371 py,
372 unsafe { leaked_ref.map(py, |o| o.iter()) },
372 unsafe { leaked_ref.map(py, |o| o.iter()) },
373 )
373 )
374 }
374 }
375
375
376 def __iter__(&self) -> PyResult<DirstateMapKeysIterator> {
376 def __iter__(&self) -> PyResult<DirstateMapKeysIterator> {
377 let leaked_ref = self.inner(py).leak_immutable();
377 let leaked_ref = self.inner(py).leak_immutable();
378 DirstateMapKeysIterator::from_inner(
378 DirstateMapKeysIterator::from_inner(
379 py,
379 py,
380 unsafe { leaked_ref.map(py, |o| o.iter()) },
380 unsafe { leaked_ref.map(py, |o| o.iter()) },
381 )
381 )
382 }
382 }
383
383
384 def getdirs(&self) -> PyResult<Dirs> {
384 def getdirs(&self) -> PyResult<Dirs> {
385 // TODO don't copy, share the reference
385 // TODO don't copy, share the reference
386 self.inner(py).borrow_mut().set_dirs()
386 self.inner(py).borrow_mut().set_dirs()
387 .map_err(|e| {
387 .map_err(|e| {
388 PyErr::new::<exc::ValueError, _>(py, e.to_string())
388 PyErr::new::<exc::ValueError, _>(py, e.to_string())
389 })?;
389 })?;
390 Dirs::from_inner(
390 Dirs::from_inner(
391 py,
391 py,
392 DirsMultiset::from_dirstate(
392 DirsMultiset::from_dirstate(
393 self.inner(py).borrow().iter(),
393 self.inner(py).borrow().iter(),
394 Some(EntryState::Removed),
394 Some(EntryState::Removed),
395 )
395 )
396 .map_err(|e| {
396 .map_err(|e| {
397 PyErr::new::<exc::ValueError, _>(py, e.to_string())
397 PyErr::new::<exc::ValueError, _>(py, e.to_string())
398 })?,
398 })?,
399 )
399 )
400 }
400 }
401 def getalldirs(&self) -> PyResult<Dirs> {
401 def getalldirs(&self) -> PyResult<Dirs> {
402 // TODO don't copy, share the reference
402 // TODO don't copy, share the reference
403 self.inner(py).borrow_mut().set_all_dirs()
403 self.inner(py).borrow_mut().set_all_dirs()
404 .map_err(|e| {
404 .map_err(|e| {
405 PyErr::new::<exc::ValueError, _>(py, e.to_string())
405 PyErr::new::<exc::ValueError, _>(py, e.to_string())
406 })?;
406 })?;
407 Dirs::from_inner(
407 Dirs::from_inner(
408 py,
408 py,
409 DirsMultiset::from_dirstate(
409 DirsMultiset::from_dirstate(
410 self.inner(py).borrow().iter(),
410 self.inner(py).borrow().iter(),
411 None,
411 None,
412 ).map_err(|e| {
412 ).map_err(|e| {
413 PyErr::new::<exc::ValueError, _>(py, e.to_string())
413 PyErr::new::<exc::ValueError, _>(py, e.to_string())
414 })?,
414 })?,
415 )
415 )
416 }
416 }
417
417
418 // TODO all copymap* methods, see docstring above
418 // TODO all copymap* methods, see docstring above
419 def copymapcopy(&self) -> PyResult<PyDict> {
419 def copymapcopy(&self) -> PyResult<PyDict> {
420 let dict = PyDict::new(py);
420 let dict = PyDict::new(py);
421 for (key, value) in self.inner(py).borrow().copy_map_iter() {
421 for (key, value) in self.inner(py).borrow().copy_map_iter() {
422 dict.set_item(
422 dict.set_item(
423 py,
423 py,
424 PyBytes::new(py, key.as_bytes()),
424 PyBytes::new(py, key.as_bytes()),
425 PyBytes::new(py, value.as_bytes()),
425 PyBytes::new(py, value.as_bytes()),
426 )?;
426 )?;
427 }
427 }
428 Ok(dict)
428 Ok(dict)
429 }
429 }
430
430
431 def copymapgetitem(&self, key: PyObject) -> PyResult<PyBytes> {
431 def copymapgetitem(&self, key: PyObject) -> PyResult<PyBytes> {
432 let key = key.extract::<PyBytes>(py)?;
432 let key = key.extract::<PyBytes>(py)?;
433 match self.inner(py).borrow().copy_map_get(HgPath::new(key.data(py))) {
433 match self.inner(py).borrow().copy_map_get(HgPath::new(key.data(py))) {
434 Some(copy) => Ok(PyBytes::new(py, copy.as_bytes())),
434 Some(copy) => Ok(PyBytes::new(py, copy.as_bytes())),
435 None => Err(PyErr::new::<exc::KeyError, _>(
435 None => Err(PyErr::new::<exc::KeyError, _>(
436 py,
436 py,
437 String::from_utf8_lossy(key.data(py)),
437 String::from_utf8_lossy(key.data(py)),
438 )),
438 )),
439 }
439 }
440 }
440 }
441 def copymap(&self) -> PyResult<CopyMap> {
441 def copymap(&self) -> PyResult<CopyMap> {
442 CopyMap::from_inner(py, self.clone_ref(py))
442 CopyMap::from_inner(py, self.clone_ref(py))
443 }
443 }
444
444
445 def copymaplen(&self) -> PyResult<usize> {
445 def copymaplen(&self) -> PyResult<usize> {
446 Ok(self.inner(py).borrow().copy_map_len())
446 Ok(self.inner(py).borrow().copy_map_len())
447 }
447 }
448 def copymapcontains(&self, key: PyObject) -> PyResult<bool> {
448 def copymapcontains(&self, key: PyObject) -> PyResult<bool> {
449 let key = key.extract::<PyBytes>(py)?;
449 let key = key.extract::<PyBytes>(py)?;
450 Ok(self
450 Ok(self
451 .inner(py)
451 .inner(py)
452 .borrow()
452 .borrow()
453 .copy_map_contains_key(HgPath::new(key.data(py))))
453 .copy_map_contains_key(HgPath::new(key.data(py))))
454 }
454 }
455 def copymapget(
455 def copymapget(
456 &self,
456 &self,
457 key: PyObject,
457 key: PyObject,
458 default: Option<PyObject>
458 default: Option<PyObject>
459 ) -> PyResult<Option<PyObject>> {
459 ) -> PyResult<Option<PyObject>> {
460 let key = key.extract::<PyBytes>(py)?;
460 let key = key.extract::<PyBytes>(py)?;
461 match self
461 match self
462 .inner(py)
462 .inner(py)
463 .borrow()
463 .borrow()
464 .copy_map_get(HgPath::new(key.data(py)))
464 .copy_map_get(HgPath::new(key.data(py)))
465 {
465 {
466 Some(copy) => Ok(Some(
466 Some(copy) => Ok(Some(
467 PyBytes::new(py, copy.as_bytes()).into_object(),
467 PyBytes::new(py, copy.as_bytes()).into_object(),
468 )),
468 )),
469 None => Ok(default),
469 None => Ok(default),
470 }
470 }
471 }
471 }
472 def copymapsetitem(
472 def copymapsetitem(
473 &self,
473 &self,
474 key: PyObject,
474 key: PyObject,
475 value: PyObject
475 value: PyObject
476 ) -> PyResult<PyObject> {
476 ) -> PyResult<PyObject> {
477 let key = key.extract::<PyBytes>(py)?;
477 let key = key.extract::<PyBytes>(py)?;
478 let value = value.extract::<PyBytes>(py)?;
478 let value = value.extract::<PyBytes>(py)?;
479 self.inner(py).borrow_mut().copy_map_insert(
479 self.inner(py).borrow_mut().copy_map_insert(
480 HgPathBuf::from_bytes(key.data(py)),
480 HgPathBuf::from_bytes(key.data(py)),
481 HgPathBuf::from_bytes(value.data(py)),
481 HgPathBuf::from_bytes(value.data(py)),
482 );
482 );
483 Ok(py.None())
483 Ok(py.None())
484 }
484 }
485 def copymappop(
485 def copymappop(
486 &self,
486 &self,
487 key: PyObject,
487 key: PyObject,
488 default: Option<PyObject>
488 default: Option<PyObject>
489 ) -> PyResult<Option<PyObject>> {
489 ) -> PyResult<Option<PyObject>> {
490 let key = key.extract::<PyBytes>(py)?;
490 let key = key.extract::<PyBytes>(py)?;
491 match self
491 match self
492 .inner(py)
492 .inner(py)
493 .borrow_mut()
493 .borrow_mut()
494 .copy_map_remove(HgPath::new(key.data(py)))
494 .copy_map_remove(HgPath::new(key.data(py)))
495 {
495 {
496 Some(_) => Ok(None),
496 Some(_) => Ok(None),
497 None => Ok(default),
497 None => Ok(default),
498 }
498 }
499 }
499 }
500
500
501 def copymapiter(&self) -> PyResult<CopyMapKeysIterator> {
501 def copymapiter(&self) -> PyResult<CopyMapKeysIterator> {
502 let leaked_ref = self.inner(py).leak_immutable();
502 let leaked_ref = self.inner(py).leak_immutable();
503 CopyMapKeysIterator::from_inner(
503 CopyMapKeysIterator::from_inner(
504 py,
504 py,
505 unsafe { leaked_ref.map(py, |o| o.copy_map_iter()) },
505 unsafe { leaked_ref.map(py, |o| o.copy_map_iter()) },
506 )
506 )
507 }
507 }
508
508
509 def copymapitemsiter(&self) -> PyResult<CopyMapItemsIterator> {
509 def copymapitemsiter(&self) -> PyResult<CopyMapItemsIterator> {
510 let leaked_ref = self.inner(py).leak_immutable();
510 let leaked_ref = self.inner(py).leak_immutable();
511 CopyMapItemsIterator::from_inner(
511 CopyMapItemsIterator::from_inner(
512 py,
512 py,
513 unsafe { leaked_ref.map(py, |o| o.copy_map_iter()) },
513 unsafe { leaked_ref.map(py, |o| o.copy_map_iter()) },
514 )
514 )
515 }
515 }
516
516
517 });
517 });
518
518
519 impl DirstateMap {
519 impl DirstateMap {
520 pub fn get_inner_mut<'a>(
520 pub fn get_inner_mut<'a>(
521 &'a self,
521 &'a self,
522 py: Python<'a>,
522 py: Python<'a>,
523 ) -> RefMut<'a, Box<dyn DirstateMapMethods + Send>> {
523 ) -> RefMut<'a, Box<dyn DirstateMapMethods + Send>> {
524 self.inner(py).borrow_mut()
524 self.inner(py).borrow_mut()
525 }
525 }
526 fn translate_key(
526 fn translate_key(
527 py: Python,
527 py: Python,
528 res: (&HgPath, &DirstateEntry),
528 res: (&HgPath, DirstateEntry),
529 ) -> PyResult<Option<PyBytes>> {
529 ) -> PyResult<Option<PyBytes>> {
530 Ok(Some(PyBytes::new(py, res.0.as_bytes())))
530 Ok(Some(PyBytes::new(py, res.0.as_bytes())))
531 }
531 }
532 fn translate_key_value(
532 fn translate_key_value(
533 py: Python,
533 py: Python,
534 res: (&HgPath, &DirstateEntry),
534 res: (&HgPath, DirstateEntry),
535 ) -> PyResult<Option<(PyBytes, PyObject)>> {
535 ) -> PyResult<Option<(PyBytes, PyObject)>> {
536 let (f, entry) = res;
536 let (f, entry) = res;
537 Ok(Some((
537 Ok(Some((
538 PyBytes::new(py, f.as_bytes()),
538 PyBytes::new(py, f.as_bytes()),
539 make_dirstate_tuple(py, &entry)?,
539 make_dirstate_tuple(py, &entry)?,
540 )))
540 )))
541 }
541 }
542 }
542 }
543
543
544 py_shared_iterator!(
544 py_shared_iterator!(
545 DirstateMapKeysIterator,
545 DirstateMapKeysIterator,
546 UnsafePyLeaked<StateMapIter<'static>>,
546 UnsafePyLeaked<StateMapIter<'static>>,
547 DirstateMap::translate_key,
547 DirstateMap::translate_key,
548 Option<PyBytes>
548 Option<PyBytes>
549 );
549 );
550
550
551 py_shared_iterator!(
551 py_shared_iterator!(
552 DirstateMapItemsIterator,
552 DirstateMapItemsIterator,
553 UnsafePyLeaked<StateMapIter<'static>>,
553 UnsafePyLeaked<StateMapIter<'static>>,
554 DirstateMap::translate_key_value,
554 DirstateMap::translate_key_value,
555 Option<(PyBytes, PyObject)>
555 Option<(PyBytes, PyObject)>
556 );
556 );
557
557
558 fn extract_node_id(py: Python, obj: &PyObject) -> PyResult<Node> {
558 fn extract_node_id(py: Python, obj: &PyObject) -> PyResult<Node> {
559 let bytes = obj.extract::<PyBytes>(py)?;
559 let bytes = obj.extract::<PyBytes>(py)?;
560 match bytes.data(py).try_into() {
560 match bytes.data(py).try_into() {
561 Ok(s) => Ok(s),
561 Ok(s) => Ok(s),
562 Err(e) => Err(PyErr::new::<exc::ValueError, _>(py, e.to_string())),
562 Err(e) => Err(PyErr::new::<exc::ValueError, _>(py, e.to_string())),
563 }
563 }
564 }
564 }
@@ -1,183 +1,183 b''
1 use crate::dirstate::owning::OwningDirstateMap;
1 use crate::dirstate::owning::OwningDirstateMap;
2 use hg::dirstate::parsers::Timestamp;
2 use hg::dirstate::parsers::Timestamp;
3 use hg::dirstate_tree::dispatch::DirstateMapMethods;
3 use hg::dirstate_tree::dispatch::DirstateMapMethods;
4 use hg::matchers::Matcher;
4 use hg::matchers::Matcher;
5 use hg::utils::hg_path::{HgPath, HgPathBuf};
5 use hg::utils::hg_path::{HgPath, HgPathBuf};
6 use hg::CopyMapIter;
6 use hg::CopyMapIter;
7 use hg::DirstateEntry;
7 use hg::DirstateEntry;
8 use hg::DirstateError;
8 use hg::DirstateError;
9 use hg::DirstateMapError;
9 use hg::DirstateMapError;
10 use hg::DirstateParents;
10 use hg::DirstateParents;
11 use hg::DirstateStatus;
11 use hg::DirstateStatus;
12 use hg::EntryState;
12 use hg::EntryState;
13 use hg::PatternFileWarning;
13 use hg::PatternFileWarning;
14 use hg::StateMapIter;
14 use hg::StateMapIter;
15 use hg::StatusError;
15 use hg::StatusError;
16 use hg::StatusOptions;
16 use hg::StatusOptions;
17 use std::path::PathBuf;
17 use std::path::PathBuf;
18
18
19 impl DirstateMapMethods for OwningDirstateMap {
19 impl DirstateMapMethods for OwningDirstateMap {
20 fn clear(&mut self) {
20 fn clear(&mut self) {
21 self.get_mut().clear()
21 self.get_mut().clear()
22 }
22 }
23
23
24 fn add_file(
24 fn add_file(
25 &mut self,
25 &mut self,
26 filename: &HgPath,
26 filename: &HgPath,
27 old_state: EntryState,
27 old_state: EntryState,
28 entry: DirstateEntry,
28 entry: DirstateEntry,
29 ) -> Result<(), DirstateMapError> {
29 ) -> Result<(), DirstateMapError> {
30 self.get_mut().add_file(filename, old_state, entry)
30 self.get_mut().add_file(filename, old_state, entry)
31 }
31 }
32
32
33 fn remove_file(
33 fn remove_file(
34 &mut self,
34 &mut self,
35 filename: &HgPath,
35 filename: &HgPath,
36 old_state: EntryState,
36 old_state: EntryState,
37 size: i32,
37 size: i32,
38 ) -> Result<(), DirstateMapError> {
38 ) -> Result<(), DirstateMapError> {
39 self.get_mut().remove_file(filename, old_state, size)
39 self.get_mut().remove_file(filename, old_state, size)
40 }
40 }
41
41
42 fn drop_file(
42 fn drop_file(
43 &mut self,
43 &mut self,
44 filename: &HgPath,
44 filename: &HgPath,
45 old_state: EntryState,
45 old_state: EntryState,
46 ) -> Result<bool, DirstateMapError> {
46 ) -> Result<bool, DirstateMapError> {
47 self.get_mut().drop_file(filename, old_state)
47 self.get_mut().drop_file(filename, old_state)
48 }
48 }
49
49
50 fn clear_ambiguous_times(&mut self, filenames: Vec<HgPathBuf>, now: i32) {
50 fn clear_ambiguous_times(&mut self, filenames: Vec<HgPathBuf>, now: i32) {
51 self.get_mut().clear_ambiguous_times(filenames, now)
51 self.get_mut().clear_ambiguous_times(filenames, now)
52 }
52 }
53
53
54 fn non_normal_entries_contains(&mut self, key: &HgPath) -> bool {
54 fn non_normal_entries_contains(&mut self, key: &HgPath) -> bool {
55 self.get_mut().non_normal_entries_contains(key)
55 self.get_mut().non_normal_entries_contains(key)
56 }
56 }
57
57
58 fn non_normal_entries_remove(&mut self, key: &HgPath) {
58 fn non_normal_entries_remove(&mut self, key: &HgPath) {
59 self.get_mut().non_normal_entries_remove(key)
59 self.get_mut().non_normal_entries_remove(key)
60 }
60 }
61
61
62 fn non_normal_or_other_parent_paths(
62 fn non_normal_or_other_parent_paths(
63 &mut self,
63 &mut self,
64 ) -> Box<dyn Iterator<Item = &HgPath> + '_> {
64 ) -> Box<dyn Iterator<Item = &HgPath> + '_> {
65 self.get_mut().non_normal_or_other_parent_paths()
65 self.get_mut().non_normal_or_other_parent_paths()
66 }
66 }
67
67
68 fn set_non_normal_other_parent_entries(&mut self, force: bool) {
68 fn set_non_normal_other_parent_entries(&mut self, force: bool) {
69 self.get_mut().set_non_normal_other_parent_entries(force)
69 self.get_mut().set_non_normal_other_parent_entries(force)
70 }
70 }
71
71
72 fn iter_non_normal_paths(
72 fn iter_non_normal_paths(
73 &mut self,
73 &mut self,
74 ) -> Box<dyn Iterator<Item = &HgPath> + Send + '_> {
74 ) -> Box<dyn Iterator<Item = &HgPath> + Send + '_> {
75 self.get_mut().iter_non_normal_paths()
75 self.get_mut().iter_non_normal_paths()
76 }
76 }
77
77
78 fn iter_non_normal_paths_panic(
78 fn iter_non_normal_paths_panic(
79 &self,
79 &self,
80 ) -> Box<dyn Iterator<Item = &HgPath> + Send + '_> {
80 ) -> Box<dyn Iterator<Item = &HgPath> + Send + '_> {
81 self.get().iter_non_normal_paths_panic()
81 self.get().iter_non_normal_paths_panic()
82 }
82 }
83
83
84 fn iter_other_parent_paths(
84 fn iter_other_parent_paths(
85 &mut self,
85 &mut self,
86 ) -> Box<dyn Iterator<Item = &HgPath> + Send + '_> {
86 ) -> Box<dyn Iterator<Item = &HgPath> + Send + '_> {
87 self.get_mut().iter_other_parent_paths()
87 self.get_mut().iter_other_parent_paths()
88 }
88 }
89
89
90 fn has_tracked_dir(
90 fn has_tracked_dir(
91 &mut self,
91 &mut self,
92 directory: &HgPath,
92 directory: &HgPath,
93 ) -> Result<bool, DirstateMapError> {
93 ) -> Result<bool, DirstateMapError> {
94 self.get_mut().has_tracked_dir(directory)
94 self.get_mut().has_tracked_dir(directory)
95 }
95 }
96
96
97 fn has_dir(
97 fn has_dir(
98 &mut self,
98 &mut self,
99 directory: &HgPath,
99 directory: &HgPath,
100 ) -> Result<bool, DirstateMapError> {
100 ) -> Result<bool, DirstateMapError> {
101 self.get_mut().has_dir(directory)
101 self.get_mut().has_dir(directory)
102 }
102 }
103
103
104 fn pack_v1(
104 fn pack_v1(
105 &mut self,
105 &mut self,
106 parents: DirstateParents,
106 parents: DirstateParents,
107 now: Timestamp,
107 now: Timestamp,
108 ) -> Result<Vec<u8>, DirstateError> {
108 ) -> Result<Vec<u8>, DirstateError> {
109 self.get_mut().pack_v1(parents, now)
109 self.get_mut().pack_v1(parents, now)
110 }
110 }
111
111
112 fn pack_v2(
112 fn pack_v2(
113 &mut self,
113 &mut self,
114 parents: DirstateParents,
114 parents: DirstateParents,
115 now: Timestamp,
115 now: Timestamp,
116 ) -> Result<Vec<u8>, DirstateError> {
116 ) -> Result<Vec<u8>, DirstateError> {
117 self.get_mut().pack_v2(parents, now)
117 self.get_mut().pack_v2(parents, now)
118 }
118 }
119
119
120 fn set_all_dirs(&mut self) -> Result<(), DirstateMapError> {
120 fn set_all_dirs(&mut self) -> Result<(), DirstateMapError> {
121 self.get_mut().set_all_dirs()
121 self.get_mut().set_all_dirs()
122 }
122 }
123
123
124 fn set_dirs(&mut self) -> Result<(), DirstateMapError> {
124 fn set_dirs(&mut self) -> Result<(), DirstateMapError> {
125 self.get_mut().set_dirs()
125 self.get_mut().set_dirs()
126 }
126 }
127
127
128 fn status<'a>(
128 fn status<'a>(
129 &'a mut self,
129 &'a mut self,
130 matcher: &'a (dyn Matcher + Sync),
130 matcher: &'a (dyn Matcher + Sync),
131 root_dir: PathBuf,
131 root_dir: PathBuf,
132 ignore_files: Vec<PathBuf>,
132 ignore_files: Vec<PathBuf>,
133 options: StatusOptions,
133 options: StatusOptions,
134 ) -> Result<(DirstateStatus<'a>, Vec<PatternFileWarning>), StatusError>
134 ) -> Result<(DirstateStatus<'a>, Vec<PatternFileWarning>), StatusError>
135 {
135 {
136 self.get_mut()
136 self.get_mut()
137 .status(matcher, root_dir, ignore_files, options)
137 .status(matcher, root_dir, ignore_files, options)
138 }
138 }
139
139
140 fn copy_map_len(&self) -> usize {
140 fn copy_map_len(&self) -> usize {
141 self.get().copy_map_len()
141 self.get().copy_map_len()
142 }
142 }
143
143
144 fn copy_map_iter(&self) -> CopyMapIter<'_> {
144 fn copy_map_iter(&self) -> CopyMapIter<'_> {
145 self.get().copy_map_iter()
145 self.get().copy_map_iter()
146 }
146 }
147
147
148 fn copy_map_contains_key(&self, key: &HgPath) -> bool {
148 fn copy_map_contains_key(&self, key: &HgPath) -> bool {
149 self.get().copy_map_contains_key(key)
149 self.get().copy_map_contains_key(key)
150 }
150 }
151
151
152 fn copy_map_get(&self, key: &HgPath) -> Option<&HgPath> {
152 fn copy_map_get(&self, key: &HgPath) -> Option<&HgPath> {
153 self.get().copy_map_get(key)
153 self.get().copy_map_get(key)
154 }
154 }
155
155
156 fn copy_map_remove(&mut self, key: &HgPath) -> Option<HgPathBuf> {
156 fn copy_map_remove(&mut self, key: &HgPath) -> Option<HgPathBuf> {
157 self.get_mut().copy_map_remove(key)
157 self.get_mut().copy_map_remove(key)
158 }
158 }
159
159
160 fn copy_map_insert(
160 fn copy_map_insert(
161 &mut self,
161 &mut self,
162 key: HgPathBuf,
162 key: HgPathBuf,
163 value: HgPathBuf,
163 value: HgPathBuf,
164 ) -> Option<HgPathBuf> {
164 ) -> Option<HgPathBuf> {
165 self.get_mut().copy_map_insert(key, value)
165 self.get_mut().copy_map_insert(key, value)
166 }
166 }
167
167
168 fn len(&self) -> usize {
168 fn len(&self) -> usize {
169 self.get().len()
169 self.get().len()
170 }
170 }
171
171
172 fn contains_key(&self, key: &HgPath) -> bool {
172 fn contains_key(&self, key: &HgPath) -> bool {
173 self.get().contains_key(key)
173 self.get().contains_key(key)
174 }
174 }
175
175
176 fn get(&self, key: &HgPath) -> Option<&DirstateEntry> {
176 fn get(&self, key: &HgPath) -> Option<DirstateEntry> {
177 self.get().get(key)
177 self.get().get(key)
178 }
178 }
179
179
180 fn iter(&self) -> StateMapIter<'_> {
180 fn iter(&self) -> StateMapIter<'_> {
181 self.get().iter()
181 self.get().iter()
182 }
182 }
183 }
183 }
General Comments 0
You need to be logged in to leave comments. Login now