morse_lib/morse/
international.rs

1use std::{cell::RefCell, ops::Index};
2
3use crate::{
4    display_chars::DisplayChars, MorseChar, MorseResult, MorseUnit,
5};
6
7#[cfg(feature = "audio")]
8use crate::sound::Sound;
9#[cfg(feature = "audio")]
10use std::{thread, time};
11
12use super::TMorse;
13
14mod iterator;
15use iterator::*;
16
17mod converters;
18pub use converters::*;
19
20/// ## International standart Morse Code (default feature).
21#[derive(Debug, PartialEq, Clone)]
22pub struct Morse {
23    morse_str: Vec<MorseChar>,
24    display_as: DisplayChars,
25    #[cfg(feature = "audio")]
26    sound: Sound,
27    from_char_converter: fn(char) -> MorseResult<Vec<MorseUnit>>,
28    into_char_converter: fn(Vec<MorseUnit>) -> MorseResult<char>,
29}
30
31impl TMorse for Morse {
32    /// Parse text into Morse Code.
33    fn parse_text(&mut self, text: &str) -> MorseResult<()> {
34        let mut morse: Vec<MorseChar> = Vec::new();
35
36        for letter in text.chars() {
37            morse.push(MorseChar::from_char(letter, self.from_char_converter)?);
38        }
39
40        Ok(())
41    }
42
43    /// Parse binary into Morse Code.
44    fn parse_bin(&mut self, bin: &str) -> MorseResult<()> {
45        let words: Vec<&str> = bin.split("0000000").collect();
46
47        for word in words {
48            let letters: Vec<&str> = word.split("000").collect();
49
50            for letter in letters {
51                self.morse_str
52                    .push(MorseChar::from_bin(letter, self.into_char_converter)?);
53            }
54        }
55
56        Ok(())
57    }
58
59    fn len(&self) -> usize {
60        self.morse_str.len()
61    }
62
63    fn remove(&mut self, idx: usize) -> MorseChar {
64        self.morse_str.remove(idx)
65    }
66}
67
68impl Index<usize> for Morse {
69    type Output = MorseChar;
70
71    fn index(&self, idx: usize) -> &Self::Output {
72        &self.morse_str[idx]
73    }
74}
75
76impl Morse {
77    /// Creates International Morse Code struct from text.
78    /// # Examples
79    ///
80    /// ```
81    /// use morse_lib::Morse;
82    ///
83    /// let morse = Morse::from_text("sos").unwrap();
84    ///
85    /// assert_eq!(morse.to_string(), ". . .   ⚊ ⚊ ⚊   . . .");
86    /// ```
87    pub fn from_text(text: &str) -> MorseResult<Morse> {
88        let mut morse_str: Vec<MorseChar> = Vec::new();
89
90        for letter in text.chars() {
91            morse_str.push(MorseChar::from_char(letter, from_int_char)?);
92        }
93
94        Ok(Morse {
95            morse_str,
96            ..Morse::default()
97        })
98    }
99
100    /// Creates International Morse Code struct from binary.
101    /// # Examples
102    ///
103    /// ```
104    /// use morse_lib::Morse;
105    ///
106    /// let morse = Morse::from_bin("101010001110111011100010101").unwrap();
107    ///
108    /// assert_eq!(morse.to_string(), ". . .   ⚊ ⚊ ⚊   . . .");
109    /// ```
110    pub fn from_bin(bin: &str) -> MorseResult<Morse> {
111        let words: Vec<&str> = bin.split("0000000").collect();
112        let mut morse_str: Vec<MorseChar> = Vec::new();
113
114        for word in words {
115            let letters: Vec<&str> = word.split("000").collect();
116
117            for letter in letters {
118                morse_str.push(MorseChar::from_bin(letter, into_int_char)?);
119            }
120        }
121
122        Ok(Morse {
123            morse_str,
124            ..Morse::default()
125        })
126    }
127
128    
129
130    /// Creates alias for dot in output string.
131    /// # Examples
132    ///
133    /// ```
134    /// use morse_lib::Morse;
135    ///
136    /// let mut morse = Morse::from_text("sos").unwrap();
137    /// morse.dot_as("🔥");
138    ///
139    /// assert_eq!(morse.to_string(), "🔥 🔥 🔥   ⚊ ⚊ ⚊   🔥 🔥 🔥");
140    /// ```
141    pub fn dot_as(&mut self, alias: &str) {
142        self.display_as.dot = alias.to_string();
143    }
144    /// Creates alias for line in output string.
145    /// # Examples
146    ///
147    /// ```
148    /// use morse_lib::Morse;
149    ///
150    /// let mut morse = Morse::from_text("sos").unwrap();
151    /// morse.line_as("➖");
152    ///
153    /// assert_eq!(morse.to_string(), ". . .   ➖ ➖ ➖   . . .");
154    /// ```
155    pub fn line_as(&mut self, alias: &str) {
156        self.display_as.line = alias.to_string();
157    }
158    /// Creates alias for whitespace in output string.
159    /// # Examples
160    ///
161    /// ```
162    /// use morse_lib::Morse;
163    ///
164    /// let mut morse = Morse::from_text("s o").unwrap();
165    /// morse.whitespace_as("🚧");
166    ///
167    /// assert_eq!(morse.to_string(), ". . .   🚧   ⚊ ⚊ ⚊");
168    /// ```
169    pub fn whitespace_as(&mut self, alias: &str) {
170        self.display_as.whitespace = alias.to_string();
171    }
172
173    /// Play sound that represent Morse Code.
174    /// <div class="warning">
175    /// 
176    /// **Only** available **if "audio"** feature is **enabled.**
177    /// 
178    /// </div>
179    #[cfg(feature = "audio")]
180    pub fn to_beep(&self) {
181        let morse_str = RefCell::new(self.morse_str.clone());
182        for (idx, m_char) in morse_str.borrow_mut().iter_mut().enumerate() {
183            m_char.frequency(self.sound.frequency);
184            m_char.play_speed(self.sound.speed);
185
186            m_char.to_beep();
187
188            // The space between letters is three units
189            if idx < self.morse_str.len() - 1 {
190                thread::sleep(time::Duration::from_secs(3));
191            }
192        }
193    }
194
195    /// Set sound frequency in MHz.
196    /// <div class="warning">
197    /// 
198    /// **Only** available **if "audio"** feature is **enabled.**
199    /// 
200    /// </div>
201    /// 
202    /// # Examples
203    /// ```
204    /// use morse_lib::Morse;
205    ///
206    /// let mut morse = Morse::from_text("s o").unwrap();
207    /// morse.frequency(643.0);
208    /// ```
209    #[cfg(feature = "audio")]
210    pub fn frequency(&mut self, frequency: f32) {
211        self.sound.frequency = frequency;
212    }
213
214    /// Set sound speed.
215    /// <div class="warning">
216    /// 
217    /// **Only** available **if "audio"** feature is **enabled.**
218    /// 
219    /// </div>
220    /// 
221    /// * '1' - normal speed
222    /// * '> 1' - faster
223    /// * '< 1' - slower
224    /// 
225    /// # Examples
226    /// ```
227    /// use morse_lib::Morse;
228    ///
229    /// let mut morse = Morse::from_text("s o").unwrap();
230    /// morse.play_speed(2.0);
231    /// ```
232    #[cfg(feature = "audio")]
233    pub fn play_speed(&mut self, speed: f32) {
234        self.sound.speed = speed;
235    }
236    /// Creates binary-formatted Morse Code.
237    /// # Examples
238    ///
239    /// ```
240    /// use morse_lib::Morse;
241    ///
242    /// let morse = Morse::from_text("sos").unwrap();
243    ///
244    /// assert_eq!(morse.to_bin_str(), "101010001110111011100010101");
245    /// ```
246    pub fn to_bin_str(&self) -> String {
247        let mut string = String::new();
248
249        for (idx, m_char) in self.morse_str.iter().enumerate() {
250            string.push_str(&m_char.to_bin_str());
251
252            // The space between letters is three units
253            if idx < self.morse_str.len() - 1 {
254                string.push_str("000");
255            }
256        }
257
258        string
259    }
260    /// Convert Morse Code back to text.
261    /// # Examples
262    ///
263    /// ```
264    /// use morse_lib::Morse;
265    ///
266    /// let morse = Morse::from_bin("101010001110111011100010101").unwrap();
267    /// let text = morse.to_text();
268    ///
269    /// assert_eq!(text, "sos");
270    /// ```
271    pub fn to_text(&self) -> String {
272        let mut text = String::new();
273
274        for m_char in &self.morse_str {
275            text.push(m_char.get_letter());
276        }
277
278        text
279    }
280
281    /// Now we can iterate:
282    /// ```
283    /// use morse_lib::Morse;
284    ///
285    /// let morse = Morse::from_text("sos").unwrap();
286    /// for char in morse.iter() {
287    ///     println!("{}", char);
288    /// }
289    /// ```
290    pub fn iter(&self) -> MorseIterator {
291        MorseIterator::init(self)
292    }
293}
294
295impl IntoIterator for Morse {
296    type Item = MorseChar;
297    type IntoIter = MorseIntoIterator;
298
299    /// ```
300    /// use morse_lib::Morse;
301    ///
302    /// let morse = Morse::from_text("sos").unwrap();
303    /// for char in morse {
304    /// println!("{}", char);
305    /// }
306    /// ```
307    fn into_iter(self) -> MorseIntoIterator {
308        MorseIntoIterator { morse: self }
309    }
310}
311
312impl Default for Morse {
313    fn default() -> Self {
314        Self {
315            morse_str: Vec::new(),
316            display_as: DisplayChars::default(),
317            #[cfg(feature = "audio")]
318            sound: Sound::default(),
319            from_char_converter: from_int_char,
320            into_char_converter: into_int_char,
321        }
322    }
323}
324
325impl ToString for Morse {
326    /// Return String value of Morse Code.
327    fn to_string(&self) -> String {
328        let mut string = String::new();
329        let morse = RefCell::new(self.morse_str.clone());
330
331        for (idx, m_char) in morse.borrow_mut().iter_mut().enumerate() {
332            m_char.dot_as(&self.display_as.dot);
333            m_char.line_as(&self.display_as.line);
334            m_char.whitespace_as(&self.display_as.whitespace);
335            string.push_str(&m_char.to_string());
336
337            // The space between letters is three units
338            if idx < self.morse_str.len() - 1 {
339                string.push_str("   ");
340            }
341        }
342
343        string
344    }
345}
346
347#[cfg(test)]
348mod morse_tests {
349    use super::*;
350
351    #[test]
352    fn create_from_text_str() {
353        assert_eq!(
354            Morse::from_text("Hello").unwrap().to_bin_str(),
355            "1010101000100010111010100010111010100011101110111"
356        );
357    }
358
359    #[test]
360    fn create_from_binary_str() {
361        const HELLO_BIN: &str = "1010101000100010111010100010111010100011101110111";
362        assert_eq!(Morse::from_bin(HELLO_BIN).unwrap().to_bin_str(), HELLO_BIN);
363    }
364
365    #[test]
366    fn to_string() {
367        assert_eq!(
368            Morse::from_text("hi u").unwrap().to_string(),
369            ". . . .   . .       . . ⚊"
370        );
371    }
372
373    #[test]
374    fn to_bin_str() {
375        assert_eq!(
376            Morse::from_text("hi u").unwrap().to_bin_str(),
377            "101010100010100000001010111"
378        );
379    }
380    #[test]
381    fn set_aliases_for_whitespace_lines_and_dots() {
382        let mut morse = Morse::from_text("hi u").unwrap();
383
384        morse.dot_as("🔥");
385        morse.line_as("➖");
386        morse.whitespace_as("🚧");
387
388        assert_eq!(morse.to_string(), "🔥 🔥 🔥 🔥   🔥 🔥   🚧   🔥 🔥 ➖");
389    }
390}