use std::borrow::Cow;
use std::{slice, str, vec};
use super::validation::is_valid;
use crate::CaseFoldMap;
use crate::arguments::ArgumentScanner;
use crate::entity::{DecodedEntity, Entity};
use crate::{Error, ErrorKind};
pub trait Decoder {
fn get_entity(&self, name: &str) -> Option<&str>;
fn decode_entity(&self, name: &str) -> crate::Result<DecodedEntity<'_>> {
let (start, radix) = match name.as_bytes() {
[b'#', b'x', ..] => (2, 16),
[b'#', ..] => (1, 10),
_ => {
return match self.get_entity(name) {
Some(entity) => Ok(entity.into()),
None if is_valid(name) => Err(Error::new(name, ErrorKind::UnknownEntity)),
None => Err(Error::new(name, ErrorKind::InvalidEntityName)),
};
}
};
let Ok(code) = u32::from_str_radix(&name[start..], radix) else {
return Err(Error::new(name, ErrorKind::InvalidEntityNumber));
};
match char::from_u32(code) {
Some('\0'..='\x08' | '\x0a'..='\x1f' | '\x7f'..='\u{9f}') | None => {
Ok(DecodedEntity::default())
}
Some(c) => Ok(c.into()),
}
}
fn decode_string<'a>(&self, mut s: &'a str) -> crate::Result<Cow<'a, str>> {
let mut res = String::new();
while let Some((before, rest)) = s.split_once('&') {
if !before.is_empty() {
res.push_str(before);
}
let Some((entity, after)) = rest.split_once(';') else {
return Err(Error::new(
format!("&{rest}"),
ErrorKind::NoClosingSemicolon,
));
};
self.decode_entity(entity)?.push_to(&mut res);
s = after;
}
if res.is_empty() {
return Ok(Cow::Borrowed(s));
}
if !s.is_empty() {
res.push_str(s);
}
Ok(Cow::Owned(res))
}
}
impl<D: Decoder> Decoder for &D {
fn get_entity(&self, name: &str) -> Option<&str> {
D::get_entity(self, name)
}
fn decode_entity(&self, entity: &str) -> crate::Result<DecodedEntity<'_>> {
D::decode_entity(self, entity)
}
}
impl Decoder for () {
fn get_entity(&self, name: &str) -> Option<&str> {
Entity::global(name)
}
}
#[derive(Clone)]
pub(crate) struct Scan<'a, S: AsRef<str>> {
positional: slice::Iter<'a, S>,
named: &'a CaseFoldMap<'a, S>,
}
impl<'a, S: AsRef<str>> Scan<'a, S> {
pub fn new(positional: &'a [S], named: &'a CaseFoldMap<'a, S>) -> Self {
Self {
positional: positional.iter(),
named,
}
}
pub fn with_decoder<D: Decoder>(self, decoder: D) -> DecodeScan<'a, D, S> {
DecodeScan {
decoder,
inner: self,
}
}
}
impl<'a, S: AsRef<str>> ArgumentScanner<'a> for Scan<'a, S> {
type Raw = &'a S;
type Decoded = &'a S;
fn decode(&self, output: Self::Raw) -> crate::Result<Self::Raw> {
Ok(output)
}
fn raw_get_named(&mut self, name: &str) -> Option<Self::Raw> {
self.named.get(name)
}
fn raw_get_next(&mut self) -> Option<Self::Raw> {
self.positional.next()
}
}
#[derive(Clone)]
pub(crate) struct OwnedScan<'a> {
positional: vec::IntoIter<&'a str>,
named: CaseFoldMap<'a, &'a str>,
}
impl<'a> OwnedScan<'a> {
pub fn new(positional: Vec<&'a str>, named: CaseFoldMap<'a, &'a str>) -> Self {
Self {
positional: positional.into_iter(),
named,
}
}
pub fn with_decoder<D: Decoder>(self, decoder: D) -> OwnedDecodeScan<'a, D> {
OwnedDecodeScan {
decoder,
inner: self,
}
}
}
impl<'a> ArgumentScanner<'a> for OwnedScan<'a> {
type Raw = &'a str;
type Decoded = &'a str;
fn decode(&self, output: Self::Raw) -> crate::Result<Self::Raw> {
Ok(output)
}
fn raw_get_named(&mut self, name: &str) -> Option<Self::Raw> {
self.named.remove(name)
}
fn raw_get_next(&mut self) -> Option<Self::Raw> {
self.positional.next()
}
}
#[derive(Clone)]
pub(crate) struct DecodeScan<'a, D: Decoder, S: AsRef<str>> {
decoder: D,
inner: Scan<'a, S>,
}
impl<'a, D: Decoder, S: AsRef<str>> ArgumentScanner<'a> for DecodeScan<'a, D, S> {
type Raw = &'a S;
type Decoded = Cow<'a, str>;
fn decode(&self, output: Self::Raw) -> crate::Result<Cow<'a, str>> {
self.decoder.decode_string(output.as_ref())
}
fn raw_get_named(&mut self, name: &str) -> Option<Self::Raw> {
self.inner.raw_get_named(name)
}
fn raw_get_next(&mut self) -> Option<Self::Raw> {
self.inner.raw_get_next()
}
}
#[derive(Clone)]
pub(crate) struct OwnedDecodeScan<'a, D: Decoder> {
decoder: D,
inner: OwnedScan<'a>,
}
impl<'a, D: Decoder> ArgumentScanner<'a> for OwnedDecodeScan<'a, D> {
type Raw = &'a str;
type Decoded = Cow<'a, str>;
fn decode(&self, output: Self::Raw) -> crate::Result<Cow<'a, str>> {
self.decoder.decode_string(output.as_ref())
}
fn raw_get_named(&mut self, name: &str) -> Option<Self::Raw> {
self.inner.raw_get_named(name)
}
fn raw_get_next(&mut self) -> Option<Self::Raw> {
self.inner.raw_get_next()
}
}