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]
41 pub fn read_bytes<const N: usize>(&self, offset: usize) -> [u8; N] {
42 let lua = self.0.lua.lock();
43 let data = self.as_slice(&lua);
44 let mut bytes = [0u8; N];
45 bytes.copy_from_slice(&data[offset..offset + N]);
46 bytes
47 }
48
49 #[track_caller]
53 pub fn write_bytes(&self, offset: usize, bytes: &[u8]) {
54 let lua = self.0.lua.lock();
55 let data = self.as_slice_mut(&lua);
56 data[offset..offset + bytes.len()].copy_from_slice(bytes);
57 }
58
59 pub fn cursor(self) -> impl io::Read + io::Write + io::Seek {
64 BufferCursor(self, 0)
65 }
66
67 pub(crate) fn as_slice(&self, lua: &RawLua) -> &[u8] {
68 unsafe {
69 let (buf, size) = self.as_raw_parts(lua);
70 std::slice::from_raw_parts(buf, size)
71 }
72 }
73
74 #[allow(clippy::mut_from_ref)]
75 fn as_slice_mut(&self, lua: &RawLua) -> &mut [u8] {
76 unsafe {
77 let (buf, size) = self.as_raw_parts(lua);
78 std::slice::from_raw_parts_mut(buf, size)
79 }
80 }
81
82 #[cfg(feature = "luau")]
83 unsafe fn as_raw_parts(&self, lua: &RawLua) -> (*mut u8, usize) {
84 let mut size = 0usize;
85 let buf = ffi::lua_tobuffer(lua.ref_thread(), self.0.index, &mut size);
86 mlua_assert!(!buf.is_null(), "invalid Luau buffer");
87 (buf as *mut u8, size)
88 }
89
90 #[cfg(not(feature = "luau"))]
91 unsafe fn as_raw_parts(&self, lua: &RawLua) -> (*mut u8, usize) {
92 unreachable!()
93 }
94}
95
96struct BufferCursor(Buffer, usize);
97
98impl io::Read for BufferCursor {
99 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
100 let lua = self.0.0.lua.lock();
101 let data = self.0.as_slice(&lua);
102 if self.1 == data.len() {
103 return Ok(0);
104 }
105 let len = buf.len().min(data.len() - self.1);
106 buf[..len].copy_from_slice(&data[self.1..self.1 + len]);
107 self.1 += len;
108 Ok(len)
109 }
110}
111
112impl io::Write for BufferCursor {
113 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
114 let lua = self.0.0.lua.lock();
115 let data = self.0.as_slice_mut(&lua);
116 if self.1 == data.len() {
117 return Ok(0);
118 }
119 let len = buf.len().min(data.len() - self.1);
120 data[self.1..self.1 + len].copy_from_slice(&buf[..len]);
121 self.1 += len;
122 Ok(len)
123 }
124
125 fn flush(&mut self) -> io::Result<()> {
126 Ok(())
127 }
128}
129
130impl io::Seek for BufferCursor {
131 fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
132 let lua = self.0.0.lua.lock();
133 let data = self.0.as_slice(&lua);
134 let new_offset = match pos {
135 io::SeekFrom::Start(offset) => offset as i64,
136 io::SeekFrom::End(offset) => data.len() as i64 + offset,
137 io::SeekFrom::Current(offset) => self.1 as i64 + offset,
138 };
139 if new_offset < 0 {
140 return Err(io::Error::new(
141 io::ErrorKind::InvalidInput,
142 "invalid seek to a negative position",
143 ));
144 }
145 if new_offset as usize > data.len() {
146 return Err(io::Error::new(
147 io::ErrorKind::InvalidInput,
148 "invalid seek to a position beyond the end of the buffer",
149 ));
150 }
151 self.1 = new_offset as usize;
152 Ok(self.1 as u64)
153 }
154}
155
156#[cfg(feature = "serde")]
157impl Serialize for Buffer {
158 fn serialize<S: Serializer>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error> {
159 let lua = self.0.lua.lock();
160 serializer.serialize_bytes(self.as_slice(&lua))
161 }
162}
163
164#[cfg(feature = "luau")]
165impl crate::types::LuaType for Buffer {
166 const TYPE_ID: std::os::raw::c_int = ffi::LUA_TBUFFER;
167}