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