Advertisement
Guest User

Untitled

a guest
Aug 22nd, 2019
78
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.20 KB | None | 0 0
  1. #![feature(const_fn)]
  2.  
  3. macro_rules! manually_init_static {(
  4. $(
  5. static $NAME:ident: $T:ty = $expr:expr;
  6. )*
  7. ) => (
  8. $(
  9. static $NAME: $crate::manually_init_lazy::ManuallyInitLazy<$T> =
  10. <$crate::manually_init_lazy::ManuallyInitLazy<$T>>::new({
  11. fn non_const_static_init () -> $T
  12. {
  13. thread_local! {
  14. static NOT_REENTRANT: ::core::cell::Cell<bool> =
  15. ::core::cell::Cell::new(true)
  16. ;
  17. }
  18. NOT_REENTRANT.with(|not_reentrant| {
  19. assert!(not_reentrant.replace(false),
  20. "static initialization cannot be reentrant!",
  21. );
  22. let ret = $expr;
  23. not_reentrant.set(true)
  24. ret
  25. })
  26. }
  27.  
  28. non_const_static_init
  29. })
  30. ;
  31. )*
  32. )}
  33.  
  34. manually_init_static! {
  35. static FOO: i32 = {
  36. eprintln!(" FOO.init();");
  37. 42
  38. };
  39. }
  40.  
  41. fn main ()
  42. {
  43. eprintln!("fn main ()\n{{");
  44. unsafe {
  45. // # Safety
  46. //
  47. // - Not yet multithreaded, so there cannot be parallel calls to .get()
  48. FOO.init();
  49. }
  50. ::crossbeam::thread::scope(|scope| (0 .. 10).for_each(|_| {
  51. scope.spawn(|_| {
  52. eprintln!(
  53. " <{:02?}> FOO = {:?}",
  54. ::std::thread::current().id(),
  55. FOO.get(),
  56. );
  57. });
  58. })).expect("Some thread panicked");
  59. eprintln!("}}");
  60. }
  61.  
  62. mod manually_init_lazy {
  63. use ::core::cell::UnsafeCell;
  64.  
  65. enum Lazy<T>
  66. {
  67. Value(T),
  68. Factory(fn() -> T),
  69. }
  70.  
  71. pub
  72. struct ManuallyInitLazy<T> /* = */ (
  73. UnsafeCell<Lazy<T>>,
  74. );
  75.  
  76. impl<T> ManuallyInitLazy<T> {
  77. pub
  78. const
  79. fn new (factory: fn() -> T) -> Self
  80. {
  81. Self(
  82. UnsafeCell::new(Lazy::Factory(factory))
  83. )
  84. }
  85.  
  86. /// # Safety
  87. ///
  88. /// - it can only be called if there are no other parallel calls
  89. /// to `.init()` or `.get()` from other threads.
  90. pub
  91. unsafe
  92. fn init (self: &'_ Self)
  93. {
  94. if let Lazy::Factory(factory) = *self.0.get() {
  95. *self.0.get() = Lazy::Value(factory())
  96. } else {
  97. panic!("Attempted to init an already init value")
  98. }
  99. }
  100.  
  101. pub
  102. fn get (self: &'_ Self) -> &'_ T
  103. {
  104. let at_this: &Lazy<T> = unsafe {
  105. // # Safety
  106. //
  107. // - there cannot be a data race unless `.init()` contract is
  108. // violated.
  109. &*self.0.get()
  110. };
  111. match at_this {
  112. | &Lazy::Value(ref inner) => inner,
  113. | _ => panic!("Attempted to fetch an uninit value"),
  114. }
  115. }
  116.  
  117. /// Skips the init check.
  118. ///
  119. /// # Safety
  120. ///
  121. /// - `.init()` must have been already called
  122. pub
  123. unsafe
  124. fn assume_init (self: &'_ Self) -> &'_ T
  125. {
  126. let at_this: &Lazy<T> = {
  127. // # Safety
  128. //
  129. // - there cannot be a data race unless `.init()` contract is
  130. // violated.
  131. &*self.0.get()
  132. };
  133. match at_this {
  134. | &Lazy::Value(ref inner) => inner,
  135. | _ => {
  136. // # Safety
  137. //
  138. // - Callers ensure that `.init()` has already been called
  139. ::std::hint::unreachable_unchecked()
  140. },
  141. }
  142. }
  143. }
  144.  
  145. /// # Safety
  146. ///
  147. /// - Lazy<T> owns `T`, so `T` needs to be `Send`.
  148. unsafe impl<T : Send> Send for ManuallyInitLazy<T> {}
  149.  
  150. /// # Safety
  151. ///
  152. /// - the API does not offer a non-`unsafe` way to perform unsynchronised
  153. /// mutation.
  154. ///
  155. /// - non-unsafe `&ManuallyInitLazy<T> -> &T` leads to `T` needing to be Sync.
  156. unsafe impl<T : Sync> Sync for ManuallyInitLazy<T> {}
  157. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement