use std::fmt;
#[derive(Clone)]
pub(crate) enum Table<M, E> {
Deferred(fn() -> Vec<M>),
Owned(Vec<E>),
}
impl<M, E: From<M>> Table<M, E> {
pub(crate) fn entries(&mut self) -> &[E] {
if let Table::Deferred(macro_entries) = *self {
*self = Table::Owned(entries_of(macro_entries));
}
self.as_entries()
}
pub(crate) fn into_entries(self) -> Vec<E> {
match self {
Table::Deferred(macro_entries) => entries_of(macro_entries),
Table::Owned(entries) => entries,
}
}
pub(crate) fn as_entries(&self) -> &[E] {
match self {
Table::Owned(entries) => entries,
Table::Deferred(_) => unreachable!("a table is owned after its first use"),
}
}
}
impl<M, E: From<M> + fmt::Debug> fmt::Debug for Table<M, E> {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Table::Deferred(macro_entries) => formatter
.debug_list()
.entries(entries_of::<M, E>(*macro_entries))
.finish(),
Table::Owned(entries) => formatter.debug_list().entries(entries).finish(),
}
}
}
fn entries_of<M, E: From<M>>(macro_entries: fn() -> Vec<M>) -> Vec<E> {
macro_entries().into_iter().map(E::from).collect()
}
#[cfg(test)]
mod tests {
use super::Table;
#[test]
fn into_entries_gives_the_entries_of_each_table() {
let tables: [Table<u8, u32>; 2] =
[Table::Deferred(|| vec![1, 2]), Table::Owned(vec![1, 2])];
for table in tables {
assert_eq!(table.into_entries(), [1, 2]);
}
}
#[test]
fn entries_keeps_the_entries_of_a_deferred_table() {
let mut table: Table<u8, u32> = Table::Deferred(|| vec![1, 2]);
let made_entries = table.entries().as_ptr();
let kept_entries = table.entries();
assert_eq!(kept_entries, [1, 2]);
assert_eq!(kept_entries.as_ptr(), made_entries);
}
#[test]
fn as_entries_lends_an_owned_table() {
let table: Table<u8, u32> = Table::Owned(vec![1, 2]);
assert_eq!(table.as_entries(), [1, 2]);
}
#[test]
fn fmt_shows_the_entries_of_each_table() {
let tables: [Table<u8, u32>; 2] =
[Table::Deferred(|| vec![1, 2]), Table::Owned(vec![1, 2])];
for table in tables {
assert_eq!(format!("{table:?}"), "[1, 2]");
}
}
#[test]
#[should_panic(expected = "a table is owned after its first use")]
fn as_entries_refuses_a_deferred_table() {
let table: Table<u8, u32> = Table::Deferred(Vec::new);
_ = table.as_entries();
}
}