use qubit_codec::ValueDecoder;
use crate::MiscCodecError;
use crate::MiscCodecResult;
use crate::internal::LiteralComponents;
#[must_use]
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct CIntegerLiteralCodec;
impl CIntegerLiteralCodec {
#[inline]
pub fn new() -> Self {
Self
}
#[inline]
pub fn decode(&self, text: &str) -> MiscCodecResult<u64> {
let (trimmed, trim_offset) = trim_with_offset(text);
if trimmed.is_empty() {
return Err(invalid_c_integer_input("expected at least one digit"));
}
let components = LiteralComponents::parse(trimmed, trim_offset)?;
validate_digits(components)?;
u64::from_str_radix(components.digits, components.radix).map_err(
|error| {
invalid_c_integer_input(&format!(
"integer literal is out of range: {error}"
))
},
)
}
}
impl ValueDecoder<str> for CIntegerLiteralCodec {
type Error = MiscCodecError;
type Output = u64;
#[inline]
fn decode(&mut self, input: &str) -> Result<Self::Output, Self::Error> {
CIntegerLiteralCodec::decode(self, input)
}
}
#[inline]
fn trim_with_offset(text: &str) -> (&str, usize) {
let trimmed_start = text.trim_start();
let start = text.len() - trimmed_start.len();
(trimmed_start.trim_end(), start)
}
fn validate_digits(components: LiteralComponents<'_>) -> MiscCodecResult<()> {
for (index, character) in components.digits.char_indices() {
if character.is_digit(components.radix) {
continue;
}
return Err(MiscCodecError::InvalidDigit {
radix: components.radix,
index: components.digits_offset + index,
character,
});
}
Ok(())
}
fn invalid_c_integer_input(reason: &str) -> MiscCodecError {
MiscCodecError::InvalidInput {
codec: "c-integer-literal",
reason: reason.to_owned(),
}
}