diff options
Diffstat (limited to 'src/library/text/lang.rs')
| -rw-r--r-- | src/library/text/lang.rs | 55 |
1 files changed, 45 insertions, 10 deletions
diff --git a/src/library/text/lang.rs b/src/library/text/lang.rs index 343359d1..360827fa 100644 --- a/src/library/text/lang.rs +++ b/src/library/text/lang.rs @@ -1,24 +1,30 @@ use crate::eval::Value; use crate::geom::Dir; -/// A natural language. +/// A code for a natural language. #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] -pub struct Lang([u8; 2]); +pub struct Lang([u8; 3], u8); impl Lang { /// The code for the english language. - pub const ENGLISH: Self = Self(*b"en"); + pub const ENGLISH: Self = Self(*b"en ", 2); - /// Construct a language from a two-byte ISO 639-1 code. + /// Construct a language from a two- or three-byte ISO 639-1/2/3 code. pub fn from_str(iso: &str) -> Option<Self> { - let mut bytes: [u8; 2] = iso.as_bytes().try_into().ok()?; - bytes.make_ascii_lowercase(); - Some(Self(bytes)) + let len = iso.len(); + if matches!(len, 2 ..= 3) && iso.is_ascii() { + let mut bytes = [b' '; 3]; + bytes[.. len].copy_from_slice(iso.as_bytes()); + bytes.make_ascii_lowercase(); + Some(Self(bytes, len as u8)) + } else { + None + } } - /// Return the language code as a string slice. + /// Return the language code as an all lowercase string slice. pub fn as_str(&self) -> &str { - std::str::from_utf8(&self.0).unwrap_or_default() + std::str::from_utf8(&self.0[.. usize::from(self.1)]).unwrap_or_default() } /// The default direction for the language. @@ -35,5 +41,34 @@ castable! { Lang, Expected: "string", Value::Str(string) => Self::from_str(&string) - .ok_or("expected two letter language code")?, + .ok_or("expected two or three letter language code (ISO 639-1/2/3)")?, +} + +/// A code for a region somewhere in the world. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub struct Region([u8; 2]); + +impl Region { + /// Construct a region from its two-byte ISO 3166-1 alpha-2 code. + pub fn from_str(iso: &str) -> Option<Self> { + if iso.is_ascii() { + let mut bytes: [u8; 2] = iso.as_bytes().try_into().ok()?; + bytes.make_ascii_uppercase(); + Some(Self(bytes)) + } else { + None + } + } + + /// Return the region code as an all uppercase string slice. + pub fn as_str(&self) -> &str { + std::str::from_utf8(&self.0).unwrap_or_default() + } +} + +castable! { + Region, + Expected: "string", + Value::Str(string) => Self::from_str(&string) + .ok_or("expected two letter region code (ISO 3166-1 alpha-2)")?, } |
