root.rs 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. use std::{
  2. any::Any,
  3. cell::RefCell,
  4. collections::HashMap,
  5. rc::Rc,
  6. sync::atomic::{AtomicU32, AtomicUsize},
  7. };
  8. use crate::{Atom, AtomBuilder, AtomValue, Readable};
  9. pub type OpaqueConsumerCallback = Box<dyn Any>;
  10. struct Consumer {
  11. callback: OpaqueConsumerCallback,
  12. }
  13. static SUBSCRIBER_ID: AtomicU32 = AtomicU32::new(0);
  14. fn next_id() -> u32 {
  15. SUBSCRIBER_ID.fetch_add(1, std::sync::atomic::Ordering::Relaxed)
  16. }
  17. type AtomId = u32;
  18. type ConsumerId = u32;
  19. pub struct RecoilRoot {
  20. consumers: RefCell<HashMap<AtomId, Box<dyn RecoilSlot>>>,
  21. }
  22. impl RecoilRoot {
  23. pub(crate) fn new() -> Self {
  24. Self {
  25. consumers: Default::default(),
  26. }
  27. }
  28. // This is run by hooks when they register as a listener for a given atom
  29. // Their ID is stored in the `atom_consumers` map which lets us know which consumers to update
  30. // When the hook is dropped, they are unregistered from this map
  31. //
  32. // If the Atom they're registering as a listener for doesn't exist, then the atom
  33. // is initialized. Otherwise, the most recent value of the atom is returned
  34. // pub fn register_readable<T: AtomValue>(&self, atom: &impl Readable<T>) -> Rc<T> {
  35. // todo!()
  36. // }
  37. /// This registers the updater fn to any updates to the readable
  38. /// Whenever the readable changes, the updater Fn will be called.
  39. ///
  40. /// This also back-propogates changes, meaning components that update an atom
  41. /// will be updated from their subscription instead of directly within their own hook.
  42. pub fn subscribe_consumer<T: AtomValue>(
  43. &self,
  44. atom: &'static impl Readable<T>,
  45. updater: impl Fn(),
  46. // return the value and the consumer's ID
  47. // the consumer needs to store its ID so it can properly unsubscribe from the value
  48. ) -> (u32, Rc<T>) {
  49. let id = next_id();
  50. // Get the raw static reference of the atom
  51. let atom_ptr = get_atom_raw_ref(atom);
  52. let mut consumers = self.consumers.borrow_mut();
  53. if !consumers.contains_key(&atom_ptr) {
  54. // Run the atom's initialization
  55. // let mut b = AtomBuilder::<T>::new();
  56. // let inital_value = atom.0(&mut b);
  57. consumers.insert(atom_ptr, HashMap::new());
  58. }
  59. todo!()
  60. // Rc::new(inital_value)
  61. // todo!()
  62. // // Get the raw static reference of the atom
  63. // let atom_ptr = get_atom_raw_ref(atom);
  64. // // Subcribe this hook_id to this atom
  65. // let mut consumers = self.consumers.borrow_mut();
  66. // let hooks = consumers
  67. // .get_mut(&atom_ptr)
  68. // .expect("Atom must be initialized before being subscribed to");
  69. // // Coerce into any by wrapping the updater in a box
  70. // // (yes it's some weird indirection)
  71. // let any_updater: OpaqueConsumerCallback = Box::new(updater);
  72. // let consumer = Consumer {
  73. // callback: any_updater,
  74. // };
  75. // Insert into the map, booting out the old consumer
  76. // TODO @Jon, make the "Consumer" more efficient, patching its update mechanism in-place
  77. // hooks.insert(hook_id, consumer);
  78. }
  79. pub fn drop_consumer(&self, subscriber_id: u32) {
  80. // let mut consumers = self.consumers.borrow_mut();
  81. // let atom_ptr = get_atom_raw_ref(atom);
  82. // let atoms = consumers.get_mut(&atom_ptr);
  83. // if let Some(consumers) = atoms {
  84. // let entry = consumers.remove_entry(&hook_id);
  85. // if let Some(_) = entry {
  86. // log::debug!("successfully unsubscribed listener");
  87. // } else {
  88. // log::debug!("Failure to unsubscribe");
  89. // }
  90. // } else {
  91. // log::debug!("Strange error, atoms should be registed if the consumer is being dropped");
  92. // }
  93. }
  94. pub fn update_atom<T: AtomValue>(&self, atom: &impl Readable<T>, new_val: T) {
  95. // Get the raw static reference of the atom
  96. // let atom_ptr = get_atom_raw_ref(atom);
  97. // let mut consumers = self.consumers.borrow_mut();
  98. // let hooks = consumers
  99. // .get_mut(&atom_ptr)
  100. // .expect("Atom needs to be registered before trying to update it");
  101. // let new_val = Rc::new(new_val);
  102. // for hook in hooks.values_mut() {
  103. // let callback: &mut Rc<ConsumerCallback<T>> = hook
  104. // .callback
  105. // .downcast_mut::<_>()
  106. // .expect("Wrong type of atom stored, internal error");
  107. // callback(UpdateAction::Regenerate(new_val.clone()));
  108. // }
  109. }
  110. pub fn load_value<T: AtomValue>(&self, atom: &impl Readable<T>) -> Rc<T> {
  111. todo!()
  112. }
  113. }
  114. trait RecoilSlot {}
  115. // struct RecoilSlot {
  116. // consumers: HashMap<u32, Box<dyn Fn()>>,
  117. // }
  118. fn get_atom_raw_ref<T: AtomValue>(atom: &'static impl Readable<T>) -> u32 {
  119. let atom_ptr = atom as *const _;
  120. let atom_ptr = atom_ptr as *const u32;
  121. atom_ptr as u32
  122. }