ferrijs_std/node/
bytes.rs1use base64::Engine as _;
10use rquickjs::{ArrayBuffer, Ctx, Value};
11
12use super::throw_named;
13
14pub fn buffer_source_bytes(ctx: &Ctx<'_>, value: &Value<'_>) -> rquickjs::Result<Vec<u8>> {
21 if let Some(ab) = ArrayBuffer::from_value(value.clone()) {
22 return unsafe { ab.as_bytes() }
24 .map(<[u8]>::to_vec)
25 .ok_or_else(|| throw_named(ctx, "TypeError", "detached ArrayBuffer"));
26 }
27 if let Some(obj) = value.as_object() {
28 let buffer: rquickjs::Result<ArrayBuffer<'_>> = obj.get("buffer");
29 if let Ok(ab) = buffer {
30 let offset: usize = obj.get("byteOffset")?;
31 let len: usize = obj.get("byteLength")?;
32 let bytes = unsafe { ab.as_bytes() }
34 .ok_or_else(|| throw_named(ctx, "TypeError", "detached ArrayBuffer"))?;
35 return bytes
36 .get(offset..offset + len)
37 .map(<[u8]>::to_vec)
38 .ok_or_else(|| throw_named(ctx, "TypeError", "view out of bounds"));
39 }
40 }
41 Err(throw_named(
42 ctx,
43 "TypeError",
44 "expected an ArrayBuffer or ArrayBuffer view",
45 ))
46}
47
48fn decode(ctx: &Ctx<'_>, s: &str, encoding: &str) -> rquickjs::Result<Vec<u8>> {
50 match encoding {
51 "utf8" | "utf-8" => Ok(s.as_bytes().to_vec()),
52 "base64" => base64::engine::general_purpose::STANDARD
53 .decode(s)
54 .map_err(|e| throw_named(ctx, "TypeError", format!("invalid base64: {e}"))),
55 "hex" => (0..s.len() / 2)
56 .map(|i| u8::from_str_radix(&s[i * 2..i * 2 + 2], 16))
57 .collect::<Result<Vec<u8>, _>>()
58 .map_err(|e| throw_named(ctx, "TypeError", format!("invalid hex: {e}"))),
59 other => Err(throw_named(
60 ctx,
61 "TypeError",
62 format!("unsupported Buffer encoding {other:?} (utf8 | base64 | hex)"),
63 )),
64 }
65}
66
67pub fn value_to_bytes<'js>(
75 ctx: &Ctx<'js>,
76 value: &Value<'js>,
77 encoding: Option<&str>,
78) -> rquickjs::Result<Vec<u8>> {
79 if let Some(s) = value.as_string() {
80 return decode(ctx, &s.to_string()?, encoding.unwrap_or("utf8"));
81 }
82 if let Some(obj) = value.as_object() {
83 if let Some(arr) = obj.as_array() {
86 let mut out = Vec::with_capacity(arr.len());
87 for i in 0..arr.len() {
88 out.push(arr.get::<u8>(i)?);
89 }
90 return Ok(out);
91 }
92 }
93 buffer_source_bytes(ctx, value)
94}