##// 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 23 config: Config,
24 24 // None means not known/initialized yet
25 25 dirstate_parents: Cell<Option<DirstateParents>>,
26 dirstate_map: RefCell<Option<OwningDirstateMap>>,
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: RefCell::new(None),
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 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 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.dirstate_map.borrow_mut() = Some(self.new_dirstate_map()?);
312 borrowed = self.dirstate_map.borrow()
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.new_dirstate_map()?);
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