use std::fmt::{Debug, Display, Formatter, Result as FmtResult};
pub struct KeyArray<K> {
keys: Vec<K>,
idx: usize,
}
impl<K> KeyArray<K>
where
K: Clone + PartialEq + Debug + Display,
{
pub fn new(keys: impl IntoIterator<Item = K>) -> Self {
let keys: Vec<K> = keys.into_iter().collect();
assert!(
!keys.is_empty(),
"KeyArray::new: must supply at least one key"
);
KeyArray { keys, idx: 0 }
}
pub fn new_with(keys: impl IntoIterator<Item = K>, start_idx: usize) -> Self {
let keys: Vec<K> = keys.into_iter().collect();
assert!(
!keys.is_empty(),
"KeyArray::new_with: must supply keys"
);
assert!(
start_idx < keys.len(),
"KeyArray::new_with: start_idx {} out of bounds",
start_idx
);
KeyArray {
keys,
idx: start_idx,
}
}
pub fn change(&mut self, i: usize) {
assert!(
i < self.keys.len(),
"KeyArray::change: index {} out of bounds",
i
);
self.idx = i;
}
pub fn current(&self) -> &K {
&self.keys[self.idx]
}
pub fn current_index(&self) -> usize {
self.idx
}
pub fn keys(&self) -> &[K] {
&self.keys
}
pub fn len(&self) -> usize {
self.keys.len()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn push(&mut self, key: K) {
self.keys.push(key);
}
pub fn insert(&mut self, i: usize, key: K) {
assert!(
i <= self.keys.len(),
"KeyArray::insert: index {} out of bounds",
i
);
self.keys.insert(i, key);
if i <= self.idx {
self.idx += 1;
}
}
pub fn remove(&mut self, i: usize) -> K {
assert!(
i < self.keys.len(),
"KeyArray::remove: index {} out of bounds",
i
);
let removed = self.keys.remove(i);
if self.idx >= self.keys.len() {
self.idx = self.keys.len().saturating_sub(1);
}
removed
}
}
impl<K> Display for KeyArray<K>
where
K: Clone + PartialEq + Debug + Display,
{
fn fmt(&self, f: &mut Formatter) -> FmtResult {
write!(
f,
"keys={:?}, current_idx={}, current={}",
self.keys,
self.idx,
self.current()
)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn basic_flow() {
let mut ka = KeyArray::new(["A", "B", "C"]);
assert_eq!(ka.current(), &"A");
assert_eq!(ka.current_index(), 0);
ka.change(2);
assert_eq!(ka.current(), &"C");
ka.push("D");
assert_eq!(ka.len(), 4);
assert_eq!(ka.keys(), &["A", "B", "C", "D"]);
ka.insert(0, "X");
assert_eq!(ka.keys()[0], "X");
assert_eq!(ka.current(), &"C");
let removed = ka.remove(0);
assert_eq!(removed, "X");
assert_eq!(ka.keys()[0], "A");
}
#[test]
#[should_panic(expected = "out of bounds")]
fn change_oob_panics() {
let mut ka = KeyArray::new(["Only"]);
ka.change(5);
}
#[test]
fn display_format() {
let ka = KeyArray::new(["Up", "Down"]);
let s = format!("{}", ka);
assert!(s.contains(r#"["Up", "Down"]"#) && s.contains("current_idx=0"));
}
#[test]
fn empty_and_len() {
let ka = KeyArray::new_with(["One"], 0);
assert!(!ka.is_empty());
assert_eq!(ka.len(), 1);
let mut empty = KeyArray::new(["X"]);
empty.remove(0);
assert!(empty.is_empty());
assert_eq!(empty.len(), 0);
}
}