trait-utils 0.0.0

Traits for shared behavior.
Documentation
/*
 * Description: Traits for shared behavior.
 *
 * Copyright (C) 2025 d@nny mc² <dmc2@hypnicjerk.ai>
 * SPDX-License-Identifier: LGPL-3.0-or-later
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

//! Traits for shared behavior.

/* Ensure any doctest warnings fail the doctest! */
#![doc(test(attr(deny(warnings))))]
#![warn(missing_docs)]

use std::iter;


/// A trait for mutable growable vectors.
pub trait VecLike: IntoIterator<Item=Self::T>+iter::Extend<Self::T> {
  /// The type of input elements.
  type T;
  /// Create an instance of this container without allocating any memory.
  ///
  /// Also see [`ConstDefault`] for an orthogonal trait for `const` instances.
  #[inline(always)]
  fn new() -> Self
  where Self: Sized {
    Self::with_capacity(0)
  }
  /// Create an instance of this container with at least `n` elements allocated.
  fn with_capacity(n: usize) -> Self
  where Self: Sized;

  /// Convert an instance of this vector into another type.
  #[inline]
  fn map_elements<T2, E2>(self, f: impl FnMut(Self::T) -> T2) -> E2
  where
    E2: VecLike<T=T2>,
    Self: Sized,
  {
    let mut new_elements = E2::with_capacity(self.len());
    new_elements.extend(self.into_iter().map(f));
    new_elements
  }

  /// Push an element to the end.
  fn push(&mut self, x: Self::T);
  /// Pop an element from the end.
  fn pop(&mut self) -> Option<Self::T>;
  /// The number of elements.
  fn len(&self) -> usize;
  /// Whether there are any elements.
  #[inline(always)]
  fn is_empty(&self) -> bool { self.len() == 0 }
  /// A contiguous slice of memory referring to the elements.
  fn as_slice(&self) -> &[Self::T];
}

impl<T> VecLike for Vec<T> {
  type T = T;
  #[inline(always)]
  fn new() -> Self { Vec::new() }
  #[inline(always)]
  fn with_capacity(n: usize) -> Self { Vec::with_capacity(n) }
  #[inline(always)]
  fn push(&mut self, x: T) { Vec::push(self, x); }
  #[inline(always)]
  fn pop(&mut self) -> Option<T> { Vec::pop(self) }
  #[inline(always)]
  fn len(&self) -> usize { Vec::len(self) }
  #[inline(always)]
  fn is_empty(&self) -> bool { Vec::is_empty(self) }
  #[inline(always)]
  fn as_slice(&self) -> &[Self::T] { &self[..] }
}

#[cfg(feature = "smallvec")]
impl<T, const N: usize> VecLike for SmallVec<T, N> {
  type T = T;
  #[inline(always)]
  fn new() -> Self { SmallVec::new() }
  #[inline(always)]
  fn with_capacity(n: usize) -> Self { SmallVec::with_capacity(n) }
  #[inline(always)]
  fn push(&mut self, x: T) { SmallVec::push(self, x); }
  #[inline(always)]
  fn pop(&mut self) -> Option<T> { SmallVec::pop(self) }
  #[inline(always)]
  fn len(&self) -> usize { SmallVec::len(self) }
  #[inline(always)]
  fn is_empty(&self) -> bool { SmallVec::is_empty(self) }
  #[inline(always)]
  fn as_slice(&self) -> &[Self::T] { &self[..] }
}

/// A `const` version of the [`Default`] trait.
pub trait ConstDefault {
  /// The statically-sized `const` instance of this type.
  const DEFAULT: Self;
}
impl<T> ConstDefault for Vec<T> {
  const DEFAULT: Self = Vec::new();
}
#[cfg(feature = "smallvec")]
impl<T, const N: usize> ConstDefault for SmallVec<T, N> {
  const DEFAULT: Self = SmallVec::new();
}