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