//! Traits, helpers, and type definitions for the collection framework.
//!
//! This module contains various tools for interacting with the collections. In summary:
//!
//! - [`Iterators`] is a trait that encapsulates all possible methods for iterating over a
//! [`Collection`].
//! - [`Collection`] is the base trait all collections must implement. Defines a series of methods
//! commonly used by almost all collections.
//! - [`FixedSizeCollection`] is a trait that extends [`Collection`] and adds the ability to define
//! collections with a fixed capacity and the possibility of expanding them. It is mainly intended
//! for collections based on arrays.
//! - [`ExpansionMode`] is a type that defines the behavior of a collection when it is full.
//! - [`check_expansion`] is a function that checks if the collection is full and if it is, expands
//! it depending on the [`ExpansionMode`]. Instead of using this function directly, the
//! [`check_expansion_add`] macro is available to wrap the behavior of a function.
//!
//! For more details, see the respective documentation of each item in the lists.
//!
//! [`check_expansion_add`]: trait_based_collection_macros::check_expansion_add
use ;
pub use check_expansion_add;
/// Trait that allows to implement all possible iterators over a [`Collection`]. All collections
/// must implement all iterators, allowing for default implementations across collections.
///
/// There are three different types of iterators:
///
/// - [`iter`] returns an immutable iterator over [`ItemRef`] in the [`Collection`] without
/// consuming them.
/// - [`iter_mut`] returns a mutable iterator over the [`ItemMut`] in the [`Collection`] without
/// consuming them.
/// - [`into_iter`] returns an iterator over the items in the [`Collection`] and consumes the
/// collection .
///
/// # Safety
///
/// All iterators must return the items in the same order as the other iterators. This is
/// required to ensure that the iterators are consistent with each other. This is not checked
/// by the compiler. If this is not upheld, the behavior of the [`Collection`] is undefined.
///
/// [`iter`]: Iterators::iter
/// [`ItemRef`]: Iterators::ItemRef
/// [`iter_mut`]: Iterators::iter_mut
/// [`ItemMut`]: Iterators::ItemMut
/// [`into_iter`]: IntoIterator::into_iter
/// This is the trait that all implementations of a collection must implement. A [`Collection`] is a
/// data structure that can be used to store a collection of items.
///
/// The [`Collection`] is generic over any type without the need of any extra traits. This allows
/// the user to create a collection of any type that they want.
///
/// The trait provides a number of methods that can be used to create, manipulate, and retrieve
/// items from the [`Collection`]. The methods are divided into three groups:
///
/// - **Creation:** These methods are used to create a new [`Collection`] and add items to it.
/// There are the following methods:
/// - [`new_default`]: Creates a new [`Collection`] with a default capacity. Normally, this
/// means that the collection will be expandable.
/// - [`with_capacity`]: Creates a new [`Collection`] with a specific capacity. This method is
/// useful if you want to avoid the expense of resizing the collection when adding items.
/// - [`with_approximate_capacity`]: Creates a new [`Collection`] with a capacity that is close
/// to the specified capacity but could be larger. This method is useful if you want to avoid
/// some of the expense of resizing the collection when adding items.
///
/// For more information about capacity, see the trait [`FixedSizeCollection`] which is used to
/// create collections with a fixed capacity (i.e. the collection will not be easily expandable).
///
/// - **Manipulation:** These methods are used to add, remove, and retrieve items from the
/// [`Collection`]. There are the following methods:
/// - [`add`]: Adds an item to the [`Collection`].
/// - [`remove`]: Removes an item from the [`Collection`] and returns the ownership of the item.
/// - [`clear`]: Removes all items from the [`Collection`].
///
/// - **Retrieval:** These methods are used to retrieve items or information from the
/// [`Collection`]. There are the following methods:
/// - [`peek`]: Returns a [`ItemRef`] to the an item in the [`Collection`]. The item should be
/// the same as the one returned by [`remove`].
/// - [`peek_mut`]: Returns a [`ItemMut`] to the an item in the [`Collection`]. The item should
/// be the same as the one returned by [`remove`].
/// - [`get`]: Returns a [`ItemRef`] to the an item at the specified index in the
/// [`Collection`].
/// - [`get_mut`]: Returns a [`ItemMut`] to the an item at the specified index in the
/// [`Collection`].
/// - [`find`]: Returns an index to the an item in the [`Collection`] that matches the
/// specified item.
/// - [`contains`]: Returns true if the [`Collection`] contains the specified item.
/// - [`len`]: Returns the number of items in the [`Collection`].
/// - [`is_empty`]: Returns `true` if the [`Collection`] is empty.
///
/// As briefly mentioned above, the [`Collection`] is intended for all types of data structures.
/// However, if the the amount of items in the collection is known, it is possible to create a
/// [`FixedSizeCollection`] which can be used to create a collection with a fixed capacity. This is
/// mainly for implementation of data structures using arrays.
///
/// # Examples
///
/// A simple example of creating a [`Collection`] by using a wrapper around the [`Vec`] data
/// structure with the minimum amount of code (by using the default implementation of the
/// different methods):
///
/// ```
/// use trait_based_collection::{prelude::*, macros::All};
///
/// #[derive(All)]
/// struct MyCollection<T> {
/// data: Vec<T>,
/// }
///
/// impl<'a, T: 'a> Iterators<'a, T> for MyCollection<T> {
/// type ItemRef = &'a T;
/// type ItemMut = &'a mut T;
///
/// type Iter = std::slice::Iter<'a, T>;
/// type IterMut = std::slice::IterMut<'a, T>;
///
/// fn iter(&'a self) -> Self::Iter {
/// self.data.iter()
/// }
///
/// fn iter_mut(&'a mut self) -> Self::IterMut {
/// self.data.iter_mut()
/// }
/// }
///
/// impl<'a, T: 'a> Collection<'a, T> for MyCollection<T> {
/// fn new_default() -> Self where Self: Sized {
/// MyCollection {
/// data: Vec::new(),
/// }
/// }
///
/// fn add(&mut self, value: T) {
/// self.data.push(value);
/// }
///
/// fn remove(&mut self) -> Option<T> {
/// self.data.pop()
/// }
///
/// fn len(&self) -> usize {
/// self.data.len()
/// }
/// }
/// ```
///
///
/// # Derivable Traits
///
/// The [`Collection`] trait allows the easy implementation of several traits that can be derived
/// through the `derive` macro. These traits can be generically implemented by using the methods
/// in the [`Collection`] trait. Currently, the following traits are derivable:
///
/// - [`FromIterator`]: Creates a new [`Collection`] from an iterator.
/// - [`IntoIterator`]: Creates an iterator from a [`Collection`].
/// - [`Default`]: Creates a new [`Collection`] with a default capacity. Uses the [`new_default`]
/// method.
/// - [`Extend`]: Extends a [`Collection`] with items from an iterator. Uses the [`add`] method.
/// - [`Display`]: Converts a [`Collection`] to a string. Uses the [`iter`] method.
/// - [`NewMacro`]: Adds a macro for easy creation of a new [`Collection`] with the same syntax as
/// the array creation syntax.
/// - [`Drop`]: Drops the [`Collection`] while avoiding memory leaks.
/// - [`Index`]: Allows indexing into a [`Collection`]. However, this this trait could be
/// incompatible with the [`get`] and [`get_mut`] methods.
///
/// Special mention to the [`All`] derive macro, which can be used to derive all traits at once.
///
/// For more information about the derivable traits, see the [`Collection Macros`] module.
///
/// # Safety
///
/// The implementation of the [`Collection`] trait could be unsafe as some of the methods in the
/// trait need the use of unsafe code. However, the different implementations of the [`Collection`]
/// should ensure that the behavior is safe.
///
/// [`new_default`]: Collection::new_default
/// [`with_capacity`]: Collection::with_capacity
/// [`with_approximate_capacity`]: Collection::with_approximate_capacity
/// [`add`]: Collection::add
/// [`remove`]: Collection::remove
/// [`clear`]: Collection::clear
/// [`peek`]: Collection::peek
/// [`peek_mut`]: Collection::peek_mut
/// [`get`]: Collection::get
/// [`get_mut`]: Collection::get_mut
/// [`find`]: Collection::find
/// [`contains`]: Collection::contains
/// [`len`]: Collection::len
/// [`is_empty`]: Collection::is_empty
/// [`ItemRef`]: Iterators::ItemRef
/// [`ItemMut`]: Iterators::ItemMut
/// [`iter`]: Iterators::iter
///
/// [`Collection Macros`]: crate::macros
/// [`FromIterator`]: trait_based_collection_macros::FromIterator
/// [`IntoIterator`]: trait_based_collection_macros::IntoIterator
/// [`Default`]: trait_based_collection_macros::Default
/// [`Extend`]: trait_based_collection_macros::Extend
/// [`Display`]: trait_based_collection_macros::Display
/// [`NewMacro`]: trait_based_collection_macros::NewMacro
/// [`Drop`]: trait_based_collection_macros::Drop
/// [`Index`]: trait_based_collection_macros::Index
/// [`All`]: trait_based_collection_macros::All
/// Different modes of action when the [`FixedSizeCollection`] is full. Depending on the mode, the
/// collection will behave differently through the [`check_expansion`] method.
///
/// There are four modes of expansion:
/// 1. [`Panic`] - The collection will panic when the capacity is reached.
/// 2. [`Ignore`] - The collection will ignore the addition of the new item.
/// 3. [`Overwrite`] - The collection will overwrite the an item when the capacity is reached.
/// 4. [`Expand`] - The collection will expand the capacity by a specific factor. The factor must
/// be greater than `1.0`. If the factor is `1.0`, the function will `panic!`. This is the
/// default mode with a factor of `2.0`.
///
/// # Examples
///
/// Example on how the expansion is checked in [`FixedSizeCollection`] through the
/// [`check_expansion`] method:
///
/// ```
/// use trait_based_collection::prelude::*;
///
/// fn check_expansion<'a, T, C: FixedSizeCollection<'a, T>>(mut collection: C) -> bool {
/// if collection.is_full() {
/// match collection.mode() {
/// ExpansionMode::Panic => {
/// panic!("The collection is full");
/// }
/// ExpansionMode::Ignore => {
/// return true;
/// }
/// ExpansionMode::Overwrite => {
/// collection.remove();
/// }
/// ExpansionMode::Expand(factor) => {
/// if *factor < 1.0 {
/// panic!("Expand factor must be greater than 1");
/// }
/// let size = ((*factor - 1.0) * collection.capacity() as f64).floor() as usize;
/// collection.expand(size);
/// }
/// }
/// }
/// false
/// }
/// ```
///
/// [`Panic`]: ExpansionMode::Panic
/// [`Ignore`]: ExpansionMode::Ignore
/// [`Overwrite`]: ExpansionMode::Overwrite
/// [`Expand`]: ExpansionMode::Expand
/// A [`Collection`] that can easily be expanded, as the capacity is fixed. Normally, this are data
/// structures that use a fixed size buffer in memory ([`Array`]-like).
///
/// Similar to [`Collection`], the [`FixedSizeCollection`] is a trait that is generic over any type
/// without the need of any extra traits. This allows the user to create a collection of any type
/// that they want.
///
/// To create a new [`FixedSizeCollection`], the user must add the following extra code into the
/// [`add`] method at the beginning of the method. This code will manage the expansion of the
/// collection depending on the [`ExpansionMode`] of the collection :
///
/// ```text
/// if check_expansion(self) {
/// return;
/// }
/// ```
///
/// An alternative way is to call the [`check_expansion_add`] macro. This macro will add the
/// the previous code into the [`add`] method.
///
/// For a full example, see the Examples section.
///
/// The trait provide extra methods related with the capacity of the collection . The capacity is
/// the amount of items that the collection can hold. The [`FixedSizeCollection`] provides the
/// following methods:
///
/// - [`with_mode`] - Creates a new [`FixedSizeCollection`] with the specified capacity and
/// [`ExpansionMode`].
/// - [`capacity`] - Returns the maximum amount of items that the collection can hold.
/// - [`expand`] - Expands the capacity of the collection by a specific amount. This amount or more
/// will be added to the capacity.
/// - [`is_full`] - Returns `true` if the collection is full. Checks if the length of the collection
/// is equal to the capacity.
/// - [`mode`] - Returns the [`ExpansionMode`] of expansion of the collection .
///
/// For implementation of the [`FixedSizeCollection`] data structure, there also exists the
/// following method:
///
/// - [`check_expansion`] - Checks if the collection is full and if it is, it will behave depending
/// on the [`mode`] of the collection .
///
/// # Examples
///
/// Expands the example shown in [`Collection`] by modifying a bit the struct with a mode and
/// implementing the [`FixedSizeCollection`] trait. The example contains only the modified code.
///
/// ```
/// use trait_based_collection::{prelude::*, macros::{check_expansion_add, All}};
///
/// #[derive(All)]
/// struct MyCollection<T> {
/// data: Vec<T>,
/// mode: ExpansionMode,
/// }
/// #
/// # impl<'a, T: 'a> Iterators<'a, T> for MyCollection<T> {
/// # type ItemRef = &'a T;
/// # type ItemMut = &'a mut T;
/// #
/// # type Iter = std::slice::Iter<'a, T>;
/// # type IterMut = std::slice::IterMut<'a, T>;
/// #
/// # fn iter(&'a self) -> Self::Iter {
/// # self.data.iter()
/// # }
/// #
/// # fn iter_mut(&'a mut self) -> Self::IterMut {
/// # self.data.iter_mut()
/// # }
/// # }
///
/// impl<'a, T: 'a> Collection<'a, T> for MyCollection<T> {
/// fn new_default() -> Self where Self: Sized {
/// MyCollection::with_mode(16, ExpansionMode::default())
/// }
///
/// fn with_capacity(capacity: usize) -> Self {
/// MyCollection::with_mode(capacity, ExpansionMode::Panic)
/// }
///
/// fn with_approximate_capacity(approx_capacity: usize) -> Self{
/// MyCollection::with_mode(approx_capacity, ExpansionMode::default())
/// }
///
/// #[check_expansion_add]
/// fn add(&mut self, value: T) {
/// self.data.push(value);
/// }
/// #
/// # fn remove(&mut self) -> Option<T> {
/// # self.data.pop()
/// # }
/// #
/// # fn len(&self) -> usize {
/// # self.data.len()
/// # }
/// }
///
/// impl<'a, T: 'a> FixedSizeCollection<'a, T> for MyCollection<T> {
/// fn with_mode(capacity: usize, mode: ExpansionMode) -> Self {
/// assert_ne!(capacity, 0, "Capacity must be greater than 0");
/// MyCollection {
/// data: Vec::with_capacity(capacity),
/// mode,
/// }
/// }
///
/// fn capacity(&self) -> usize {
/// self.data.capacity()
/// }
///
/// fn expand(&mut self, extra_size: usize) {
/// self.data.reserve(extra_size);
/// }
///
/// fn mode(&self) -> &ExpansionMode {
/// &self.mode
/// }
/// }
/// ```
///
/// # Safety
///
/// The [`FixedSizeCollection`] trait is currently safe as it is based on the [`Vec`]
/// implementation. However, in the future, [`Vec`] could also be implemented in the project and
/// the [`FixedSizeCollection`] trait would be unsafe. Similarly to [`Collection`], the trait
/// is implemented in unsafe code but the usage of the trait should be safe.
///
/// [`Array`]: https://doc.rust-lang.org/std/primitive.array.html
/// [`add`]: Collection::add
/// [`check_expansion_add`]: macro@trait_based_collection_macros::check_expansion_add
/// [`capacity`]: FixedSizeCollection::capacity
/// [`expand`]: FixedSizeCollection::expand
/// [`is_full`]: FixedSizeCollection::is_full
/// [`mode`]: FixedSizeCollection::mode
/// [`with_mode`]: FixedSizeCollection::with_mode
/// Checks if the collection is full and if it is, expands the collection depending on the
/// [`ExpansionMode`]. Also, returns `true` if the [`add`] method should finish execution.
///
/// This method should be called before adding an item to the collection . If the collection is
/// full, the method will do:
/// - [`Panic`]: The method will panic.
/// - [`Ignore`]: The item will not be added to the collection and will npt
/// - [`Overwrite`]: An item will be removed from the collection and the new item will be added.
/// In this case, the [`remove`] method will be called.
/// - [`Expand`]: The collection will be expanded and the item will be added. In this case, the
/// [`expand`] method will be called.
///
/// Instead of using this method inside the [`add`] method, it is recommended to use the
/// [`check_expansion_add`] macro.
///
/// # Panics
///
/// This method will panic if [`mode`] is [`Panic`] and the collection is full.
///
/// # Examples
///
/// Example without using [`check_expansion_add`] macro on an [`add`] method:
///
/// ```
/// # use trait_based_collection::{prelude::*, macros::All};
/// use trait_based_collection::macros::check_expansion_add;
/// #
/// # #[derive(All)]
/// # struct MyCollection<T> {
/// # data: Vec<T>,
/// # mode: ExpansionMode,
/// # }
/// #
/// # impl<'a, T: 'a> Iterators<'a, T> for MyCollection<T> {
/// # type ItemRef = &'a T;
/// # type ItemMut = &'a mut T;
/// #
/// # type Iter = std::slice::Iter<'a, T>;
/// # type IterMut = std::slice::IterMut<'a, T>;
/// #
/// # fn iter(&'a self) -> Self::Iter {
/// # self.data.iter()
/// # }
/// #
/// # fn iter_mut(&'a mut self) -> Self::IterMut {
/// # self.data.iter_mut()
/// # }
/// # }
/// #
/// # impl<'a, T: 'a> Collection<'a, T> for MyCollection<T> {
/// # fn new_default() -> Self where Self: Sized {
/// # MyCollection::with_mode(16, ExpansionMode::default())
/// # }
/// #
/// # fn with_capacity(capacity: usize) -> Self {
/// # MyCollection::with_mode(capacity, ExpansionMode::Panic)
/// # }
/// #
/// # fn with_approximate_capacity(approx_capacity: usize) -> Self{
/// # MyCollection::with_mode(approx_capacity, ExpansionMode::default())
/// # }
/// #
/// #[check_expansion_add]
/// fn add(&mut self, value: T) {
/// self.data.push(value);
/// }
/// #
/// # fn remove(&mut self) -> Option<T> {
/// # self.data.pop()
/// # }
/// #
/// # fn len(&self) -> usize {
/// # self.data.len()
/// # }
/// # }
/// #
/// # impl<'a, T: 'a> FixedSizeCollection<'a, T> for MyCollection<T> {
/// # fn with_mode(capacity: usize, mode: ExpansionMode) -> Self {
/// # assert_ne!(capacity, 0, "Capacity must be greater than 0");
/// # MyCollection {
/// # data: Vec::with_capacity(capacity),
/// # mode,
/// # }
/// # }
/// #
/// # fn capacity(&self) -> usize {
/// # self.data.capacity()
/// # }
/// #
/// # fn expand(&mut self, extra_size: usize) {
/// # self.data.reserve(extra_size);
/// # }
/// #
/// # fn mode(&self) -> &ExpansionMode {
/// # &self.mode
/// # }
/// # }
/// ```
///
/// Alternative example without using [`check_expansion_add`] macro on an [`add`] method:
///
/// ```
/// # use trait_based_collection::{prelude::*, macros::All};
/// use trait_based_collection::collection::check_expansion;
/// #
/// # #[derive(All)]
/// # struct MyCollection<T> {
/// # data: Vec<T>,
/// # mode: ExpansionMode,
/// # }
/// #
/// # impl<'a, T: 'a> Iterators<'a, T> for MyCollection<T> {
/// # type ItemRef = &'a T;
/// # type ItemMut = &'a mut T;
/// #
/// # type Iter = std::slice::Iter<'a, T>;
/// # type IterMut = std::slice::IterMut<'a, T>;
/// #
/// # fn iter(&'a self) -> Self::Iter {
/// # self.data.iter()
/// # }
/// #
/// # fn iter_mut(&'a mut self) -> Self::IterMut {
/// # self.data.iter_mut()
/// # }
/// # }
/// #
/// # impl<'a, T: 'a> Collection<'a, T> for MyCollection<T> {
/// # fn new_default() -> Self where Self: Sized {
/// # MyCollection::with_mode(16, ExpansionMode::default())
/// # }
/// #
/// # fn with_capacity(capacity: usize) -> Self {
/// # MyCollection::with_mode(capacity, ExpansionMode::Panic)
/// # }
/// #
/// # fn with_approximate_capacity(approx_capacity: usize) -> Self{
/// # MyCollection::with_mode(approx_capacity, ExpansionMode::default())
/// # }
/// #
/// fn add(&mut self, value: T) {
/// if check_expansion(self) {
/// return;
/// }
/// self.data.push(value);
/// }
/// #
/// # fn remove(&mut self) -> Option<T> {
/// # self.data.pop()
/// # }
/// #
/// # fn len(&self) -> usize {
/// # self.data.len()
/// # }
/// # }
/// #
/// # impl<'a, T: 'a> FixedSizeCollection<'a, T> for MyCollection<T> {
/// # fn with_mode(capacity: usize, mode: ExpansionMode) -> Self {
/// # assert_ne!(capacity, 0, "Capacity must be greater than 0");
/// # MyCollection {
/// # data: Vec::with_capacity(capacity),
/// # mode,
/// # }
/// # }
/// #
/// # fn capacity(&self) -> usize {
/// # self.data.capacity()
/// # }
/// #
/// # fn expand(&mut self, extra_size: usize) {
/// # self.data.reserve(extra_size);
/// # }
/// #
/// # fn mode(&self) -> &ExpansionMode {
/// # &self.mode
/// # }
/// # }
/// ```
///
/// [`add`]: Collection::add
/// [`Panic`]: ExpansionMode::Panic
/// [`Ignore`]: ExpansionMode::Ignore
/// [`Overwrite`]: ExpansionMode::Overwrite
/// [`remove`]: Collection::remove
/// [`Expand`]: ExpansionMode::Expand
/// [`expand`]: FixedSizeCollection::expand
/// [`mode`]: FixedSizeCollection::mode