use crate::{
Charset,
CharsetCodec,
CharsetDecodeError,
CharsetDecodeErrorKind,
CharsetDecodeResult,
CharsetEncodeError,
CharsetEncodeErrorKind,
CharsetEncodeProbe,
CharsetEncodeResult,
Unicode,
};
use qubit_codec::Codec;
#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
pub struct Latin1Codec;
impl Latin1Codec {
#[must_use]
#[inline(always)]
pub const fn charset(self) -> Charset {
Charset::ISO_8859_1
}
}
impl CharsetCodec for Latin1Codec {
#[inline(always)]
fn charset(&self) -> Charset {
Charset::ISO_8859_1
}
}
impl CharsetEncodeProbe for Latin1Codec {
#[inline]
fn encode_len(&self, ch: char, index: usize) -> CharsetEncodeResult<usize> {
let value = ch as u32;
if value > Unicode::LATIN1_MAX {
let kind = CharsetEncodeErrorKind::UnmappableCharacter { value };
return Err(CharsetEncodeError::new(
Charset::ISO_8859_1,
kind,
index,
));
}
Ok(1)
}
}
unsafe impl Codec for Latin1Codec {
type Value = char;
type Unit = u8;
type DecodeError = CharsetDecodeError;
type EncodeError = CharsetEncodeError;
#[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 {
core::num::NonZeroUsize::MIN
}
#[inline]
unsafe fn decode_unchecked(
&self,
input: &[u8],
index: usize,
) -> CharsetDecodeResult<(char, core::num::NonZeroUsize)> {
if index > input.len() {
let kind = CharsetDecodeErrorKind::InvalidInputIndex {
input_len: input.len(),
};
return Err(CharsetDecodeError::new(
Charset::ISO_8859_1,
kind,
index,
));
}
if index == input.len() {
let kind = CharsetDecodeErrorKind::IncompleteSequence {
required: 1,
available: 0,
};
return Err(CharsetDecodeError::new(
Charset::ISO_8859_1,
kind,
index,
));
}
let value = input[index] as u32;
debug_assert!(index < input.len());
Ok((
Unicode::to_char(value)
.expect("valid Latin-1 byte decodes to Unicode scalar"),
core::num::NonZeroUsize::MIN,
))
}
#[inline]
unsafe fn encode_unchecked(
&self,
ch: &char,
output: &mut [u8],
index: usize,
) -> CharsetEncodeResult<usize> {
let value = *ch as u32;
if value > Unicode::LATIN1_MAX {
let kind = CharsetEncodeErrorKind::UnmappableCharacter { value };
return Err(CharsetEncodeError::new(
Charset::ISO_8859_1,
kind,
index,
));
}
if index >= output.len() {
let kind = CharsetEncodeErrorKind::BufferTooSmall {
required: required_index(index, 1),
available: 0,
};
return Err(CharsetEncodeError::new(
Charset::ISO_8859_1,
kind,
index,
));
}
output[index] = value as u8;
Ok(1)
}
}
#[inline(always)]
const fn required_index(index: usize, required_units: usize) -> usize {
match index.checked_add(required_units) {
Some(required) => required,
None => usize::MAX,
}
}