SHARE
TWEET

Untitled

a guest Jul 23rd, 2019 70 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. mod cache {
  2.     use std::{cell::UnsafeCell, mem, sync::Mutex};
  3.  
  4.     /// A thread safe single-value cache.
  5.     pub struct ThreadSafeCache<T> {
  6.         data: Mutex<UnsafeCell<Option<T>>>,
  7.     }
  8.  
  9.     impl<T> ThreadSafeCache<T> {
  10.         /// Create a new instance of the cache with uninitialized data.
  11.         pub fn new() -> Self {
  12.             Self {
  13.                 data: Mutex::new(UnsafeCell::new(None)),
  14.             }
  15.         }
  16.  
  17.         /// Get the cached data, or calculate it using the given closure if it
  18.         /// hasn't been initialized.
  19.         ///
  20.         /// # Panics
  21.         ///
  22.         /// Panics if the cache's mutex has been poisoned.
  23.         pub fn get<F>(&self, f: F) -> &T
  24.         where
  25.             F: FnOnce() -> T,
  26.         {
  27.             // Get a lock on data. We get this to prevent double-initialization
  28.             // of the cached data, as well as other issues with potentially
  29.             // having multiple mutable references. While we have the lock, we
  30.             // can create shared references with impunity, since the only block
  31.             // of code that should be allowed to get one is this method.
  32.             let cell = self.data.lock().unwrap();
  33.             let ptr = cell.get();
  34.             unsafe {
  35.                 // This can't be a mutable reference - we don't know if the data
  36.                 // has been initialized yet, and if it has, there are
  37.                 // potentially shared references to its contents. We have to
  38.                 // limit its lifetime to this expression, as well, since we will
  39.                 // need to get a shared reference if we need to initialize.
  40.                 if (&*ptr).is_none() {
  41.                     // We can get a mutable reference here since we know that
  42.                     // there aren't any other mutable references (due to the
  43.                     // mutex), there aren't any external shared references
  44.                     // (since we can only get a reference to the data after it's
  45.                     // been initialized,) and we've prevented any local shared
  46.                     // references by limiting the scope of the `is_none` check.
  47.                     let data = &mut *ptr;
  48.                     mem::replace(data, Some(f()));
  49.                 }
  50.                 // Safe to get a reference because the mutable reference's
  51.                 // lifetime extends only to the end of the `if` block.
  52.                 (&*ptr).as_ref().unwrap()
  53.             }
  54.         }
  55.     }
  56.  
  57.     #[cfg(test)]
  58.     mod tests {
  59.         use super::*;
  60.  
  61.         #[test]
  62.         fn cache_is_send_and_sync() {
  63.             fn is_send_and_sync<T: Send + Sync>() {}
  64.             is_send_and_sync::<ThreadSafeCache<u32>>()
  65.         }
  66.     }
  67. }
  68.  
  69. use self::cache::ThreadSafeCache;
  70.  
  71. struct Foo {
  72.     name: String,
  73.     msg: ThreadSafeCache<String>,
  74. }
  75.  
  76. impl Foo {
  77.     fn new<T: Into<String>>(name: T) -> Self {
  78.         Self {
  79.             name: name.into(),
  80.             msg: ThreadSafeCache::new(),
  81.         }
  82.     }
  83.  
  84.     fn msg(&self) -> &str {
  85.         self.msg.get(|| {
  86.             println!("Long computation here...");
  87.             format!("Hello, {}!", self.name)
  88.         })
  89.     }
  90. }
  91.  
  92. fn main() {
  93.     let x = Foo::new("world");
  94.     println!("{}", x.msg());
  95.     println!("{}", x.msg());
  96. }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top