use encoding_rs::GBK;
use std::str::FromStr;
use super::error::ParseError;
#[derive(Debug, Clone, Copy, Default, Eq, PartialEq)]
pub enum ParseMode {
#[default]
Strict,
Permissive,
}
impl ParseMode {
pub const fn as_str(self) -> &'static str {
match self {
Self::Strict => "strict",
Self::Permissive => "permissive",
}
}
pub(crate) const fn is_permissive(self) -> bool {
matches!(self, Self::Permissive)
}
}
impl FromStr for ParseMode {
type Err = ();
fn from_str(value: &str) -> Result<Self, Self::Err> {
match value {
"strict" => Ok(Self::Strict),
"permissive" => Ok(Self::Permissive),
_ => Err(()),
}
}
}
#[derive(Debug, Clone, Copy, Default, Eq, PartialEq)]
pub enum StringEncoding {
#[default]
Utf8,
Gbk,
}
impl StringEncoding {
pub const fn as_str(self) -> &'static str {
match self {
Self::Utf8 => "utf-8",
Self::Gbk => "gbk",
}
}
pub(crate) fn decode(
self,
offset: usize,
bytes: &[u8],
mode: StringDecodeMode,
) -> Result<String, ParseError> {
match self {
Self::Utf8 => {
match mode {
StringDecodeMode::Strict => std::str::from_utf8(bytes)
.map(str::to_owned)
.map_err(|_| ParseError::StringDecode {
offset,
encoding: self.as_str(),
}),
StringDecodeMode::Lossy => Ok(String::from_utf8_lossy(bytes).into_owned()),
}
}
Self::Gbk => {
let (value, _, had_errors) = GBK.decode(bytes);
if had_errors && matches!(mode, StringDecodeMode::Strict) {
return Err(ParseError::StringDecode {
offset,
encoding: self.as_str(),
});
}
Ok(value.into_owned())
}
}
}
}
impl FromStr for StringEncoding {
type Err = ();
fn from_str(value: &str) -> Result<Self, Self::Err> {
match value {
"utf8" | "utf-8" => Ok(Self::Utf8),
"gbk" => Ok(Self::Gbk),
_ => Err(()),
}
}
}
#[derive(Debug, Clone, Copy, Default, Eq, PartialEq)]
pub enum StringDecodeMode {
#[default]
Strict,
Lossy,
}
impl StringDecodeMode {
pub const fn as_str(self) -> &'static str {
match self {
Self::Strict => "strict",
Self::Lossy => "lossy",
}
}
}
impl FromStr for StringDecodeMode {
type Err = ();
fn from_str(value: &str) -> Result<Self, Self::Err> {
match value {
"strict" => Ok(Self::Strict),
"lossy" => Ok(Self::Lossy),
_ => Err(()),
}
}
}
#[derive(Debug, Clone, Copy, Default, Eq, PartialEq)]
pub struct ParseOptions {
pub mode: ParseMode,
pub string_encoding: StringEncoding,
pub string_decode_mode: StringDecodeMode,
}