1use base64::prelude::*;
2use rune::alloc::fmt::TryWrite;
3use rune::alloc::{String, Vec};
4use rune::runtime::Bytes;
5use rune::runtime::{Formatter, VmResult};
6use rune::{vm_panic, ContextError, Module};
7
8#[rune::module(::base64)]
9pub fn module(_stdio: bool) -> Result<Module, ContextError> {
21 let mut module = Module::from_meta(self::module_meta)?;
22
23 module.ty::<DecodeError>()?;
24
25 module.function_meta(decode)?;
26 module.function_meta(encode)?;
27 Ok(module)
28}
29
30#[rune::function(vm_result)]
38fn decode(inp: &str) -> Result<Bytes, DecodeError> {
39 let decoded_size = base64::decoded_len_estimate(inp.len());
41
42 let mut v = Vec::new();
44 v.try_resize(decoded_size, 0).vm?;
45
46 let len = BASE64_STANDARD.decode_slice(inp, &mut v)?;
48 v.truncate(len);
49 Ok(Bytes::from_vec(v))
50}
51
52#[rune::function(vm_result)]
60fn encode(bytes: &[u8]) -> String {
61 let Some(encoded_size) = base64::encoded_len(bytes.len(), true) else {
62 vm_panic!("encoded input length overflows usize");
63 };
64
65 let mut buf = Vec::new();
66 buf.try_resize(encoded_size, 0).vm?;
67
68 if let Err(e) = BASE64_STANDARD.encode_slice(bytes, &mut buf) {
70 vm_panic!(e);
71 }
72
73 let string = match String::from_utf8(buf) {
75 Ok(s) => s,
76 Err(e) => vm_panic!(e),
77 };
78
79 string
80}
81
82#[derive(Debug, rune::Any)]
84#[rune(item = ::base64)]
85#[allow(dead_code)]
86pub struct DecodeError {
87 inner: base64::DecodeSliceError,
88}
89
90impl From<base64::DecodeSliceError> for DecodeError {
91 fn from(inner: base64::DecodeSliceError) -> Self {
92 Self { inner }
93 }
94}
95
96impl DecodeError {
97 #[rune::function(instance, protocol = DISPLAY_FMT)]
98 fn display_fmt(&self, f: &mut Formatter) -> VmResult<()> {
99 rune::vm_write!(f, "{}", self.inner)
100 }
101}