morse_lib/morse/custom.rs
1use std::{cell::RefCell, ops::Index};
2use crate::{display_chars::DisplayChars, MorseChar, MorseResult, MorseUnit};
3
4#[cfg(feature = "audio")]
5use crate::sound::Sound;
6#[cfg(feature = "audio")]
7use std::{thread, time};
8
9mod iterator;
10use iterator::*;
11
12use super::TMorse;
13
14/// ## Custom language Morse Code (feature).
15#[derive(Debug, PartialEq, Clone)]
16pub struct MorseCustom {
17 morse_str: Vec<MorseChar>,
18 display_as: DisplayChars,
19 #[cfg(feature = "audio")]
20 sound: Sound,
21 from_char_converter: fn(char) -> MorseResult<Vec<MorseUnit>>,
22 into_char_converter: fn(Vec<MorseUnit>) -> MorseResult<char>,
23}
24
25impl TMorse for MorseCustom {
26 /// Parse text into Morse Code.
27 fn parse_text(&mut self, text: &str) -> MorseResult<()> {
28 let mut morse: Vec<MorseChar> = Vec::new();
29
30 for letter in text.chars() {
31 morse.push(MorseChar::from_char(letter, self.from_char_converter)?);
32 }
33
34 self.morse_str = morse;
35 Ok(())
36 }
37
38 /// Parse binary into Morse Code.
39 fn parse_bin(&mut self, bin: &str) -> MorseResult<()> {
40 let words: Vec<&str> = bin.split("0000000").collect();
41
42 for word in words {
43 let letters: Vec<&str> = word.split("000").collect();
44
45 for letter in letters {
46 self.morse_str
47 .push(MorseChar::from_bin(letter, self.into_char_converter)?);
48 }
49 }
50
51 Ok(())
52 }
53
54 fn len(&self) -> usize {
55 self.morse_str.len()
56 }
57
58 fn remove(&mut self, idx: usize) -> MorseChar {
59 self.morse_str.remove(idx)
60 }
61}
62
63impl Index<usize> for MorseCustom {
64 type Output = MorseChar;
65
66 fn index(&self, idx: usize) -> &Self::Output {
67 &self.morse_str[idx]
68 }
69}
70
71impl MorseCustom {
72 /// Creates custom language Morse Code struct.
73 /// # Examples
74 ///
75 /// ```
76 /// use morse_lib::{MorseCustom, MorseUnit, MorseError, MorseResult};
77 /// use MorseUnit::{Dot, Line, Whitespace};
78 ///
79 /// fn from_char(letter: char) -> MorseResult<Vec<MorseUnit>>{
80 /// match letter {
81 /// 'а' | 'А' => Ok(vec![Dot, Line]),
82 /// 'б' | 'Б' => Ok(vec![Line, Dot, Dot, Dot]),
83 /// 'в' | 'В' => Ok(vec![Dot, Line, Line]),
84 /// 'г' | 'Г' => Ok(vec![Dot, Dot, Dot, Dot]),
85 /// ' ' => Ok(vec![Whitespace]),
86 /// _ => Err(MorseError::InvalidChar)
87 /// }
88 /// }
89 ///
90 /// fn into_char(letter: Vec<MorseUnit>) -> MorseResult<char> {
91 /// if letter.len() == 1 && letter[0] == Whitespace {
92 /// return Ok(' ');
93 /// } else if letter.len() == 2 && letter[0] == Dot && letter[1] == Line {
94 /// return Ok('а')
95 /// } else if letter.len() == 3 && letter[0] == Dot && letter[1] == Line && letter[2] == Line {
96 /// return Ok('в');
97 /// } else if letter.len() == 4 {
98 /// if letter[0] == Line && letter[1] == Dot && letter[2] == Dot && letter[3] == Dot {
99 /// return Ok('б');
100 /// } else {
101 /// return Ok('г');
102 /// }
103 /// } else {
104 /// Err(MorseError::InvalidMorseSequence)
105 /// }
106 /// }
107 ///
108 /// let morse_ua = MorseCustom::new(from_char, into_char);
109 /// ```
110 pub fn new(
111 from_char: fn(char) -> MorseResult<Vec<MorseUnit>>,
112 into_char: fn(Vec<MorseUnit>) -> MorseResult<char>,
113 ) -> MorseCustom {
114 MorseCustom {
115 morse_str: Vec::new(),
116 display_as: DisplayChars::default(),
117 #[cfg(feature = "audio")]
118 sound: Sound::default(),
119 from_char_converter: from_char,
120 into_char_converter: into_char,
121 }
122 }
123
124 /// Creates alias for dot in output string.
125 /// # Examples
126 ///
127 /// ```
128 /// use morse_lib::{MorseCustom, MorseUnit, MorseError, MorseResult, TMorse};
129 /// use MorseUnit::{Dot, Line, Whitespace};
130 ///
131 /// fn from_char(letter: char) -> MorseResult<Vec<MorseUnit>>{
132 /// match letter {
133 /// 'а' | 'А' => Ok(vec![Dot, Line]),
134 /// 'б' | 'Б' => Ok(vec![Line, Dot, Dot, Dot]),
135 /// 'в' | 'В' => Ok(vec![Dot, Line, Line]),
136 /// 'г' | 'Г' => Ok(vec![Dot, Dot, Dot, Dot]),
137 /// ' ' => Ok(vec![Whitespace]),
138 /// _ => Err(MorseError::InvalidChar)
139 /// }
140 /// }
141 ///
142 /// fn into_char(letter: Vec<MorseUnit>) -> MorseResult<char> {
143 /// if letter.len() == 1 && letter[0] == Whitespace {
144 /// return Ok(' ');
145 /// } else if letter.len() == 2 && letter[0] == Dot && letter[1] == Line {
146 /// return Ok('а')
147 /// } else if letter.len() == 3 && letter[0] == Dot && letter[1] == Line && letter[2] == Line {
148 /// return Ok('в');
149 /// } else if letter.len() == 4 {
150 /// if letter[0] == Line && letter[1] == Dot && letter[2] == Dot && letter[3] == Dot {
151 /// return Ok('б');
152 /// } else {
153 /// return Ok('г');
154 /// }
155 /// } else {
156 /// Err(MorseError::InvalidMorseSequence)
157 /// }
158 /// }
159 ///
160 /// let mut morse = MorseCustom::new(from_char, into_char);
161 ///
162 /// morse.parse_text("ба").unwrap();
163 /// morse.dot_as("🔥");
164 ///
165 /// assert_eq!(morse.to_string(), "⚊ 🔥 🔥 🔥 🔥 ⚊");
166 /// ```
167 pub fn dot_as(&mut self, alias: &str) {
168 self.display_as.dot = alias.to_string();
169 }
170 /// Creates alias for line in output string.
171 /// # Examples
172 ///
173 /// ```
174 /// use morse_lib::{MorseCustom, MorseUnit, MorseError, MorseResult, TMorse};
175 /// use MorseUnit::{Dot, Line, Whitespace};
176 ///
177 /// fn from_char(letter: char) -> MorseResult<Vec<MorseUnit>>{
178 /// match letter {
179 /// 'а' | 'А' => Ok(vec![Dot, Line]),
180 /// 'б' | 'Б' => Ok(vec![Line, Dot, Dot, Dot]),
181 /// 'в' | 'В' => Ok(vec![Dot, Line, Line]),
182 /// 'г' | 'Г' => Ok(vec![Dot, Dot, Dot, Dot]),
183 /// ' ' => Ok(vec![Whitespace]),
184 /// _ => Err(MorseError::InvalidChar)
185 /// }
186 /// }
187 ///
188 /// fn into_char(letter: Vec<MorseUnit>) -> MorseResult<char> {
189 /// if letter.len() == 1 && letter[0] == Whitespace {
190 /// return Ok(' ');
191 /// } else if letter.len() == 2 && letter[0] == Dot && letter[1] == Line {
192 /// return Ok('а')
193 /// } else if letter.len() == 3 && letter[0] == Dot && letter[1] == Line && letter[2] == Line {
194 /// return Ok('в');
195 /// } else if letter.len() == 4 {
196 /// if letter[0] == Line && letter[1] == Dot && letter[2] == Dot && letter[3] == Dot {
197 /// return Ok('б');
198 /// } else {
199 /// return Ok('г');
200 /// }
201 /// } else {
202 /// Err(MorseError::InvalidMorseSequence)
203 /// }
204 /// }
205 ///
206 /// let mut morse = MorseCustom::new( from_char, into_char);
207 ///
208 /// morse.parse_text("ба").unwrap();
209 /// morse.line_as("➖");
210 ///
211 /// assert_eq!(morse.to_string(), "➖ . . . . ➖");
212 /// ```
213 pub fn line_as(&mut self, alias: &str) {
214 self.display_as.line = alias.to_string();
215 }
216 /// Creates alias for whitespace in output string.
217 /// # Examples
218 ///
219 /// ```
220 /// use morse_lib::{MorseCustom, MorseUnit, MorseError, MorseResult, TMorse};
221 /// use MorseUnit::{Dot, Line, Whitespace};
222 ///
223 /// fn from_char(letter: char) -> MorseResult<Vec<MorseUnit>>{
224 /// match letter {
225 /// 'а' | 'А' => Ok(vec![Dot, Line]),
226 /// 'б' | 'Б' => Ok(vec![Line, Dot, Dot, Dot]),
227 /// 'в' | 'В' => Ok(vec![Dot, Line, Line]),
228 /// 'г' | 'Г' => Ok(vec![Dot, Dot, Dot, Dot]),
229 /// ' ' => Ok(vec![Whitespace]),
230 /// _ => Err(MorseError::InvalidChar)
231 /// }
232 /// }
233 ///
234 /// fn into_char(letter: Vec<MorseUnit>) -> MorseResult<char> {
235 /// if letter.len() == 1 && letter[0] == Whitespace {
236 /// return Ok(' ');
237 /// } else if letter.len() == 2 && letter[0] == Dot && letter[1] == Line {
238 /// return Ok('а')
239 /// } else if letter.len() == 3 && letter[0] == Dot && letter[1] == Line && letter[2] == Line {
240 /// return Ok('в');
241 /// } else if letter.len() == 4 {
242 /// if letter[0] == Line && letter[1] == Dot && letter[2] == Dot && letter[3] == Dot {
243 /// return Ok('б');
244 /// } else {
245 /// return Ok('г');
246 /// }
247 /// } else {
248 /// Err(MorseError::InvalidMorseSequence)
249 /// }
250 /// }
251 ///
252 /// let mut morse = MorseCustom::new( from_char, into_char);
253 ///
254 /// morse.parse_text("б а").unwrap();
255 /// morse.whitespace_as("🚧");
256 ///
257 /// assert_eq!(morse.to_string(), "⚊ . . . 🚧 . ⚊");
258 /// ```
259 pub fn whitespace_as(&mut self, alias: &str) {
260 self.display_as.whitespace = alias.to_string();
261 }
262
263 /// Play sound that represent Morse Code.
264 /// <div class="warning">
265 ///
266 /// **Only** available **if "audio"** feature is **enabled.**
267 ///
268 /// </div>
269 ///
270 #[cfg(feature = "audio")]
271 pub fn to_beep(&self) {
272 let morse_str = RefCell::new(self.morse_str.clone());
273 for (idx, m_char) in morse_str.borrow_mut().iter_mut().enumerate() {
274 m_char.frequency(self.sound.frequency);
275 m_char.play_speed(self.sound.speed);
276
277 m_char.to_beep();
278
279 // The space between letters is three units
280 if idx < self.morse_str.len() - 1 {
281 thread::sleep(time::Duration::from_secs(3));
282 }
283 }
284 }
285
286 /// Set sound frequency in MHz.
287 /// <div class="warning">
288 ///
289 /// **Only** available **if "audio"** feature is **enabled.**
290 ///
291 /// </div>
292 ///
293 /// # Examples
294 ///
295 /// ```
296 /// use morse_lib::{MorseCustom, MorseUnit, MorseError, MorseResult, TMorse};
297 /// use MorseUnit::{Dot, Line, Whitespace};
298 ///
299 /// fn from_char(letter: char) -> MorseResult<Vec<MorseUnit>>{
300 /// match letter {
301 /// 'а' | 'А' => Ok(vec![Dot, Line]),
302 /// 'б' | 'Б' => Ok(vec![Line, Dot, Dot, Dot]),
303 /// 'в' | 'В' => Ok(vec![Dot, Line, Line]),
304 /// 'г' | 'Г' => Ok(vec![Dot, Dot, Dot, Dot]),
305 /// ' ' => Ok(vec![Whitespace]),
306 /// _ => Err(MorseError::InvalidChar)
307 /// }
308 /// }
309 ///
310 /// fn into_char(letter: Vec<MorseUnit>) -> MorseResult<char> {
311 /// if letter.len() == 1 && letter[0] == Whitespace {
312 /// return Ok(' ');
313 /// } else if letter.len() == 2 && letter[0] == Dot && letter[1] == Line {
314 /// return Ok('а')
315 /// } else if letter.len() == 3 && letter[0] == Dot && letter[1] == Line && letter[2] == Line {
316 /// return Ok('в');
317 /// } else if letter.len() == 4 {
318 /// if letter[0] == Line && letter[1] == Dot && letter[2] == Dot && letter[3] == Dot {
319 /// return Ok('б');
320 /// } else {
321 /// return Ok('г');
322 /// }
323 /// } else {
324 /// Err(MorseError::InvalidMorseSequence)
325 /// }
326 /// }
327 ///
328 /// let mut morse = MorseCustom::new(from_char, into_char);
329 ///
330 /// morse.parse_text("б а").unwrap();
331 /// morse.frequency(643.0);
332 /// ```
333 #[cfg(feature = "audio")]
334 pub fn frequency(&mut self, frequency: f32) {
335 self.sound.frequency = frequency;
336 }
337
338 /// Set sound speed.
339 /// <div class="warning">
340 ///
341 /// **Only** available **if "audio"** feature is **enabled.**
342 ///
343 /// </div>
344 ///
345 /// * '1' - normal speed
346 /// * '> 1' - faster
347 /// * '< 1' - slower
348 /// # Examples
349 ///
350 /// ```
351 /// use morse_lib::{MorseCustom, MorseUnit, MorseError, MorseResult, TMorse};
352 /// use MorseUnit::{Dot, Line, Whitespace};
353 ///
354 /// fn from_char(letter: char) -> MorseResult<Vec<MorseUnit>>{
355 /// match letter {
356 /// 'а' | 'А' => Ok(vec![Dot, Line]),
357 /// 'б' | 'Б' => Ok(vec![Line, Dot, Dot, Dot]),
358 /// 'в' | 'В' => Ok(vec![Dot, Line, Line]),
359 /// 'г' | 'Г' => Ok(vec![Dot, Dot, Dot, Dot]),
360 /// ' ' => Ok(vec![Whitespace]),
361 /// _ => Err(MorseError::InvalidChar)
362 /// }
363 /// }
364 ///
365 /// fn into_char(letter: Vec<MorseUnit>) -> MorseResult<char> {
366 /// if letter.len() == 1 && letter[0] == Whitespace {
367 /// return Ok(' ');
368 /// } else if letter.len() == 2 && letter[0] == Dot && letter[1] == Line {
369 /// return Ok('а')
370 /// } else if letter.len() == 3 && letter[0] == Dot && letter[1] == Line && letter[2] == Line {
371 /// return Ok('в');
372 /// } else if letter.len() == 4 {
373 /// if letter[0] == Line && letter[1] == Dot && letter[2] == Dot && letter[3] == Dot {
374 /// return Ok('б');
375 /// } else {
376 /// return Ok('г');
377 /// }
378 /// } else {
379 /// Err(MorseError::InvalidMorseSequence)
380 /// }
381 /// }
382 ///
383 /// let mut morse = MorseCustom::new( from_char, into_char);
384 ///
385 /// morse.parse_text("б а").unwrap();
386 /// morse.play_speed(2.0);
387 /// ```
388 #[cfg(feature = "audio")]
389 pub fn play_speed(&mut self, speed: f32) {
390 self.sound.speed = speed;
391 }
392
393 /// Creates binary-formatted Morse Code.
394 /// # Examples
395 ///
396 /// ```
397 /// use morse_lib::{MorseCustom, MorseUnit, MorseError, MorseResult, TMorse};
398 /// use MorseUnit::{Dot, Line, Whitespace};
399 ///
400 /// fn from_char(letter: char) -> MorseResult<Vec<MorseUnit>>{
401 /// match letter {
402 /// 'а' | 'А' => Ok(vec![Dot, Line]),
403 /// 'б' | 'Б' => Ok(vec![Line, Dot, Dot, Dot]),
404 /// 'в' | 'В' => Ok(vec![Dot, Line, Line]),
405 /// 'г' | 'Г' => Ok(vec![Dot, Dot, Dot, Dot]),
406 /// ' ' => Ok(vec![Whitespace]),
407 /// _ => Err(MorseError::InvalidChar)
408 /// }
409 /// }
410 ///
411 /// fn into_char(letter: Vec<MorseUnit>) -> MorseResult<char> {
412 /// if letter.len() == 1 && letter[0] == Whitespace {
413 /// return Ok(' ');
414 /// } else if letter.len() == 2 && letter[0] == Dot && letter[1] == Line {
415 /// return Ok('а')
416 /// } else if letter.len() == 3 && letter[0] == Dot && letter[1] == Line && letter[2] == Line {
417 /// return Ok('в');
418 /// } else if letter.len() == 4 {
419 /// if letter[0] == Line && letter[1] == Dot && letter[2] == Dot && letter[3] == Dot {
420 /// return Ok('б');
421 /// } else {
422 /// return Ok('г');
423 /// }
424 /// } else {
425 /// Err(MorseError::InvalidMorseSequence)
426 /// }
427 /// }
428 ///
429 /// let mut morse = MorseCustom::new(from_char, into_char);
430 ///
431 /// morse.parse_text("б а").unwrap();
432 ///
433 /// assert_eq!(morse.to_bin_str(),"111010101000000010111");
434 /// ```
435 pub fn to_bin_str(&self) -> String {
436 let mut string = String::new();
437
438 for (idx, m_char) in self.morse_str.iter().enumerate() {
439 string.push_str(&m_char.to_bin_str());
440
441 // The space between letters is three units
442 if idx < self.morse_str.len() - 1 {
443 string.push_str("000");
444 }
445 }
446
447 string
448 }
449 /// Convert Morse Code back to text.
450 pub fn to_text(&self) -> String {
451 let mut text = String::new();
452
453 for m_char in &self.morse_str {
454 text.push(m_char.get_letter());
455 }
456
457 text
458 }
459
460 pub fn iter(&self) -> MorseIterator {
461 MorseIterator::init(self)
462 }
463}
464
465impl IntoIterator for MorseCustom {
466 type Item = MorseChar;
467 type IntoIter = MorseIntoIterator;
468
469 fn into_iter(self) -> MorseIntoIterator {
470 MorseIntoIterator { morse: self }
471 }
472}
473
474impl ToString for MorseCustom {
475 /// Return String value of Morse Code.
476 fn to_string(&self) -> String {
477 let mut string = String::new();
478 let morse = RefCell::new(self.morse_str.clone());
479
480 for (idx, m_char) in morse.borrow_mut().iter_mut().enumerate() {
481 m_char.dot_as(&self.display_as.dot);
482 m_char.line_as(&self.display_as.line);
483 m_char.whitespace_as(&self.display_as.whitespace);
484 string.push_str(&m_char.to_string());
485
486 // The space between letters is three units
487 if idx < self.morse_str.len() - 1 {
488 string.push_str(" ");
489 }
490 }
491
492 string
493 }
494}
495
496#[cfg(test)]
497mod morse_tests {
498 use super::*;
499 use crate::morse_unit::MorseUnit::{Dot, Line, Whitespace};
500 use crate::{MorseError, MorseResult, MorseUnit};
501
502 fn from_char(letter: char) -> MorseResult<Vec<MorseUnit>> {
503 println!("{} confver", letter.to_ascii_lowercase());
504 match letter {
505 'а' | 'А' => Ok(vec![Dot, Line]),
506 'б' | 'Б' => Ok(vec![Line, Dot, Dot, Dot]),
507 'в' | 'В' => Ok(vec![Dot, Line, Line]),
508 'г' | 'Г' => Ok(vec![Dot, Dot, Dot, Dot]),
509 ' ' => Ok(vec![Whitespace]),
510 _ => Err(MorseError::InvalidChar),
511 }
512 }
513 fn into_char(letter: Vec<MorseUnit>) -> MorseResult<char> {
514 if letter.len() == 1 && letter[0] == Whitespace {
515 return Ok(' ');
516 } else if letter.len() == 2 && letter[0] == Dot && letter[1] == Line {
517 return Ok('а');
518 } else if letter.len() == 3 && letter[0] == Dot && letter[1] == Line && letter[2] == Line {
519 return Ok('в');
520 } else if letter.len() == 4 {
521 if letter[0] == Line && letter[1] == Dot && letter[2] == Dot && letter[3] == Dot {
522 return Ok('б');
523 } else {
524 return Ok('г');
525 }
526 } else {
527 Err(MorseError::InvalidMorseSequence)
528 }
529 }
530
531 #[test]
532 fn create_from_text_str() {
533 let mut morse = MorseCustom::new(from_char, into_char);
534 morse.parse_text("Ба").unwrap();
535
536 assert_eq!(morse.to_bin_str(), "11101010100010111");
537 }
538
539 #[test]
540 fn create_from_binary_str() {
541 const BIN: &str = "11101010100010111";
542 let mut morse = MorseCustom::new(from_char, into_char);
543
544 morse.parse_bin(BIN).unwrap();
545
546 assert_eq!(morse.to_text(), "ба");
547 }
548
549 #[test]
550 fn to_string() {
551 let mut morse = MorseCustom::new(from_char, into_char);
552 morse.parse_text("ба").unwrap();
553
554 assert_eq!(morse.to_string(), "⚊ . . . . ⚊");
555 }
556
557 #[test]
558 fn to_bin_str() {
559 let mut morse = MorseCustom::new(from_char, into_char);
560 morse.parse_text("ба").unwrap();
561 println!("{} BIIIN", morse.to_bin_str());
562
563 assert_eq!(morse.to_bin_str(), "11101010100010111");
564 }
565 #[test]
566 fn set_aliases_for_whitespace_lines_and_dots() {
567 let mut morse = MorseCustom::new(from_char, into_char);
568 morse.parse_text("ба ба").unwrap();
569
570 println!("{} TEXXT", morse.to_text());
571
572 morse.dot_as("🔥");
573 morse.line_as("➖");
574 morse.whitespace_as("🚧");
575
576 assert_eq!(
577 morse.to_string(),
578 "➖ 🔥 🔥 🔥 🔥 ➖ 🚧 ➖ 🔥 🔥 🔥 🔥 ➖"
579 );
580 }
581}