1use crate::letter::Letter;
2use smallvec::SmallVec;
3use std::fmt;
4use std::hash::{Hash, Hasher};
5
6#[derive(Clone, Debug)]
8pub struct Word {
9 letters: SmallVec<[Letter; 8]>,
10}
11
12impl Word {
13 pub fn new() -> Self {
15 Word {
16 letters: SmallVec::new(),
17 }
18 }
19
20 pub fn from_letters(letters: Vec<Letter>) -> Self {
22 Word { letters: SmallVec::from_vec(letters) }
23 }
24
25 pub fn letters(&self) -> &[Letter] {
27 &self.letters
28 }
29
30 pub fn len(&self) -> usize {
32 self.letters.len()
33 }
34
35 pub fn is_empty(&self) -> bool {
37 self.letters.is_empty()
38 }
39
40 pub fn last_letter(&self) -> Option<&Letter> {
42 self.letters.last()
43 }
44
45 pub fn append_letter(mut self, letter: Letter) -> Self {
47 self.letters.push(letter);
48 self
49 }
50
51 pub fn concatenate(&self, other: &Word) -> Word {
53 let mut letters = SmallVec::with_capacity(self.letters.len() + other.letters.len());
54 letters.extend(self.letters.iter().cloned());
55 letters.extend(other.letters.iter().cloned());
56 Word { letters }
57 }
58
59 pub fn concatenate_letter(&self, letter: &Letter) -> Word {
61 let mut letters = SmallVec::with_capacity(self.letters.len() + 1);
62 letters.extend(self.letters.iter().cloned());
63 letters.push(letter.clone());
64 Word { letters }
65 }
66
67 pub fn prefix(&self, len: usize) -> Word {
69 let prefix_len = std::cmp::min(len, self.letters.len());
70 Word {
71 letters: self.letters[..prefix_len].iter().cloned().collect(),
72 }
73 }
74}
75
76impl Default for Word {
77 fn default() -> Self {
78 Self::new()
79 }
80}
81
82impl PartialEq for Word {
83 fn eq(&self, other: &Self) -> bool {
84 self.letters == other.letters
85 }
86}
87
88impl Eq for Word {}
89
90impl Hash for Word {
91 fn hash<H: Hasher>(&self, state: &mut H) {
92 self.letters.hash(state);
93 }
94}
95
96impl fmt::Display for Word {
97 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
98 write!(
99 f,
100 "[{}]",
101 self.letters
102 .iter()
103 .map(|l| l.to_string())
104 .collect::<Vec<_>>()
105 .join(", ")
106 )
107 }
108}
109
110#[cfg(test)]
111mod tests {
112 use super::*;
113
114 #[test]
115 fn test_word_creation() {
116 let word = Word::new();
117 assert!(word.is_empty());
118 assert_eq!(word.len(), 0);
119 }
120
121 #[test]
122 fn test_word_from_letters() {
123 let letters = vec![Letter::new("a"), Letter::new("b")];
124 let word = Word::from_letters(letters);
125 assert_eq!(word.len(), 2);
126 }
127
128 #[test]
129 fn test_word_append() {
130 let word = Word::new();
131 let word = word.append_letter(Letter::new("a"));
132 assert_eq!(word.len(), 1);
133 }
134
135 #[test]
136 fn test_word_concatenate() {
137 let w1 = Word::from_letters(vec![Letter::new("a")]);
138 let w2 = Word::from_letters(vec![Letter::new("b")]);
139 let w3 = w1.concatenate(&w2);
140 assert_eq!(w3.len(), 2);
141 }
142
143 #[test]
144 fn test_word_prefix() {
145 let word = Word::from_letters(vec![Letter::new("a"), Letter::new("b"), Letter::new("c")]);
146 let prefix = word.prefix(2);
147 assert_eq!(prefix.len(), 2);
148 }
149}