use alloc::vec::Vec;
#[derive(Debug, Clone, Eq)]
pub enum List<'a, T> {
Borrowed(&'a [&'a T]),
Owned(Vec<T>),
}
impl<'a, T> List<'a, T> {
pub fn iter(&self) -> impl Iterator<Item = &T> {
match self {
List::Borrowed(slice) => ListIter::Borrowed(slice.iter()),
List::Owned(vec) => ListIter::Owned(vec.iter()),
}
}
pub fn len(&self) -> usize {
match self {
List::Borrowed(slice) => slice.len(),
List::Owned(vec) => vec.len(),
}
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub const fn as_borrowed(&self) -> Option<&[&T]> {
match self {
List::Borrowed(slice) => Some(slice),
List::Owned(_) => None,
}
}
pub fn as_owned(&self) -> Option<&Vec<T>> {
match self {
List::Borrowed(_) => None,
List::Owned(vec) => Some(vec),
}
}
}
enum ListIter<'a, T> {
Borrowed(core::slice::Iter<'a, &'a T>),
Owned(core::slice::Iter<'a, T>),
}
impl<'a, T> Iterator for ListIter<'a, T> {
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
match self {
ListIter::Borrowed(iter) => iter.next().copied(),
ListIter::Owned(iter) => iter.next(),
}
}
}
impl<'a, T> Default for List<'a, T> {
fn default() -> Self {
List::Borrowed(&[])
}
}
impl<'a, T> From<Vec<T>> for List<'a, T> {
fn from(vec: Vec<T>) -> Self {
List::Owned(vec)
}
}
impl<'a, T> From<&'a [&'a T]> for List<'a, T> {
fn from(slice: &'a [&'a T]) -> Self {
List::Borrowed(slice)
}
}
impl<'a, T> PartialEq for List<'a, T>
where
T: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
if self.len() != other.len() {
return false;
}
self.iter().zip(other.iter()).all(|(a, b)| a == b)
}
}
#[cfg(test)]
mod tests {
use alloc::{
string::{String, ToString},
vec,
};
use super::*;
#[test]
fn list_borrowed() {
static ITEM_ONE: &str = "one";
static ITEM_TWO: &str = "two";
static ITEM_THREE: &str = "three";
static ITEMS: [&'static &str; 3] = [&ITEM_ONE, &ITEM_TWO, &ITEM_THREE];
let list: List<'_, &str> = List::Borrowed(&ITEMS);
assert_eq!(list.len(), 3);
assert!(!list.is_empty());
let expected = ["one", "two", "three"];
let mut actual = Vec::<&str>::new();
for item in list.iter() {
actual.push(*item);
}
assert_eq!(actual.as_slice(), &expected);
}
#[test]
fn list_owned() {
let vec = vec!["one".to_string(), "two".to_string(), "three".to_string()];
let list: List<'_, String> = List::from(vec);
assert_eq!(list.len(), 3);
assert!(!list.is_empty());
let collected: Vec<_> = list.iter().map(|s| s.as_str()).collect();
assert_eq!(collected, vec!["one", "two", "three"]);
}
#[test]
fn list_partial_eq_cross_variant() {
static ITEM_ONE: &str = "one";
static ITEM_TWO: &str = "two";
static ITEM_THREE: &str = "three";
static REFS: [&'static &str; 3] = [&ITEM_ONE, &ITEM_TWO, &ITEM_THREE];
let borrowed_list: List<'_, &str> = List::Borrowed(&REFS);
let owned_list: List<'_, &str> = List::Owned(vec!["one", "two", "three"]);
assert_eq!(borrowed_list, owned_list);
assert_eq!(owned_list, borrowed_list);
static OTHER_REFS: [&'static &str; 2] = [&ITEM_ONE, &ITEM_TWO];
let different_borrowed: List<'_, &str> = List::Borrowed(&OTHER_REFS);
assert_ne!(borrowed_list, different_borrowed);
let different_owned: List<'_, &str> = List::Owned(vec!["one", "two"]);
assert_ne!(borrowed_list, different_owned);
}
}