Advertisement
Guest User

Untitled

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