Skip to main content

static_lang_word_lists/
metadata.rs

1use std::{borrow::Cow, fs, path::Path};
2
3use serde::Deserialize;
4
5use crate::WordListError;
6
7/// Metadata about a [`WordList`](crate::WordList).
8///
9/// If you don't want to mess around with the 🐄s, convenience methods are
10/// provided for reading fields:
11/// - [`WordListMetadata::name`]
12/// - [`WordListMetadata::script`]
13/// - [`WordListMetadata::language`]
14#[derive(Debug, Clone, Eq, PartialEq, Hash, Deserialize)]
15#[serde(deny_unknown_fields)]
16pub struct WordListMetadata {
17    /// The cosmetic name for the word list
18    pub name: Cow<'static, str>,
19    /// The script of the word list, if known.
20    ///
21    /// The script is expected to be an [ISO 15924](https://en.wikipedia.org/wiki/ISO_15924)
22    /// four-letter capitalised code.
23    pub script: Option<Cow<'static, str>>,
24    /// The language of the word list, if known.
25    ///
26    /// The language is expected to be an [ISO 639-1](https://en.wikipedia.org/wiki/ISO_639-1)
27    /// two-letter code.
28    pub language: Option<Cow<'static, str>>,
29}
30
31impl WordListMetadata {
32    // Used by word_list!
33    #[must_use]
34    pub(crate) const fn new(
35        name: &'static str,
36        script: Option<&'static str>,
37        language: Option<&'static str>,
38    ) -> Self {
39        // Can't use Option::map in const context
40        let script = match script {
41            Some(script) => Some(Cow::Borrowed(script)),
42            None => None,
43        };
44        let language = match language {
45            Some(language) => Some(Cow::Borrowed(language)),
46            None => None,
47        };
48        WordListMetadata {
49            name: Cow::Borrowed(name),
50            script,
51            language,
52        }
53    }
54
55    /// Load metadata from an on-disk TOML file
56    #[allow(clippy::result_large_err)]
57    pub fn load(
58        metadata_path: impl AsRef<Path>,
59    ) -> Result<Self, WordListError> {
60        let path = metadata_path.as_ref();
61        let metadata_content = fs::read_to_string(path).map_err(|io_err| {
62            WordListError::FailedToRead(path.to_owned(), io_err)
63        })?;
64        let metadata: WordListMetadata = toml::from_str(&metadata_content)
65            .map_err(|json_err| {
66                WordListError::MetadataError(path.to_owned(), json_err)
67            })?;
68        Ok(metadata)
69    }
70
71    pub(crate) fn new_from_name(name: impl Into<String>) -> Self {
72        WordListMetadata {
73            name: Cow::Owned(name.into()),
74            script: None,
75            language: None,
76        }
77    }
78
79    /// Get the name of the word list.
80    #[inline]
81    #[must_use]
82    pub fn name(&self) -> &str {
83        self.name.as_ref()
84    }
85
86    /// Get the script of the word list, if known.
87    ///
88    /// The script is expected to be an [ISO 15924](https://en.wikipedia.org/wiki/ISO_15924)
89    /// four-letter capitalised code, but this is only guaranteed for built-in
90    /// word lists.
91    #[inline]
92    #[must_use]
93    pub fn script(&self) -> Option<&str> {
94        self.script.as_deref()
95    }
96
97    /// Get the language of the word list, if known.
98    ///
99    /// The language is expected to be an [ISO 639-1](https://en.wikipedia.org/wiki/ISO_639-1)
100    /// two-letter code, but this is only guaranteed for built-in word lists.
101    #[inline]
102    #[must_use]
103    pub fn language(&self) -> Option<&str> {
104        self.language.as_deref()
105    }
106}
107
108impl<S> From<S> for WordListMetadata
109where
110    S: Into<Cow<'static, str>>,
111{
112    fn from(word_list_name: S) -> Self {
113        WordListMetadata {
114            name: word_list_name.into(),
115            script: None,
116            language: None,
117        }
118    }
119}