1use crate::bindings::vtx::api::stream_io;
4use crate::bindings::vtx::api::stream_io::Buffer;
5use crate::error::{VtxError, VtxResult};
6use serde::de::DeserializeOwned;
7
8pub type StreamBuffer = Buffer;
9
10pub fn open_file(uuid: &str) -> VtxResult<Buffer> {
12 stream_io::open_file(uuid).map_err(VtxError::from_host_message)
13}
14
15pub fn memory_buffer(data: impl AsRef<[u8]>) -> Buffer {
17 stream_io::create_memory_buffer(data.as_ref())
18}
19
20pub trait BufferExt {
22 fn read_all(&self) -> Vec<u8>;
27
28 fn read_to_string(&self) -> VtxResult<String>;
30
31 fn read_json<T: DeserializeOwned>(&self) -> VtxResult<T>;
33
34 fn write_all(&self, data: impl AsRef<[u8]>) -> u64;
36}
37
38impl BufferExt for Buffer {
39 fn read_all(&self) -> Vec<u8> {
40 const CHUNK: u64 = 64 * 1024;
41 const MAX_TOTAL: usize = 64 * 1024 * 1024;
42
43 let mut out = Vec::new();
44
45 let total = self.size();
46 if total > 0 {
47 let mut offset = 0u64;
48 while offset < total && out.len() < MAX_TOTAL {
49 let to_read = std::cmp::min(CHUNK, total - offset);
50 let chunk = self.read(offset, to_read);
51 if chunk.is_empty() {
52 break;
53 }
54 out.extend_from_slice(&chunk);
55 offset += chunk.len() as u64;
56 }
57 return out;
58 }
59
60 while out.len() < MAX_TOTAL {
62 let chunk = self.read(0, CHUNK);
63 if chunk.is_empty() {
64 break;
65 }
66 out.extend_from_slice(&chunk);
67 }
68
69 out
70 }
71
72 fn read_to_string(&self) -> VtxResult<String> {
73 let bytes = self.read_all();
74 String::from_utf8(bytes).map_err(|e| VtxError::SerializationError(e.to_string()))
75 }
76
77 fn read_json<T: DeserializeOwned>(&self) -> VtxResult<T> {
78 let s = self.read_to_string()?;
79 serde_json::from_str(&s).map_err(|e| VtxError::SerializationError(e.to_string()))
80 }
81
82 fn write_all(&self, data: impl AsRef<[u8]>) -> u64 {
83 self.write(data.as_ref())
84 }
85}