use base64::prelude::*;
use rune::alloc::fmt::TryWrite;
use rune::alloc::{String, Vec};
use rune::runtime::Bytes;
use rune::runtime::{Formatter, VmResult};
use rune::{vm_panic, ContextError, Module};
#[rune::module(::base64)]
pub fn module(_stdio: bool) -> Result<Module, ContextError> {
let mut module = Module::from_meta(self::module_meta)?;
module.ty::<DecodeError>()?;
module.function_meta(decode)?;
module.function_meta(encode)?;
Ok(module)
}
#[rune::function(vm_result)]
fn decode(inp: &str) -> Result<Bytes, DecodeError> {
let decoded_size = base64::decoded_len_estimate(inp.len());
let mut v = Vec::new();
v.try_resize(decoded_size, 0).vm?;
let len = BASE64_STANDARD.decode_slice(inp, &mut v)?;
v.truncate(len);
Ok(Bytes::from_vec(v))
}
#[rune::function(vm_result)]
fn encode(bytes: &[u8]) -> String {
let Some(encoded_size) = base64::encoded_len(bytes.len(), true) else {
vm_panic!("encoded input length overflows usize");
};
let mut buf = Vec::new();
buf.try_resize(encoded_size, 0).vm?;
if let Err(e) = BASE64_STANDARD.encode_slice(bytes, &mut buf) {
vm_panic!(e);
}
let string = match String::from_utf8(buf) {
Ok(s) => s,
Err(e) => vm_panic!(e),
};
string
}
#[derive(Debug, rune::Any)]
#[rune(item = ::base64)]
#[allow(dead_code)]
pub struct DecodeError {
inner: base64::DecodeSliceError,
}
impl From<base64::DecodeSliceError> for DecodeError {
fn from(inner: base64::DecodeSliceError) -> Self {
Self { inner }
}
}
impl DecodeError {
#[rune::function(instance, protocol = DISPLAY_FMT)]
fn display_fmt(&self, f: &mut Formatter) -> VmResult<()> {
rune::vm_write!(f, "{}", self.inner)
}
}