pub(crate) fn small_uint_literal(canonical: &str) -> Option<u8> {
if !is_normalized_unsigned(canonical) {
return None;
}
match canonical.parse::<u16>() {
Ok(value) if value < 16 => Some(value as u8),
_ => None,
}
}
pub(crate) fn integer_to_bits(canonical: &str) -> Option<(bool, Vec<bool>)> {
let (negative, digits) = match canonical.strip_prefix('-') {
Some(rest) => (true, rest),
None => (false, canonical),
};
if !is_normalized_unsigned(digits) {
return None;
}
if digits == "0" {
return if negative {
None
} else {
Some((false, Vec::new()))
};
}
let mut decimal: Vec<u8> = digits.bytes().map(|b| b - b'0').collect();
let mut bits_lsb = Vec::new();
while !decimal.iter().all(|&d| d == 0) {
let remainder = divmod2(&mut decimal);
bits_lsb.push(remainder == 1);
}
bits_lsb.reverse();
Some((negative, bits_lsb))
}
pub(crate) fn bits_to_integer(negative: bool, bits: &[bool]) -> String {
let mut decimal = vec![0u8];
for &bit in bits {
mul2_add(&mut decimal, u8::from(bit));
}
let text: String = decimal.iter().map(|&d| (d + b'0') as char).collect();
if text == "0" {
return text;
}
if negative { format!("-{text}") } else { text }
}
fn is_normalized_unsigned(text: &str) -> bool {
if text.is_empty() || !text.bytes().all(|b| b.is_ascii_digit()) {
return false;
}
!(text.len() > 1 && text.starts_with('0'))
}
fn divmod2(decimal: &mut [u8]) -> u8 {
let mut carry = 0u8;
for digit in decimal.iter_mut() {
let current = carry * 10 + *digit;
*digit = current / 2;
carry = current % 2;
}
carry
}
fn mul2_add(decimal: &mut Vec<u8>, add: u8) {
let mut carry = add;
for digit in decimal.iter_mut().rev() {
let current = *digit * 2 + carry;
*digit = current % 10;
carry = current / 10;
}
if carry > 0 {
decimal.insert(0, carry);
}
while decimal.len() > 1 && decimal[0] == 0 {
decimal.remove(0);
}
}