123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106 |
- //! `LazyStatic` like initialization.
- /// The initialization state
- enum State<F, T> {
- /// The data is uninitialized, initialization is pending.
- ///
- /// The inner closure contains the initialization function.
- Uninitialized(F),
- /// The data is initialized, and ready for use.
- Initialized(T),
- /// The data is unreachable, panick!
- Unreachable,
- }
- /// A lazily initialized container.
- ///
- /// This container starts out simply containing an initializer (i.e., a function to construct the
- /// value in question). When the value is requested, the initializer runs.
- pub struct LazyInit<F, T> {
- /// The internal state.
- state: State<F, T>,
- }
- impl<F: FnMut() -> T, T> LazyInit<F, T> {
- /// Create a new to-be-initialized container.
- ///
- /// The closure will be executed when initialization is required, and is guaranteed to be
- /// executed at most once.
- #[inline]
- pub const fn new(init: F) -> LazyInit<F, T> {
- LazyInit {
- state: State::Uninitialized(init),
- }
- }
- /// Create a lazy initializer with unreachable inner data.
- ///
- /// When access is tried, it will simply issue a panic. This is useful for e.g. temporarily
- /// getting ownership.
- pub const fn unreachable() -> LazyInit<F, T> {
- LazyInit {
- state: State::Unreachable,
- }
- }
- /// Get a mutable reference to the inner value.
- ///
- /// If it is uninitialize, it will be initialized and then returned.
- #[inline]
- pub fn get(&mut self) -> &mut T {
- let inner;
- match self.state {
- State::Initialized(ref mut x) => return x,
- State::Uninitialized(ref mut f) => inner = f(),
- State::Unreachable => unreachable!(),
- }
- self.state = State::Initialized(inner);
- if let State::Initialized(ref mut x) = self.state {
- x
- } else {
- // TODO find a better way.
- unreachable!();
- }
- }
- /// Get the inner of the container.
- ///
- /// This won't mutate the container itself, since it consumes it. The initializer will (if
- /// necessary) be called and the result returned. If already initialized, the inner value will
- /// be moved out and returned.
- pub fn into_inner(self) -> T {
- match self.state {
- State::Initialized(x) => x,
- State::Uninitialized(mut f) => f(),
- State::Unreachable => unreachable!(),
- }
- }
- }
- #[cfg(test)]
- mod test {
- use super::*;
- use core::cell::Cell;
- #[test]
- fn test_init() {
- let mut lazy = LazyInit::new(|| 300);
- assert_eq!(*lazy.get(), 300);
- *lazy.get() = 400;
- assert_eq!(*lazy.get(), 400);
- }
- #[test]
- fn test_laziness() {
- let is_called = Cell::new(false);
- let mut lazy = LazyInit::new(|| is_called.set(true));
- assert!(!is_called.get());
- lazy.get();
- assert!(is_called.get());
- }
- }
|