##// END OF EJS Templates
rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct...
Simon Sapin -
r48772:fc208d6f default
parent child Browse files
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: RefCell<Option<OwningDirstateMap>>,
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: RefCell::new(None),
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 let mut borrowed = self.dirstate_map.borrow();
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.dirstate_map.borrow_mut() = Some(self.new_dirstate_map()?);
341 *self.value.borrow_mut() = Some((self.init)(repo)?);
312 borrowed = self.dirstate_map.borrow()
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.new_dirstate_map()?);
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