utls 0.10.8

A simple utilities library for stuff I actually use sometimes, with a large focus on convenience and lack of dependencies.
Documentation
/// Module providing buffer types
pub mod buf {
    use std::{
        error::Error,
        fmt::Display,
        ops::{Index, IndexMut},
    };

    /// A fixed-size circular buffer implementation.
    ///
    /// This buffer can store a fixed number of elements in a circular fashion,
    /// where new elements overwrite old ones when the buffer is full.
    #[derive(Clone, Debug)]
    pub struct CircularBuffer<T> {
        buffer: Vec<Option<T>>,
        read_pos: usize,
        write_pos: usize,
        size: usize,
    }
    impl<T> CircularBuffer<T> {
        /// Creates a new `CircularBuffer` with the specified capacity.
        ///
        /// # Arguments
        ///
        /// * `capacity` - The fixed size of the buffer
        ///
        /// # Errors
        ///
        /// Returns `BufError::InvalidCapacity` if capacity is 0
        pub fn new(capacity: usize) -> Result<Self, BufError> {
            if capacity == 0 {
                return Err(BufError::InvalidCapacity);
            }

            let mut buffer = Vec::with_capacity(capacity);
            buffer.resize_with(capacity, || None);
            Ok(Self {
                buffer,
                read_pos: 0,
                write_pos: 0,
                size: capacity,
            })
        }

        /// Pushes an item to the back of the buffer.
        ///
        /// # Arguments
        ///
        /// * `item` - The item to push
        ///
        /// # Errors
        ///
        /// Returns `BufError::BufFull` if the buffer is full
        pub fn push(&mut self, item: T) -> Result<(), BufError> {
            if self.is_full() {
                return Err(BufError::BufFull(self.size));
            }

            self.buffer[self.write_pos] = Some(item);
            self.write_pos = (self.write_pos + 1) % self.size;
            Ok(())
        }
        /// Removes and returns the first item in the buffer.
        ///
        /// # Returns
        ///
        /// * `Some(T)` - The first item if the buffer is not empty
        /// * `None` - If the buffer is empty
        pub fn pop(&mut self) -> Option<T> {
            if self.is_empty() {
                return None;
            }

            let item = self.buffer[self.read_pos].take();
            self.read_pos = (self.read_pos + 1) % self.size;
            item
        }
        /// Returns a reference to the first item without removing it.
        ///
        /// # Returns
        ///
        /// * `Some(&T)` - Reference to the first item if buffer is not empty
        /// * `None` - If the buffer is empty
        pub fn peek(&self) -> Option<&T> {
            self.buffer.get(self.read_pos).unwrap_or(&None).as_ref()
        }

        /// Checks if the buffer is at full capacity.
        pub fn is_full(&self) -> bool {
            self.available() == self.size
        }

        /// Checks if the buffer is empty.
        pub fn is_empty(&self) -> bool {
            self.available() == 0
        }
        /// Returns the total capacity of the buffer.
        pub fn capacity(&self) -> usize {
            self.size
        }
        pub fn len(&self) -> usize {
            self.available()
        }
        pub fn clear(&mut self) {
            self.buffer.clear();
            self.read_pos = 0;
            self.write_pos = 0;
        }
        /// Returns the number of elements currently in the buffer
        pub fn available(&self) -> usize {
            if self.write_pos >= self.read_pos {
                self.write_pos - self.read_pos
            } else {
                self.size - (self.read_pos - self.write_pos)
            }
        }
        /// Returns the amount of free space in the buffer
        pub fn free_space(&self) -> usize {
            self.size - self.available()
        }
        /// Returns an iterator over references to the elements in the buffer.
        pub fn iter(&self) -> impl Iterator<Item = &T> {
            self.buffer.iter().filter_map(|x| x.as_ref())
        }

        /// Attempts to extend the buffer with elements from an iterator
        pub fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) -> Result<(), BufError> {
            for item in iter {
                self.push(item)?;
            }
            Ok(())
        }
        /// Gets a reference to the element at the specified index.
        ///
        /// # Arguments
        ///
        /// * `index` - The index of the element to retrieve
        ///
        /// # Returns
        ///
        /// * `Some(&T)` - Reference to the element if index is valid
        /// * `None` - If index is out of bounds
        pub fn get(&self, index: usize) -> Option<&T> {
            if index >= self.len() {
                return None;
            }
            let actual_index = (self.read_pos + index) % self.size;
            self.buffer[actual_index].as_ref()
        }
        /// Overwrites the oldest element in the buffer with a new item.
        ///
        /// If the buffer is full, the read position is adjusted to maintain
        /// the circular nature of the buffer.
        ///
        /// # Arguments
        ///
        /// * `item` - The item to write
        pub fn overwrite(&mut self, item: T) {
            self.buffer[self.write_pos] = Some(item);
            self.write_pos = (self.write_pos + 1) % self.size;
            if self.is_full() {
                self.read_pos = self.write_pos;
            }
        }
        /// Rotates the buffer left by n positions
        pub fn rotate_left(&mut self, n: usize) {
            if self.is_empty() || n == 0 {
                return;
            }
            self.read_pos = (self.read_pos + n) % self.size;
            self.write_pos = (self.write_pos + n) % self.size;
        }

        /// Rotates the buffer right by n positions
        pub fn rotate_right(&mut self, n: usize) {
            if self.is_empty() || n == 0 {
                return;
            }
            self.read_pos = (self.size + self.read_pos - n) % self.size;
            self.write_pos = (self.size + self.write_pos - n) % self.size;
        }

        /// Removes and returns the element at index while preserving order
        pub fn remove(&mut self, index: usize) -> Option<T> {
            if index >= self.available() {
                return None;
            }

            let actual_index = (self.read_pos + index) % self.size;
            let item = self.buffer[actual_index].take();

            // Shift elements
            for i in actual_index..self.write_pos {
                self.buffer[i] = self.buffer[(i + 1) % self.size].take();
            }

            self.write_pos = (self.size + self.write_pos - 1) % self.size;
            item
        }
    }

    impl<T: Clone> CircularBuffer<T> {
        pub fn as_slices(&self) -> (Vec<T>, Vec<T>) {
            if self.is_empty() {
                return (Vec::new(), Vec::new());
            }

            let buf: Vec<T> = self.iter().cloned().collect();

            if self.write_pos <= self.read_pos {
                // Data wraps around
                // First slice: from read_pos to end
                // Second slice: from start to write_pos
                (
                    buf[self.read_pos..].to_vec(),
                    buf[..self.write_pos].to_vec(),
                )
            } else {
                // Data is contiguous
                // First slice: from read_pos to write_pos
                // Second slice: empty
                (buf[self.read_pos..self.write_pos].to_vec(), Vec::new())
            }
        }
    }

    impl<T> Default for CircularBuffer<T> {
        fn default() -> Self {
            Self::new(16).expect("This message physically cannot be shown")
        }
    }

    impl<T> IntoIterator for CircularBuffer<T> {
        type Item = T;
        type IntoIter = std::vec::IntoIter<T>;

        fn into_iter(self) -> Self::IntoIter {
            self.buffer
                .into_iter()
                .filter_map(|x| x)
                .collect::<Vec<_>>()
                .into_iter()
        }
    }

    impl<T> FromIterator<T> for CircularBuffer<T> {
        fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
            let iter = iter.into_iter();
            let (lower, _) = iter.size_hint();
            let mut buffer =
                CircularBuffer::new(lower.max(16)).expect("Failed to create buffer from iterator");

            for item in iter {
                buffer.push(item).ok();
            }
            buffer
        }
    }

    impl<T> Index<usize> for CircularBuffer<T> {
        type Output = Option<T>;
        fn index(&self, index: usize) -> &Self::Output {
            &self.buffer[index]
        }
    }

    impl<T> IndexMut<usize> for CircularBuffer<T> {
        fn index_mut(&mut self, index: usize) -> &mut Self::Output {
            &mut self.buffer[index]
        }
    }

    /// Error types for buffer operations
    #[derive(Debug)]
    pub enum BufError {
        /// Buffer is full, contains the capacity
        BufFull(usize),
        /// Attempted to create buffer with invalid capacity
        InvalidCapacity,
        /// Other buffer-related errors with description
        Other(String),
    }

    impl Error for BufError {}

    impl Display for BufError {
        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
            match self {
                Self::BufFull(cap) => write!(f, "Buffer is full. Capacity: {}", cap),
                Self::InvalidCapacity => write!(f, "Requested capacity is invalid"),
                Self::Other(message) => write!(f, "An unknown error occurred: {}", message),
            }
        }
    }
}

pub mod list {
    pub mod sorted {
        use std::{ops::{Index, IndexMut}, random};

        pub struct SortedList<T> {
            pub list: Vec<T>,
            sort: Box<dyn Fn(&[T]) -> Vec<T>>,
        }

        impl<T> SortedList<T> {
            pub fn new(sort_function: impl Fn(&[T]) -> Vec<T> + 'static) -> Self {
                Self {
                    list: Vec::new(),
                    sort: Box::new(sort_function),
                }
            }
            pub fn push(&mut self, item: T) {
                self.list.push(item);
                self.list = (self.sort)(&self.list);
            }
            pub fn pop(&mut self) -> Option<T>
            {
                let out = self.list.pop();
                self.list = (self.sort)(&self.list);
                out
            }
            pub fn add_no_sort(&mut self, item: T) {
                self.list.push(item);
            }
            pub fn man_sort(&mut self) {
                self.list = (self.sort)(&self.list);
            }
            pub fn get(&self, index: usize) -> Option<&T> {
                self.list.get(index)
            }
            pub fn set_sort(&mut self, sort_function: impl Fn(&[T]) -> Vec<T> + 'static) {
                self.sort = Box::new(sort_function);
            }
        }

        impl<T> Index<usize> for SortedList<T> {
            type Output = T;
            fn index(&self, index: usize) -> &Self::Output {
                &self.list[index]
            }
        }

        impl<T> IndexMut<usize> for SortedList<T> {
            fn index_mut(&mut self, index: usize) -> &mut Self::Output {
                &mut self.list[index]
            }
        }
        pub struct DefaultSorts;

        impl DefaultSorts {
            pub fn descending<T: Ord + Clone>() -> impl Fn(&[T]) -> Vec<T> {
                |slice: &[T]| {
                    let mut vec = slice.to_vec();
                    vec.sort_by(|a, b| b.cmp(a));
                    vec
                }
            }
            pub fn ascending<T: Ord + Clone>() -> impl Fn(&[T]) -> Vec<T> {
                |slice: &[T]| {
                    let mut vec = slice.to_vec();
                    vec.sort_by(|a, b| a.cmp(b));
                    vec
                }
            }
            pub fn random<T: Ord + Clone>() -> impl Fn(&[T]) -> Vec<T> {
                move |slice: &[T]| {
                    let mut vec = slice.to_vec();
                    vec.sort_by(|a, b| {
                        // Get the memory addresses of elements and use them as a source of randomness
                        let addr_a = (a as *const T) as usize;
                        let addr_b = (b as *const T) as usize;

                        // XOR with some prime numbers to distribute values better
                        let mut hash_a = addr_a.wrapping_mul(2654435761);
                        let mut hash_b = addr_b.wrapping_mul(2654435761);

                        hash_a = hash_a.checked_add(random::random::<usize>()).unwrap_or(hash_a);
                        hash_b = hash_b.checked_add(random::random::<usize>()).unwrap_or(hash_b);

                        // Use the difference to determine ordering
                        if hash_a < hash_b {
                            std::cmp::Ordering::Less
                        } else if hash_a > hash_b {
                            std::cmp::Ordering::Greater
                        } else {
                            std::cmp::Ordering::Equal
                        }
                    });
                    vec
                }
            }
        }
    }
}