use crate::bindings::vtx::api::vtx_vfs;
use crate::bindings::vtx::api::vtx_vfs::Buffer;
use crate::error::{VtxError, VtxResult};
use serde::de::DeserializeOwned;
pub type StreamBuffer = Buffer;
pub fn open_uri(uri: &str) -> VtxResult<Buffer> {
vtx_vfs::open_uri(uri).map_err(VtxError::from_host_message)
}
pub fn open_file(uuid: &str) -> VtxResult<Buffer> {
open_uri(uuid)
}
pub fn memory_buffer(data: impl AsRef<[u8]>) -> Buffer {
vtx_vfs::create_memory_buffer(data.as_ref())
}
pub trait BufferExt {
fn read_all(&self) -> Vec<u8>;
fn read_to_string(&self) -> VtxResult<String>;
fn read_json<T: DeserializeOwned>(&self) -> VtxResult<T>;
fn write_all(&self, data: impl AsRef<[u8]>) -> u64;
}
impl BufferExt for Buffer {
fn read_all(&self) -> Vec<u8> {
const CHUNK: u64 = 64 * 1024;
const MAX_TOTAL: usize = 64 * 1024 * 1024;
let mut out = Vec::new();
let total = self.size();
if total > 0 {
let mut offset = 0u64;
while offset < total && out.len() < MAX_TOTAL {
let to_read = std::cmp::min(CHUNK, total - offset);
let chunk = self.read(offset, to_read);
if chunk.is_empty() {
break;
}
out.extend_from_slice(&chunk);
offset += chunk.len() as u64;
}
return out;
}
while out.len() < MAX_TOTAL {
let chunk = self.read(0, CHUNK);
if chunk.is_empty() {
break;
}
out.extend_from_slice(&chunk);
}
out
}
fn read_to_string(&self) -> VtxResult<String> {
let bytes = self.read_all();
String::from_utf8(bytes).map_err(|e| VtxError::SerializationError(e.to_string()))
}
fn read_json<T: DeserializeOwned>(&self) -> VtxResult<T> {
let s = self.read_to_string()?;
serde_json::from_str(&s).map_err(|e| VtxError::SerializationError(e.to_string()))
}
fn write_all(&self, data: impl AsRef<[u8]>) -> u64 {
self.write(data.as_ref())
}
}