typo-eq 0.2.0

Typo-eq is a typing training app for other languages. All it needs is a dictionary for words and their translations.
Documentation
use std::fmt::Display;
use std::io::{BufReader, SeekFrom};
use std::{fs::File, io::Seek};

use quick_xml::events::Event;
use quick_xml::Reader;

#[derive(Debug, Clone)]
pub enum DictionaryEntry {
    Word(DictionaryWord),
    Phrase(DictionaryPhrase),
}

#[derive(Debug, Clone)]
pub struct DictionaryWord {
    pub kind: String,
    pub identifier: String,
    pub translation: Vec<String>,
}

impl DictionaryWord {
    pub fn new(kind: String) -> Self {
        Self {
            kind,
            identifier: String::new(),
            translation: Vec::new(),
        }
    }
}

#[derive(Debug, Clone)]
pub struct DictionaryPhrase {
    pub kind: String,
    pub identifier: String,
    pub translation: String,
    pub example_for: String,
}

impl DictionaryPhrase {
    pub fn new(kind: String) -> Self {
        Self {
            kind,
            identifier: String::new(),
            translation: String::new(),
            example_for: String::new(),
        }
    }
}

impl Display for DictionaryWord {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}->{}", self.identifier, self.translation.concat())
    }
}

#[derive(Clone)]
pub struct Dictionary {
    pub entries: Vec<DictionaryEntry>,
    pub words: Vec<DictionaryWord>,
    pub phrases: Vec<DictionaryPhrase>,
    pub from: String,
    pub to: String,
}

impl Dictionary {
    pub fn from_file(mut file: File) -> Self {
        file.seek(SeekFrom::Start(0)).unwrap();
        let file = BufReader::new(file);
        let mut entries = Vec::new();
        let mut words = Vec::new();
        let mut phrases = Vec::new();
        let mut from = "Unkown".to_string();
        let mut to   = "Unkown".to_string();

        let mut parser = Reader::from_reader(file);
        let mut word = None;
        let mut phrase = None;
        let mut buf = Vec::new();
        let mut current_tag = String::new();
        let mut current_attrs = Vec::new();
        loop {
            match parser.read_event_into(&mut buf) {
                Err(e) => panic!("Error at position {}: {:?}", parser.buffer_position(), e),
                Ok(Event::Eof) => break,
                Ok(Event::Start(e)) => {
                    let tag = e.name();
                    let tag = String::from_utf8(tag.as_ref().to_vec()).unwrap();
                    if tag.as_str() == "ar" {
                        let new_entry = DictionaryWord::new(tag.clone());
                        word = Some(new_entry);
                    }
                    if tag.as_str() == "xdxf" {
                        let lang_from = e.try_get_attribute("lang_from");
                        let lang_to = e.try_get_attribute("lang_to");
                        if let Ok(lang_from) = lang_from {
                            if let Some(lang_from) = lang_from {
                                from = String::from_utf8(lang_from.value.to_vec()).unwrap();
                            }
                        }
                        if let Ok(lang_to) = lang_to {
                            if let Some(lang_to) = lang_to {
                                to = String::from_utf8(lang_to.value.to_vec()).unwrap();
                            }
                        }
                    }
                    if tag.as_str() == "exm" {
                        let new_phrase = DictionaryPhrase::new(tag.clone());
                        phrase = Some(new_phrase);
                    }
                    let attrs = e.attributes().map(|attr| {
                        if let Ok(attr) = attr {
                            String::from_utf8(attr.value.to_vec()).unwrap()
                        } else {
                            String::new()
                        }
                    });
                    current_tag = tag;
                    current_attrs = attrs.collect();
                }
                Ok(Event::Text(e)) => {
                    if let Some(entry) = word.as_mut() {
                        if current_tag == "k" {
                            entry.identifier = e.unescape().unwrap().to_string();
                            if let Some(phrase) = phrase.as_mut() {
                                phrase.example_for = entry.identifier.clone();
                            }
                        }
                        if current_tag == "dtrn" {
                            entry.translation.push(e.unescape().unwrap().to_string());
                        }
                        if current_tag == "ex" && current_attrs.contains(&"exm".to_string()) {
                            if let Some(phrase) = phrase.as_mut() {
                                phrase.identifier = e.unescape().unwrap().to_string();
                            }
                        }
                    }
                }
                Ok(Event::End(e)) => {
                    let tag = e.name();
                    let tag = String::from_utf8(tag.as_ref().to_vec()).unwrap();
                    if tag.as_str() == "ar" {
                        if let Some(new_word) = word {
                            words.push(new_word.clone());
                            entries.push(DictionaryEntry::Word(new_word));
                            word = None;
                        }
                        if let Some(new_phrase) = phrase {
                            phrases.push(new_phrase.clone());
                            entries.push(DictionaryEntry::Phrase(new_phrase));
                            phrase = None;
                        }
                    }
                    current_tag = String::new();
                    current_attrs = Vec::new();
                }
                _ => {}
            }
            buf.clear();
        }
        return Dictionary { entries, words, phrases, from, to };
    }
}