use std::io::{self, Cursor, Read, Write};
use std::sync::{Arc, Mutex};
#[cfg(feature = "async")]
use super::AsyncInputProvider;
use super::{InputProvider, OutputTarget};
#[cfg(feature = "async")]
use async_trait::async_trait;
#[cfg(feature = "async")]
use tokio::io::{AsyncRead, BufReader};
#[derive(Debug, Clone)]
pub struct InMemorySource {
id: String,
data: Arc<Vec<u8>>,
}
impl InMemorySource {
pub fn new(id: impl Into<String>, data: Vec<u8>) -> Self {
Self {
id: id.into(),
data: Arc::new(data),
}
}
pub fn from_string(id: impl Into<String>, data: impl Into<String>) -> Self {
Self::new(id, data.into().into_bytes())
}
}
impl InputProvider for InMemorySource {
fn id(&self) -> &str {
&self.id
}
fn open(&self) -> io::Result<Box<dyn Read + Send>> {
Ok(Box::new(Cursor::new(self.data.as_ref().clone())))
}
}
#[derive(Debug, Clone)]
pub struct InMemorySink {
id: String,
buf: Arc<Mutex<Vec<u8>>>,
}
impl InMemorySink {
pub fn new(id: impl Into<String>) -> Self {
Self {
id: id.into(),
buf: Arc::new(Mutex::new(Vec::new())),
}
}
pub fn contents(&self) -> Vec<u8> {
self.buf.lock().unwrap().clone()
}
pub fn contents_string(&self) -> String {
String::from_utf8_lossy(&self.contents()).into_owned()
}
pub fn into_inner(self) -> Vec<u8> {
Arc::try_unwrap(self.buf)
.map(|m| m.into_inner().unwrap())
.unwrap_or_else(|arc| arc.lock().unwrap().clone())
}
pub fn clear(&self) {
self.buf.lock().unwrap().clear();
}
}
impl OutputTarget for InMemorySink {
fn id(&self) -> &str {
&self.id
}
fn open_overwrite(&self) -> io::Result<Box<dyn Write + Send>> {
self.buf.lock().unwrap().clear();
Ok(Box::new(InMemoryWriteHandle {
buf: self.buf.clone(),
}))
}
fn open_append(&self) -> io::Result<Box<dyn Write + Send>> {
Ok(Box::new(InMemoryWriteHandle {
buf: self.buf.clone(),
}))
}
}
#[cfg(feature = "async")]
#[derive(Debug, Clone)]
pub struct AsyncInMemorySource {
id: String,
data: Arc<Vec<u8>>,
}
#[cfg(feature = "async")]
impl AsyncInMemorySource {
pub fn new(id: impl Into<String>, data: Vec<u8>) -> Self {
Self {
id: id.into(),
data: Arc::new(data),
}
}
pub fn from_string(id: impl Into<String>, data: impl Into<String>) -> Self {
Self::new(id, data.into().into_bytes())
}
}
#[cfg(feature = "async")]
#[async_trait]
impl AsyncInputProvider for AsyncInMemorySource {
fn id(&self) -> &str {
&self.id
}
async fn open(&self) -> io::Result<Box<dyn AsyncRead + Unpin + Send>> {
Ok(Box::new(BufReader::new(Cursor::new(
self.data.as_ref().clone(),
))))
}
}
struct InMemoryWriteHandle {
buf: Arc<Mutex<Vec<u8>>>,
}
impl std::fmt::Debug for InMemoryWriteHandle {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("InMemoryWriteHandle").finish()
}
}
impl Write for InMemoryWriteHandle {
fn write(&mut self, data: &[u8]) -> io::Result<usize> {
let mut guard = self.buf.lock().unwrap();
guard.extend_from_slice(data);
Ok(data.len())
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}