use core::{
fmt,
hash::{
Hash,
Hasher,
},
};
use crate::ByteOrder;
#[derive(Clone, Copy, Debug)]
pub struct Charset {
id: &'static str,
name: &'static str,
aliases: &'static [&'static str],
}
impl Charset {
pub const ASCII: Self = Self::new("ascii", "ASCII", &["us-ascii"]);
pub const ISO_8859_1: Self = Self::new(
"iso-8859-1",
"ISO-8859-1",
&[
"latin1",
"latin-1",
"iso8859-1",
"csisolatin1",
"iso_8859-1",
],
);
pub const UTF_8: Self = Self::new("utf-8", "UTF-8", &["utf8"]);
pub const UTF_16: Self = Self::new("utf-16", "UTF-16", &["utf16"]);
pub const UTF_16LE: Self = Self::new(
"utf-16le",
"UTF-16LE",
&["utf16le", "utf16_le", "utf_16_le"],
);
pub const UTF_16BE: Self = Self::new(
"utf-16be",
"UTF-16BE",
&["utf16be", "utf16_be", "utf_16_be"],
);
pub const UTF_32: Self = Self::new("utf-32", "UTF-32", &["utf32"]);
pub const UTF_32LE: Self = Self::new(
"utf-32le",
"UTF-32LE",
&["utf32le", "utf32_le", "utf_32_le"],
);
pub const UTF_32BE: Self = Self::new(
"utf-32be",
"UTF-32BE",
&["utf32be", "utf32_be", "utf_32_be"],
);
pub const BUILTINS: &'static [Self] = &[
Self::ASCII,
Self::ISO_8859_1,
Self::UTF_8,
Self::UTF_16,
Self::UTF_16LE,
Self::UTF_16BE,
Self::UTF_32,
Self::UTF_32LE,
Self::UTF_32BE,
];
#[inline(always)]
pub const fn new(
id: &'static str,
name: &'static str,
aliases: &'static [&'static str],
) -> Self {
Self { id, name, aliases }
}
pub fn from_label(label: &str) -> Option<Self> {
let label = label.trim_ascii();
Self::BUILTINS
.iter()
.copied()
.find(|charset| charset.matches_label(label))
}
#[inline(always)]
pub const fn id(self) -> &'static str {
self.id
}
#[inline(always)]
pub const fn name(self) -> &'static str {
self.name
}
#[inline(always)]
pub const fn aliases(self) -> &'static [&'static str] {
self.aliases
}
#[inline(always)]
pub const fn from_utf16_byte_order(byte_order: ByteOrder) -> Self {
match byte_order {
ByteOrder::LittleEndian => Self::UTF_16LE,
ByteOrder::BigEndian => Self::UTF_16BE,
}
}
#[inline(always)]
pub const fn from_utf32_byte_order(byte_order: ByteOrder) -> Self {
match byte_order {
ByteOrder::LittleEndian => Self::UTF_32LE,
ByteOrder::BigEndian => Self::UTF_32BE,
}
}
#[inline]
pub fn byte_order(self) -> Option<ByteOrder> {
if self == Self::UTF_16LE || self == Self::UTF_32LE {
Some(ByteOrder::LittleEndian)
} else if self == Self::UTF_16BE || self == Self::UTF_32BE {
Some(ByteOrder::BigEndian)
} else {
None
}
}
pub fn matches_label(self, label: &str) -> bool {
if label.eq_ignore_ascii_case(self.id)
|| label.eq_ignore_ascii_case(self.name)
{
return true;
}
self.aliases
.iter()
.any(|alias| label.eq_ignore_ascii_case(alias))
}
}
impl PartialEq for Charset {
#[inline(always)]
fn eq(&self, other: &Self) -> bool {
self.id == other.id
}
}
impl Eq for Charset {}
impl Hash for Charset {
#[inline(always)]
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
self.id.hash(state);
}
}
impl fmt::Display for Charset {
#[inline(always)]
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str(self.name())
}
}