use std::{ ops::Deref, sync::{atomic::AtomicUsize, Arc, Weak}, }; use parking_lot::Mutex; use crate::{ messages::{Message, MessageCopyState, MessageRingBuffer}, progress::{Id, Key, Task}, tree::{Item, Root}, }; impl Root { /// Create a new tree with default configuration. /// /// As opposed to [Item](./struct.Item.html) instances, this type can be closed and sent /// safely across threads. pub fn new() -> Arc { Options::default().into() } /// Returns the maximum amount of messages we can keep before overwriting older ones. pub fn messages_capacity(&self) -> usize { self.inner.lock().messages.lock().buf.capacity() } /// Returns the current amount of `Item`s stored in the tree. /// **Note** that this is at most a guess as tasks can be added and removed in parallel. pub fn num_tasks(&self) -> usize { #[cfg(feature = "progress-tree-hp-hashmap")] { self.inner.lock().tree.len() } #[cfg(not(feature = "progress-tree-hp-hashmap"))] { self.inner.lock().tree.len() } } /// Adds a new child `tree::Item`, whose parent is this instance, with the given `name`. /// /// This builds a hierarchy of `tree::Item`s, each having their own progress. /// Use this method to [track progress](./struct.Item.html) of your first tasks. pub fn add_child(&self, name: impl Into) -> Item { self.inner.lock().add_child(name) } /// Adds a new child `tree::Item`, whose parent is this instance, with the given `name` and `id`. /// /// This builds a hierarchy of `tree::Item`s, each having their own progress. /// Use this method to [track progress](./struct.Item.html) of your first tasks. pub fn add_child_with_id(&self, name: impl Into, id: Id) -> Item { self.inner.lock().add_child_with_id(name, id) } /// Copy the entire progress tree into the given `out` vector, so that /// it can be traversed from beginning to end in order of hierarchy. pub fn sorted_snapshot(&self, out: &mut Vec<(Key, Task)>) { out.clear(); #[cfg(feature = "progress-tree-hp-hashmap")] out.extend(self.inner.lock().tree.iter().map(|r| (*r.key(), r.value().clone()))); #[cfg(not(feature = "progress-tree-hp-hashmap"))] self.inner.lock().tree.extend_to(out); out.sort_by_key(|t| t.0); } /// Copy all messages from the internal ring buffer into the given `out` /// vector. Messages are ordered from oldest to newest. pub fn copy_messages(&self, out: &mut Vec) { self.inner.lock().messages.lock().copy_all(out); } /// Copy only new messages from the internal ring buffer into the given `out` /// vector. Messages are ordered from oldest to newest. pub fn copy_new_messages(&self, out: &mut Vec, prev: Option) -> MessageCopyState { self.inner.lock().messages.lock().copy_new(out, prev) } /// Duplicate all content and return it. /// /// This is an expensive operation, whereas `clone()` is not as it is shallow. pub fn deep_clone(&self) -> Arc { Arc::new(Root { inner: Mutex::new(self.inner.lock().deep_clone()), }) } } /// A way to configure new [`tree::Root`](./tree/struct.Root.html) instances /// ```rust /// let tree = prodash::tree::root::Options::default().create(); /// let tree2 = prodash::tree::root::Options { message_buffer_capacity: 100, ..Default::default() }.create(); /// ``` #[derive(Clone, Debug)] pub struct Options { /// The amount of [items][Item] the tree can hold without being forced to allocate. pub initial_capacity: usize, /// The amount of messages we can hold before we start overwriting old ones. pub message_buffer_capacity: usize, } impl Options { /// Create a new [`Root`](./tree/struct.Root.html) instance from the /// configuration within. pub fn create(self) -> Root { self.into() } } impl Default for Options { fn default() -> Self { Options { initial_capacity: 100, message_buffer_capacity: 20, } } } impl From for Arc { fn from(opts: Options) -> Self { Arc::new(opts.into()) } } impl From for Root { fn from( Options { initial_capacity, message_buffer_capacity, }: Options, ) -> Self { Root { inner: Mutex::new(Item { highest_child_id: 0, value: Arc::new(AtomicUsize::default()), key: Key::default(), tree: Arc::new(crate::tree::HashMap::with_capacity(initial_capacity)), messages: Arc::new(Mutex::new(MessageRingBuffer::with_capacity(message_buffer_capacity))), }), } } } impl crate::WeakRoot for Weak { type Root = Arc; fn upgrade(&self) -> Option { Weak::upgrade(self) } } impl crate::Root for Arc { type WeakRoot = Weak; fn messages_capacity(&self) -> usize { self.deref().messages_capacity() } fn num_tasks(&self) -> usize { self.deref().num_tasks() } fn sorted_snapshot(&self, out: &mut Vec<(Key, Task)>) { self.deref().sorted_snapshot(out) } fn copy_messages(&self, out: &mut Vec) { self.deref().copy_messages(out) } fn copy_new_messages(&self, out: &mut Vec, prev: Option) -> MessageCopyState { self.deref().copy_new_messages(out, prev) } fn downgrade(&self) -> Self::WeakRoot { Arc::downgrade(self) } }