generational_box.rs 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. //! Integration with the generational-box crate for copy state management.
  2. //!
  3. //! Each scope in dioxus has a single [Owner]
  4. use std::{
  5. any::{Any, TypeId},
  6. cell::RefCell,
  7. };
  8. use generational_box::{AnyStorage, Owner, SyncStorage, UnsyncStorage};
  9. use crate::{innerlude::current_scope_id, ScopeId};
  10. /// Run a closure with the given owner.
  11. ///
  12. /// This will override the default owner for the current component.
  13. pub fn with_owner<S: AnyStorage, F: FnOnce() -> R, R>(owner: Owner<S>, f: F) -> R {
  14. let old_owner = set_owner(Some(owner));
  15. let result = f();
  16. set_owner(old_owner);
  17. result
  18. }
  19. /// Set the owner for the current thread.
  20. fn set_owner<S: AnyStorage>(owner: Option<Owner<S>>) -> Option<Owner<S>> {
  21. let id = TypeId::of::<S>();
  22. if id == TypeId::of::<SyncStorage>() {
  23. SYNC_OWNER.with(|cell| {
  24. std::mem::replace(
  25. &mut *cell.borrow_mut(),
  26. owner.map(|owner| {
  27. *(Box::new(owner) as Box<dyn Any>)
  28. .downcast::<Owner<SyncStorage>>()
  29. .unwrap()
  30. }),
  31. )
  32. .map(|owner| *(Box::new(owner) as Box<dyn Any>).downcast().unwrap())
  33. })
  34. } else {
  35. UNSYNC_OWNER.with(|cell| {
  36. std::mem::replace(
  37. &mut *cell.borrow_mut(),
  38. owner.map(|owner| {
  39. *(Box::new(owner) as Box<dyn Any>)
  40. .downcast::<Owner<UnsyncStorage>>()
  41. .unwrap()
  42. }),
  43. )
  44. .map(|owner| *(Box::new(owner) as Box<dyn Any>).downcast().unwrap())
  45. })
  46. }
  47. }
  48. thread_local! {
  49. static SYNC_OWNER: RefCell<Option<Owner<SyncStorage>>> = const { RefCell::new(None) };
  50. static UNSYNC_OWNER: RefCell<Option<Owner<UnsyncStorage>>> = const { RefCell::new(None) };
  51. }
  52. /// Returns the current owner. This owner will be used to drop any `Copy` state that is created by the `generational-box` crate.
  53. ///
  54. /// If an owner has been set with `with_owner`, that owner will be returned. Otherwise, the owner from the current scope will be returned.
  55. pub fn current_owner<S: AnyStorage>() -> Owner<S> {
  56. let id = TypeId::of::<S>();
  57. let override_owner = if id == TypeId::of::<SyncStorage>() {
  58. SYNC_OWNER.with(|cell| {
  59. let owner = cell.borrow();
  60. owner.clone().map(|owner| {
  61. *(Box::new(owner) as Box<dyn Any>)
  62. .downcast::<Owner<S>>()
  63. .unwrap()
  64. })
  65. })
  66. } else {
  67. UNSYNC_OWNER.with(|cell| {
  68. cell.borrow().clone().map(|owner| {
  69. *(Box::new(owner) as Box<dyn Any>)
  70. .downcast::<Owner<S>>()
  71. .unwrap()
  72. })
  73. })
  74. };
  75. if let Some(owner) = override_owner {
  76. return owner;
  77. }
  78. // Otherwise get the owner from the current scope
  79. current_scope_id().expect("in a virtual dom").owner()
  80. }
  81. impl ScopeId {
  82. /// Get the owner for the current scope.
  83. pub fn owner<S: AnyStorage>(self) -> Owner<S> {
  84. match self.has_context() {
  85. Some(rt) => rt,
  86. None => {
  87. let owner = S::owner();
  88. self.provide_context(owner)
  89. }
  90. }
  91. }
  92. }