blob: 4ff2a997887b4120974e54618095f9c781f87531 [file] [log] [blame]
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<Root> {
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<String>) -> 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<String>, 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<Message>) {
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<Message>, prev: Option<MessageCopyState>) -> 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<Root> {
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<Options> for Arc<Root> {
fn from(opts: Options) -> Self {
Arc::new(opts.into())
}
}
impl From<Options> 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<Root> {
type Root = Arc<Root>;
fn upgrade(&self) -> Option<Self::Root> {
Weak::upgrade(self)
}
}
impl crate::Root for Arc<Root> {
type WeakRoot = Weak<Root>;
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<Message>) {
self.deref().copy_messages(out)
}
fn copy_new_messages(&self, out: &mut Vec<Message>, prev: Option<MessageCopyState>) -> MessageCopyState {
self.deref().copy_new_messages(out, prev)
}
fn downgrade(&self) -> Self::WeakRoot {
Arc::downgrade(self)
}
}