Advertisement
Guest User

Untitled

a guest
Jul 23rd, 2019
106
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.16 KB | None | 0 0
  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. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement