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() }
35 .ok_or_else(|| throw_named(ctx, "TypeError", "detached ArrayBuffer"))?;
36 return bytes
37 .get(offset..offset + len)
38 .map(<[u8]>::to_vec)
39 .ok_or_else(|| throw_named(ctx, "TypeError", "view out of bounds"));
40 }
41 }
42 Err(throw_named(
43 ctx,
44 "TypeError",
45 "expected an ArrayBuffer or ArrayBuffer view",
46 ))
47}
48
49fn decode(ctx: &Ctx<'_>, s: &str, encoding: &str) -> rquickjs::Result<Vec<u8>> {
51 match encoding {
52 "utf8" | "utf-8" => Ok(s.as_bytes().to_vec()),
53 "base64" => base64::engine::general_purpose::STANDARD
54 .decode(s)
55 .map_err(|e| throw_named(ctx, "TypeError", format!("invalid base64: {e}"))),
56 "hex" => (0..s.len() / 2)
57 .map(|i| u8::from_str_radix(&s[i * 2..i * 2 + 2], 16))
58 .collect::<Result<Vec<u8>, _>>()
59 .map_err(|e| throw_named(ctx, "TypeError", format!("invalid hex: {e}"))),
60 other => Err(throw_named(
61 ctx,
62 "TypeError",
63 format!("unsupported Buffer encoding {other:?} (utf8 | base64 | hex)"),
64 )),
65 }
66}
67
68pub fn value_to_bytes<'js>(
76 ctx: &Ctx<'js>,
77 value: &Value<'js>,
78 encoding: Option<&str>,
79) -> rquickjs::Result<Vec<u8>> {
80 if let Some(s) = value.as_string() {
81 return decode(ctx, &s.to_string()?, encoding.unwrap_or("utf8"));
82 }
83 if let Some(obj) = value.as_object() {
84 if let Some(arr) = obj.as_array() {
87 let mut out = Vec::with_capacity(arr.len());
88 for i in 0..arr.len() {
89 out.push(arr.get::<u8>(i)?);
90 }
91 return Ok(out);
92 }
93 }
94 buffer_source_bytes(ctx, value)
95}