Show More
@@ -23,7 +23,7 b' pub struct Repo {' | |||
|
23 | 23 | config: Config, |
|
24 | 24 | // None means not known/initialized yet |
|
25 | 25 | dirstate_parents: Cell<Option<DirstateParents>>, |
|
26 |
dirstate_map: |
|
|
26 | dirstate_map: LazyCell<OwningDirstateMap, DirstateError>, | |
|
27 | 27 | } |
|
28 | 28 | |
|
29 | 29 | #[derive(Debug, derive_more::From)] |
@@ -196,7 +196,7 b' impl Repo {' | |||
|
196 | 196 | dot_hg, |
|
197 | 197 | config: repo_config, |
|
198 | 198 | dirstate_parents: Cell::new(None), |
|
199 |
dirstate_map: |
|
|
199 | dirstate_map: LazyCell::new(Self::new_dirstate_map), | |
|
200 | 200 | }; |
|
201 | 201 | |
|
202 | 202 | requirements::check(&repo)?; |
@@ -302,24 +302,52 b' impl Repo {' | |||
|
302 | 302 | pub fn dirstate_map( |
|
303 | 303 | &self, |
|
304 | 304 | ) -> Result<Ref<OwningDirstateMap>, DirstateError> { |
|
305 |
|
|
|
305 | self.dirstate_map.get_or_init(self) | |
|
306 | } | |
|
307 | ||
|
308 | pub fn dirstate_map_mut( | |
|
309 | &self, | |
|
310 | ) -> Result<RefMut<OwningDirstateMap>, DirstateError> { | |
|
311 | self.dirstate_map.get_mut_or_init(self) | |
|
312 | } | |
|
313 | } | |
|
314 | ||
|
315 | /// Lazily-initialized component of `Repo` with interior mutability | |
|
316 | /// | |
|
317 | /// This differs from `OnceCell` in that the value can still be "deinitialized" | |
|
318 | /// later by setting its inner `Option` to `None`. | |
|
319 | struct LazyCell<T, E> { | |
|
320 | value: RefCell<Option<T>>, | |
|
321 | // `Fn`s that don’t capture environment are zero-size, so this box does | |
|
322 | // not allocate: | |
|
323 | init: Box<dyn Fn(&Repo) -> Result<T, E>>, | |
|
324 | } | |
|
325 | ||
|
326 | impl<T, E> LazyCell<T, E> { | |
|
327 | fn new(init: impl Fn(&Repo) -> Result<T, E> + 'static) -> Self { | |
|
328 | Self { | |
|
329 | value: RefCell::new(None), | |
|
330 | init: Box::new(init), | |
|
331 | } | |
|
332 | } | |
|
333 | ||
|
334 | fn get_or_init(&self, repo: &Repo) -> Result<Ref<T>, E> { | |
|
335 | let mut borrowed = self.value.borrow(); | |
|
306 | 336 | if borrowed.is_none() { |
|
307 | 337 | drop(borrowed); |
|
308 | 338 | // Only use `borrow_mut` if it is really needed to avoid panic in |
|
309 | 339 | // case there is another outstanding borrow but mutation is not |
|
310 | 340 | // needed. |
|
311 |
*self. |
|
|
312 |
borrowed = self. |
|
|
341 | *self.value.borrow_mut() = Some((self.init)(repo)?); | |
|
342 | borrowed = self.value.borrow() | |
|
313 | 343 | } |
|
314 | 344 | Ok(Ref::map(borrowed, |option| option.as_ref().unwrap())) |
|
315 | 345 | } |
|
316 | 346 | |
|
317 | pub fn dirstate_map_mut( | |
|
318 | &self, | |
|
319 | ) -> Result<RefMut<OwningDirstateMap>, DirstateError> { | |
|
320 | let mut borrowed = self.dirstate_map.borrow_mut(); | |
|
347 | pub fn get_mut_or_init(&self, repo: &Repo) -> Result<RefMut<T>, E> { | |
|
348 | let mut borrowed = self.value.borrow_mut(); | |
|
321 | 349 | if borrowed.is_none() { |
|
322 |
*borrowed = Some(self. |
|
|
350 | *borrowed = Some((self.init)(repo)?); | |
|
323 | 351 | } |
|
324 | 352 | Ok(RefMut::map(borrowed, |option| option.as_mut().unwrap())) |
|
325 | 353 | } |
General Comments 0
You need to be logged in to leave comments.
Login now