use std::{
any::Any,
ops::Deref,
sync::{Arc, Mutex},
};
use wasi_common::{Error, ErrorExt, WasiFile, file::FileType};
pub struct RamFile {
data: Mutex<Vec<u8>>,
size_limit: usize,
}
impl RamFile {
pub fn with_size_limit(size_limit: usize) -> Self {
RamFile {
data: Default::default(),
size_limit,
}
}
pub fn take(&self) -> Vec<u8> {
let mut data = self.data.lock().unwrap();
std::mem::take(&mut *data)
}
}
#[async_trait::async_trait]
impl WasiFile for RamFile {
fn as_any(&self) -> &dyn Any {
self
}
async fn get_filetype(&self) -> Result<FileType, Error> {
Ok(FileType::RegularFile)
}
async fn writable(&self) -> Result<(), Error> {
Ok(())
}
async fn write_vectored<'a>(&self, bufs: &[std::io::IoSlice<'a>]) -> Result<u64, Error> {
let mut data = self.data.lock().unwrap();
let written: u64 = bufs.iter().map(|buf| buf.len() as u64).sum();
if data.len() + written as usize > self.size_limit {
return Err(Error::overflow());
}
for buf in bufs {
data.extend_from_slice(buf);
}
Ok(written)
}
}
#[derive(Clone)]
pub struct RamFileRef(Arc<RamFile>);
impl RamFileRef {
pub fn new(file: RamFile) -> Self {
RamFileRef(Arc::new(file))
}
}
impl Deref for RamFileRef {
type Target = RamFile;
fn deref(&self) -> &Self::Target {
&self.0
}
}
#[async_trait::async_trait]
impl WasiFile for RamFileRef {
fn as_any(&self) -> &dyn Any {
self
}
async fn get_filetype(&self) -> Result<FileType, Error> {
Ok(FileType::RegularFile)
}
async fn writable(&self) -> Result<(), Error> {
Ok(())
}
async fn write_vectored<'a>(&self, bufs: &[std::io::IoSlice<'a>]) -> Result<u64, Error> {
self.0.write_vectored(bufs).await
}
}