use qubit_io::{
BigEndian,
BinaryCodec,
ByteOrder,
LittleEndian,
};
use crate::{
Charset,
CharsetDecodeError,
CharsetDecodeErrorKind,
CharsetDecodeResult,
CharsetEncodeError,
CharsetEncodeErrorKind,
CharsetEncodeResult,
DecodeStatus,
Unicode,
};
pub(crate) fn decode_units_prefix(input: &[u32], index: usize) -> CharsetDecodeResult<DecodeStatus> {
if index > input.len() {
let kind = CharsetDecodeErrorKind::MalformedSequence { value: None };
return Err(CharsetDecodeError::new(Charset::UTF_32, kind, index));
}
if index == input.len() {
return Ok(DecodeStatus::NeedMore {
required: index + 1,
available: 0,
});
}
match Unicode::to_char(input[index]) {
Some(ch) => Ok(DecodeStatus::Complete { value: ch, consumed: 1 }),
None => {
let kind = CharsetDecodeErrorKind::InvalidCodePoint { value: input[index] };
Err(CharsetDecodeError::new(Charset::UTF_32, kind, index))
}
}
}
pub(crate) fn encode_units_char(ch: char, output: &mut [u32], index: usize) -> CharsetEncodeResult<usize> {
if index >= output.len() {
let kind = CharsetEncodeErrorKind::BufferTooSmall {
required: index + 1,
available: 0,
};
return Err(CharsetEncodeError::new(Charset::UTF_32, kind, index));
}
output[index] = ch as u32;
Ok(1)
}
pub(crate) fn decode_bytes_prefix(
input: &[u8],
index: usize,
byte_order: ByteOrder,
) -> CharsetDecodeResult<DecodeStatus> {
let charset = Charset::from_utf32_byte_order(byte_order);
if index > input.len() {
let kind = CharsetDecodeErrorKind::MalformedSequence { value: None };
return Err(CharsetDecodeError::new(charset, kind, index));
}
let available = input.len() - index;
if available < 4 {
return Ok(DecodeStatus::NeedMore {
required: index.saturating_add(4),
available,
});
}
let unit = match byte_order {
ByteOrder::BigEndian => unsafe { BinaryCodec::<u32, BigEndian>::read_unchecked(input, index) },
ByteOrder::LittleEndian => unsafe { BinaryCodec::<u32, LittleEndian>::read_unchecked(input, index) },
};
match Unicode::to_char(unit) {
Some(ch) => Ok(DecodeStatus::Complete { value: ch, consumed: 4 }),
None => {
let kind = CharsetDecodeErrorKind::InvalidCodePoint { value: unit };
Err(CharsetDecodeError::new(charset, kind, index))
}
}
}
pub(crate) fn encode_bytes_char(
ch: char,
output: &mut [u8],
byte_order: ByteOrder,
index: usize,
) -> CharsetEncodeResult<usize> {
let charset = Charset::from_utf32_byte_order(byte_order);
if index > output.len() {
let kind = CharsetEncodeErrorKind::BufferTooSmall {
required: index + 4,
available: 0,
};
return Err(CharsetEncodeError::new(charset, kind, index));
}
let required = 4;
let available = output.len() - index;
if available < required {
let kind = CharsetEncodeErrorKind::BufferTooSmall {
required: index + required,
available,
};
return Err(CharsetEncodeError::new(charset, kind, index));
}
match byte_order {
ByteOrder::BigEndian => unsafe { BinaryCodec::<u32, BigEndian>::write_unchecked(output, index, ch as u32) },
ByteOrder::LittleEndian => unsafe {
BinaryCodec::<u32, LittleEndian>::write_unchecked(output, index, ch as u32)
},
}
Ok(4)
}