Skip to main content

ferrijs_std/buffer/
array_buffer_view.rs

1// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3#![allow(clippy::uninlined_format_args)]
4
5use std::ptr::NonNull;
6
7use rquickjs::{ArrayBuffer, Ctx, Error, FromJs, IntoJs, Object, Result, TypedArray, Value};
8
9use crate::buffer::Buffer;
10
11pub struct ArrayBufferView<'js> {
12    value: Value<'js>,
13    buffer: Option<RawArrayBuffer>,
14}
15
16struct RawArrayBuffer {
17    len: usize,
18    ptr: NonNull<u8>,
19}
20
21impl RawArrayBuffer {
22    pub fn new(len: usize, ptr: NonNull<u8>) -> Self {
23        Self { len, ptr }
24    }
25}
26
27impl<'js> IntoJs<'js> for ArrayBufferView<'js> {
28    fn into_js(self, _ctx: &Ctx<'js>) -> Result<Value<'js>> {
29        Ok(self.value)
30    }
31}
32
33impl<'js> FromJs<'js> for ArrayBufferView<'js> {
34    fn from_js(_ctx: &Ctx<'js>, value: Value<'js>) -> Result<Self> {
35        let ty_name = value.type_name();
36        let obj = Object::from_value(value.clone())
37            .map_err(|_| Error::new_from_js(ty_name, "ArrayBufferView"))?;
38
39        if let Some(array_buffer) = ArrayBuffer::from_object(obj.clone()) {
40            let buffer = array_buffer
41                .as_raw()
42                .map(|raw| RawArrayBuffer::new(raw.len(), raw.cast::<u8>()));
43            return Ok(ArrayBufferView { value, buffer });
44        }
45
46        if let Ok(typed_array) = TypedArray::<i8>::from_object(obj.clone()) {
47            let buffer = typed_array
48                .as_raw()
49                .map(|raw| RawArrayBuffer::new(raw.len(), raw.cast::<u8>()));
50            return Ok(ArrayBufferView { value, buffer });
51        }
52
53        if let Ok(typed_array) = TypedArray::<u8>::from_object(obj.clone()) {
54            let buffer = typed_array
55                .as_raw()
56                .map(|raw| RawArrayBuffer::new(raw.len(), raw.cast::<u8>()));
57            return Ok(ArrayBufferView { value, buffer });
58        }
59
60        if let Ok(typed_array) = TypedArray::<i16>::from_object(obj.clone()) {
61            let buffer = typed_array
62                .as_raw()
63                .map(|raw| RawArrayBuffer::new(raw.len(), raw.cast::<u8>()));
64            return Ok(ArrayBufferView { value, buffer });
65        }
66
67        if let Ok(typed_array) = TypedArray::<u16>::from_object(obj.clone()) {
68            let buffer = typed_array
69                .as_raw()
70                .map(|raw| RawArrayBuffer::new(raw.len(), raw.cast::<u8>()));
71            return Ok(ArrayBufferView { value, buffer });
72        }
73
74        if let Ok(typed_array) = TypedArray::<i32>::from_object(obj.clone()) {
75            let buffer = typed_array
76                .as_raw()
77                .map(|raw| RawArrayBuffer::new(raw.len(), raw.cast::<u8>()));
78            return Ok(ArrayBufferView { value, buffer });
79        }
80
81        if let Ok(typed_array) = TypedArray::<u32>::from_object(obj.clone()) {
82            let buffer = typed_array
83                .as_raw()
84                .map(|raw| RawArrayBuffer::new(raw.len(), raw.cast::<u8>()));
85            return Ok(ArrayBufferView { value, buffer });
86        }
87
88        if let Ok(typed_array) = TypedArray::<f32>::from_object(obj.clone()) {
89            let buffer = typed_array
90                .as_raw()
91                .map(|raw| RawArrayBuffer::new(raw.len(), raw.cast::<u8>()));
92            return Ok(ArrayBufferView { value, buffer });
93        }
94
95        if let Ok(typed_array) = TypedArray::<f64>::from_object(obj.clone()) {
96            let buffer = typed_array
97                .as_raw()
98                .map(|raw| RawArrayBuffer::new(raw.len(), raw.cast::<u8>()));
99            return Ok(ArrayBufferView { value, buffer });
100        }
101
102        if let Ok(typed_array) = TypedArray::<i64>::from_object(obj.clone()) {
103            let buffer = typed_array
104                .as_raw()
105                .map(|raw| RawArrayBuffer::new(raw.len(), raw.cast::<u8>()));
106            return Ok(ArrayBufferView { value, buffer });
107        }
108
109        if let Ok(typed_array) = TypedArray::<u64>::from_object(obj.clone()) {
110            let buffer = typed_array
111                .as_raw()
112                .map(|raw| RawArrayBuffer::new(raw.len(), raw.cast::<u8>()));
113            return Ok(ArrayBufferView { value, buffer });
114        }
115
116        if let Ok(array_buffer) = obj.get::<_, ArrayBuffer>("buffer") {
117            let buffer = array_buffer
118                .as_raw()
119                .map(|raw| RawArrayBuffer::new(raw.len(), raw.cast::<u8>()));
120            return Ok(ArrayBufferView { value, buffer });
121        }
122
123        Err(Error::new_from_js(ty_name, "ArrayBufferView"))
124    }
125}
126
127impl<'js> ArrayBufferView<'js> {
128    pub fn from_buffer(ctx: &Ctx<'js>, buffer: Buffer) -> Result<Self> {
129        let value = buffer.into_js(ctx)?;
130        Self::from_js(ctx, value)
131    }
132
133    pub fn len(&self) -> usize {
134        self.buffer.as_ref().map(|b| b.len).unwrap_or(0)
135    }
136
137    #[allow(dead_code)]
138    pub fn is_empty(&self) -> bool {
139        self.len() == 0
140    }
141
142    pub fn as_bytes(&self) -> Option<&[u8]> {
143        self.buffer
144            .as_ref()
145            .map(|b| unsafe { std::slice::from_raw_parts(b.ptr.as_ptr(), b.len) })
146    }
147
148    /// Mutable buffer for the view.
149    ///
150    /// # Safety
151    /// This is only safe if you have a lock on the runtime.
152    /// Do not pass it directly to other threads.
153    pub fn as_bytes_mut(&mut self) -> Option<&mut [u8]> {
154        self.buffer
155            .as_ref()
156            .map(|b| unsafe { std::slice::from_raw_parts_mut(b.ptr.as_ptr(), b.len) })
157    }
158}