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