///|
let base64_chars : String = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
///|
fn base64_value(ch : Char) -> Int? {
for i in 0.. Char {
base64_chars.unsafe_get(value).to_int().unsafe_to_char()
}
///|
/// Encode one signed integer using Source Map Base64 VLQ.
pub fn encode_vlq(value : Int) -> String {
let mut vlq = if value < 0 { ((0 - value) << 1) | 1 } else { value << 1 }
let mut out = ""
for ;; {
let mut digit = vlq & 31
vlq = vlq >> 5
if vlq != 0 {
digit = digit | 32
}
out = out + base64_char(digit).to_string()
if vlq == 0 {
break
}
}
out
}
///|
/// Decode all signed values in one mapping segment.
pub fn decode_vlq_values(encoded : String) -> Array[Int] raise SourceMapError {
let values : Array[Int] = Array::new()
let mut offset = 0
while offset < encoded.length() {
let mut result = 0
let mut shift = 0
let start = offset
for ;; {
if offset >= encoded.length() {
raise SourceMapError::At(start, "unterminated VLQ value")
}
let ch = encoded.unsafe_get(offset).to_int().unsafe_to_char()
let digit = match base64_value(ch) {
Some(value) => value
None =>
raise SourceMapError::At(
offset,
"invalid Base64 character '\{ch.to_string()}'",
)
}
offset += 1
result = result | ((digit & 31) << shift)
if (digit & 32) == 0 {
break
}
shift += 5
if shift > 30 {
raise SourceMapError::At(start, "VLQ value exceeds Int range")
}
}
let negative = (result & 1) == 1
let magnitude = result >> 1
values.push(if negative { 0 - magnitude } else { magnitude })
}
values
}
///|
/// Decode exactly one signed Base64 VLQ integer.
pub fn decode_vlq(encoded : String) -> Int raise SourceMapError {
let values = decode_vlq_values(encoded)
if values.length() != 1 {
raise SourceMapError::At(0, "expected exactly one VLQ value")
}
values[0]
}