use crate::{Result, SourceMapError};
const BASE64_CHARS: &[u8; 64] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
const BASE64_DECODE: [i8; 256] = {
let mut table = [-1i8; 256];
let mut i = 0;
while i < 64 {
table[BASE64_CHARS[i] as usize] = i as i8;
i += 1;
}
table
};
const VLQ_CONTINUATION_BIT: u8 = 0b100000;
const VLQ_BASE_MASK: u8 = 0b011111;
pub fn vlq_encode(value: i32) -> String {
let mut result = String::new();
let mut value = if value < 0 { ((-value) << 1) + 1 } else { value << 1 };
loop {
let mut digit = (value & VLQ_BASE_MASK as i32) as u8;
value >>= 5;
if value > 0 {
digit |= VLQ_CONTINUATION_BIT;
}
result.push(BASE64_CHARS[digit as usize] as char);
if value == 0 {
break;
}
}
result
}
pub fn vlq_decode(s: &str) -> Result<(i32, usize)> {
vlq_decode_from_slice(s.as_bytes())
}
pub fn vlq_decode_from_slice(bytes: &[u8]) -> Result<(i32, usize)> {
let mut result: i32 = 0;
let mut shift: u32 = 0;
let mut count = 0;
for &byte in bytes {
count += 1;
let decoded = BASE64_DECODE[byte as usize];
if decoded < 0 {
return Err(SourceMapError::invalid_vlq(count - 1, format!("Invalid Base64 character: '{}'", byte as char)));
}
let decoded = decoded as u8;
result |= ((decoded & VLQ_BASE_MASK) as i32) << shift;
shift += 5;
if decoded & VLQ_CONTINUATION_BIT == 0 {
break;
}
}
let is_negative = result & 1 != 0;
result >>= 1;
if is_negative {
result = -result;
}
Ok((result, count))
}
pub fn vlq_encode_many(values: &[i32]) -> String {
values.iter().map(|v| vlq_encode(*v)).collect()
}
pub fn vlq_decode_many(s: &str) -> Result<Vec<i32>> {
let bytes = s.as_bytes();
let mut pos = 0;
let mut result = Vec::new();
while pos < bytes.len() {
let (value, consumed) = vlq_decode_from_slice(&bytes[pos..])?;
result.push(value);
pos += consumed;
}
Ok(result)
}