1use std::io;
2
3#[cfg(feature = "serde")]
4use serde::ser::{Serialize, Serializer};
5
6use crate::state::RawLua;
7use crate::types::ValueRef;
8
9#[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
15#[derive(Clone, Debug, PartialEq)]
16pub struct Buffer(pub(crate) ValueRef);
17
18#[cfg_attr(not(feature = "luau"), allow(unused))]
19impl Buffer {
20 pub fn to_vec(&self) -> Vec<u8> {
22 let lua = self.0.lua.lock();
23 self.as_slice(&lua).to_vec()
24 }
25
26 pub fn len(&self) -> usize {
28 let lua = self.0.lua.lock();
29 self.as_slice(&lua).len()
30 }
31
32 pub fn is_empty(&self) -> bool {
34 self.len() == 0
35 }
36
37 #[track_caller]
45 pub fn read_bytes<const N: usize>(&self, offset: usize) -> [u8; N] {
46 let lua = self.0.lua.lock();
47 let data = self.as_slice(&lua);
48 let mut bytes = [0u8; N];
49 bytes.copy_from_slice(&data[offset..offset + N]);
50 bytes
51 }
52
53 #[track_caller]
61 pub fn write_bytes(&self, offset: usize, bytes: &[u8]) {
62 let lua = self.0.lua.lock();
63 let data = self.as_slice_mut(&lua);
64 data[offset..offset + bytes.len()].copy_from_slice(bytes);
65 }
66
67 pub fn cursor(self) -> impl io::Read + io::Write + io::Seek {
72 BufferCursor(self, 0)
73 }
74
75 pub(crate) fn as_slice(&self, lua: &RawLua) -> &[u8] {
76 unsafe {
77 let (buf, size) = self.as_raw_parts(lua);
78 std::slice::from_raw_parts(buf, size)
79 }
80 }
81
82 #[allow(clippy::mut_from_ref)]
83 fn as_slice_mut(&self, lua: &RawLua) -> &mut [u8] {
84 unsafe {
85 let (buf, size) = self.as_raw_parts(lua);
86 std::slice::from_raw_parts_mut(buf, size)
87 }
88 }
89
90 #[cfg(feature = "luau")]
91 unsafe fn as_raw_parts(&self, lua: &RawLua) -> (*mut u8, usize) {
92 let mut size = 0usize;
93 let buf = ffi::lua_tobuffer(lua.ref_thread(), self.0.index, &mut size);
94 mlua_assert!(!buf.is_null(), "invalid Luau buffer");
95 (buf as *mut u8, size)
96 }
97
98 #[cfg(not(feature = "luau"))]
99 unsafe fn as_raw_parts(&self, lua: &RawLua) -> (*mut u8, usize) {
100 unreachable!()
101 }
102}
103
104struct BufferCursor(Buffer, usize);
105
106impl io::Read for BufferCursor {
107 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
108 let lua = self.0.0.lua.lock();
109 let data = self.0.as_slice(&lua);
110 if self.1 == data.len() {
111 return Ok(0);
112 }
113 let len = buf.len().min(data.len() - self.1);
114 buf[..len].copy_from_slice(&data[self.1..self.1 + len]);
115 self.1 += len;
116 Ok(len)
117 }
118}
119
120impl io::Write for BufferCursor {
121 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
122 let lua = self.0.0.lua.lock();
123 let data = self.0.as_slice_mut(&lua);
124 if self.1 == data.len() {
125 return Ok(0);
126 }
127 let len = buf.len().min(data.len() - self.1);
128 data[self.1..self.1 + len].copy_from_slice(&buf[..len]);
129 self.1 += len;
130 Ok(len)
131 }
132
133 fn flush(&mut self) -> io::Result<()> {
134 Ok(())
135 }
136}
137
138impl io::Seek for BufferCursor {
139 fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
140 let lua = self.0.0.lua.lock();
141 let data = self.0.as_slice(&lua);
142 let new_offset = match pos {
143 io::SeekFrom::Start(offset) => offset as i64,
144 io::SeekFrom::End(offset) => data.len() as i64 + offset,
145 io::SeekFrom::Current(offset) => self.1 as i64 + offset,
146 };
147 if new_offset < 0 {
148 return Err(io::Error::new(
149 io::ErrorKind::InvalidInput,
150 "invalid seek to a negative position",
151 ));
152 }
153 if new_offset as usize > data.len() {
154 return Err(io::Error::new(
155 io::ErrorKind::InvalidInput,
156 "invalid seek to a position beyond the end of the buffer",
157 ));
158 }
159 self.1 = new_offset as usize;
160 Ok(self.1 as u64)
161 }
162}
163
164#[cfg(feature = "serde")]
165impl Serialize for Buffer {
166 fn serialize<S: Serializer>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error> {
167 let lua = self.0.lua.lock();
168 serializer.serialize_bytes(self.as_slice(&lua))
169 }
170}
171
172#[cfg(feature = "luau")]
173impl crate::types::LuaType for Buffer {
174 const TYPE_ID: std::os::raw::c_int = ffi::LUA_TBUFFER;
175}