Show More
@@ -23,7 +23,7 b' pub struct Repo {' | |||||
23 | config: Config, |
|
23 | config: Config, | |
24 | // None means not known/initialized yet |
|
24 | // None means not known/initialized yet | |
25 | dirstate_parents: Cell<Option<DirstateParents>>, |
|
25 | dirstate_parents: Cell<Option<DirstateParents>>, | |
26 |
dirstate_map: |
|
26 | dirstate_map: LazyCell<OwningDirstateMap, DirstateError>, | |
27 | } |
|
27 | } | |
28 |
|
28 | |||
29 | #[derive(Debug, derive_more::From)] |
|
29 | #[derive(Debug, derive_more::From)] | |
@@ -196,7 +196,7 b' impl Repo {' | |||||
196 | dot_hg, |
|
196 | dot_hg, | |
197 | config: repo_config, |
|
197 | config: repo_config, | |
198 | dirstate_parents: Cell::new(None), |
|
198 | dirstate_parents: Cell::new(None), | |
199 |
dirstate_map: |
|
199 | dirstate_map: LazyCell::new(Self::new_dirstate_map), | |
200 | }; |
|
200 | }; | |
201 |
|
201 | |||
202 | requirements::check(&repo)?; |
|
202 | requirements::check(&repo)?; | |
@@ -302,24 +302,52 b' impl Repo {' | |||||
302 | pub fn dirstate_map( |
|
302 | pub fn dirstate_map( | |
303 | &self, |
|
303 | &self, | |
304 | ) -> Result<Ref<OwningDirstateMap>, DirstateError> { |
|
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 | if borrowed.is_none() { |
|
336 | if borrowed.is_none() { | |
307 | drop(borrowed); |
|
337 | drop(borrowed); | |
308 | // Only use `borrow_mut` if it is really needed to avoid panic in |
|
338 | // Only use `borrow_mut` if it is really needed to avoid panic in | |
309 | // case there is another outstanding borrow but mutation is not |
|
339 | // case there is another outstanding borrow but mutation is not | |
310 | // needed. |
|
340 | // needed. | |
311 |
*self. |
|
341 | *self.value.borrow_mut() = Some((self.init)(repo)?); | |
312 |
borrowed = self. |
|
342 | borrowed = self.value.borrow() | |
313 | } |
|
343 | } | |
314 | Ok(Ref::map(borrowed, |option| option.as_ref().unwrap())) |
|
344 | Ok(Ref::map(borrowed, |option| option.as_ref().unwrap())) | |
315 | } |
|
345 | } | |
316 |
|
346 | |||
317 | pub fn dirstate_map_mut( |
|
347 | pub fn get_mut_or_init(&self, repo: &Repo) -> Result<RefMut<T>, E> { | |
318 | &self, |
|
348 | let mut borrowed = self.value.borrow_mut(); | |
319 | ) -> Result<RefMut<OwningDirstateMap>, DirstateError> { |
|
|||
320 | let mut borrowed = self.dirstate_map.borrow_mut(); |
|
|||
321 | if borrowed.is_none() { |
|
349 | if borrowed.is_none() { | |
322 |
*borrowed = Some(self. |
|
350 | *borrowed = Some((self.init)(repo)?); | |
323 | } |
|
351 | } | |
324 | Ok(RefMut::map(borrowed, |option| option.as_mut().unwrap())) |
|
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