use crate::percent_codec::{
percent_decode_byte,
percent_decode_bytes,
percent_encode_byte,
percent_encode_bytes,
};
use crate::{
Codec,
MiscCodecError,
MiscCodecResult,
ValueDecoder,
ValueEncoder,
};
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct FormUrlencodedCodec;
impl FormUrlencodedCodec {
#[inline]
pub fn new() -> Self {
Self
}
#[inline]
pub fn encode(&self, text: &str) -> String {
percent_encode_bytes(text.as_bytes(), true)
}
#[inline]
pub fn decode(&self, text: &str) -> MiscCodecResult<String> {
String::from_utf8(percent_decode_bytes(text, true)?)
.map_err(MiscCodecError::from)
}
}
impl ValueEncoder<str> for FormUrlencodedCodec {
type Error = MiscCodecError;
type Output = String;
#[inline]
fn encode(&self, input: &str) -> Result<Self::Output, Self::Error> {
Ok(FormUrlencodedCodec::encode(self, input))
}
}
impl ValueDecoder<str> for FormUrlencodedCodec {
type Error = MiscCodecError;
type Output = String;
#[inline]
fn decode(&self, input: &str) -> Result<Self::Output, Self::Error> {
FormUrlencodedCodec::decode(self, input)
}
}
unsafe impl Codec for FormUrlencodedCodec {
type Value = u8;
type Unit = u8;
type DecodeError = MiscCodecError;
type EncodeError = MiscCodecError;
#[inline(always)]
fn min_units_per_value(&self) -> core::num::NonZeroUsize {
core::num::NonZeroUsize::MIN
}
#[inline(always)]
fn max_units_per_value(&self) -> core::num::NonZeroUsize {
unsafe { core::num::NonZeroUsize::new_unchecked(3) }
}
#[inline]
unsafe fn decode_unchecked(
&self,
input: &[u8],
index: usize,
) -> Result<(u8, core::num::NonZeroUsize), Self::DecodeError> {
debug_assert!(index < input.len());
let (value, consumed) = percent_decode_byte(input, index, true)?;
debug_assert!(consumed > 0);
let consumed =
unsafe { core::num::NonZeroUsize::new_unchecked(consumed) };
Ok((value, consumed))
}
#[inline]
unsafe fn encode_unchecked(
&self,
value: &u8,
output: &mut [u8],
index: usize,
) -> Result<usize, Self::EncodeError> {
debug_assert!(
index
+ if *value == b' '
|| value.is_ascii_alphanumeric()
|| matches!(*value, b'-' | b'.' | b'_' | b'~')
{
1
} else {
3
}
<= output.len()
);
Ok(percent_encode_byte(*value, output, index, true))
}
}