use std::path::Path;
use std::pin::Pin;
use std::task::{Context as TaskContext, Poll};
use futures::prelude::*;
use ssri::{Algorithm, Integrity};
use crate::content::read;
use crate::errors::{Error, Result};
use crate::index::{self, Metadata};
pub struct Reader {
reader: read::AsyncReader,
}
impl AsyncRead for Reader {
fn poll_read(
mut self: Pin<&mut Self>,
cx: &mut TaskContext<'_>,
buf: &mut [u8],
) -> Poll<std::io::Result<usize>> {
Pin::new(&mut self.reader).poll_read(cx, buf)
}
}
impl Reader {
pub fn check(self) -> Result<Algorithm> {
self.reader.check()
}
pub async fn open<P, K>(cache: P, key: K) -> Result<Reader>
where
P: AsRef<Path>,
K: AsRef<str>,
{
if let Some(entry) = index::find_async(cache.as_ref(), key.as_ref()).await? {
Reader::open_hash(cache, entry.integrity).await
} else {
return Err(Error::EntryNotFound(
cache.as_ref().to_path_buf(),
key.as_ref().into(),
))
}
}
pub async fn open_hash<P>(cache: P, sri: Integrity) -> Result<Reader>
where
P: AsRef<Path>,
{
Ok(Reader {
reader: read::open_async(cache.as_ref(), sri).await?,
})
}
}
pub async fn read<P, K>(cache: P, key: K) -> Result<Vec<u8>>
where
P: AsRef<Path>,
K: AsRef<str>,
{
if let Some(entry) = index::find_async(cache.as_ref(), key.as_ref()).await? {
read_hash(cache, &entry.integrity).await
} else {
return Err(Error::EntryNotFound(
cache.as_ref().to_path_buf(),
key.as_ref().into(),
))
}
}
pub async fn read_hash<P>(cache: P, sri: &Integrity) -> Result<Vec<u8>>
where
P: AsRef<Path>,
{
Ok(read::read_async(cache.as_ref(), sri).await?)
}
pub async fn copy<P, K, Q>(cache: P, key: K, to: Q) -> Result<u64>
where
P: AsRef<Path>,
K: AsRef<str>,
Q: AsRef<Path>,
{
if let Some(entry) = index::find_async(cache.as_ref(), key.as_ref()).await? {
copy_hash(cache, &entry.integrity, to).await
} else {
return Err(Error::EntryNotFound(
cache.as_ref().to_path_buf(),
key.as_ref().into(),
))
}
}
pub async fn copy_hash<P, Q>(cache: P, sri: &Integrity, to: Q) -> Result<u64>
where
P: AsRef<Path>,
Q: AsRef<Path>,
{
read::copy_async(cache.as_ref(), sri, to.as_ref()).await
}
pub async fn metadata<P, K>(cache: P, key: K) -> Result<Option<Metadata>>
where
P: AsRef<Path>,
K: AsRef<str>,
{
Ok(index::find_async(cache.as_ref(), key.as_ref()).await?)
}
pub async fn exists<P: AsRef<Path>>(cache: P, sri: &Integrity) -> bool {
read::has_content_async(cache.as_ref(), sri)
.await
.is_some()
}
pub struct SyncReader {
reader: read::Reader,
}
impl std::io::Read for SyncReader {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
self.reader.read(buf)
}
}
impl SyncReader {
pub fn check(self) -> Result<Algorithm> {
self.reader.check()
}
pub fn open<P, K>(cache: P, key: K) -> Result<SyncReader>
where
P: AsRef<Path>,
K: AsRef<str>,
{
if let Some(entry) = index::find(cache.as_ref(), key.as_ref())? {
SyncReader::open_hash(cache, entry.integrity)
} else {
return Err(Error::EntryNotFound(
cache.as_ref().to_path_buf(),
key.as_ref().into(),
))
}
}
pub fn open_hash<P>(cache: P, sri: Integrity) -> Result<SyncReader>
where
P: AsRef<Path>,
{
Ok(SyncReader {
reader: read::open(cache.as_ref(), sri)?,
})
}
}
pub fn read_sync<P, K>(cache: P, key: K) -> Result<Vec<u8>>
where
P: AsRef<Path>,
K: AsRef<str>,
{
if let Some(entry) = index::find(cache.as_ref(), key.as_ref())? {
read_hash_sync(cache, &entry.integrity)
} else {
return Err(Error::EntryNotFound(
cache.as_ref().to_path_buf(),
key.as_ref().into(),
))
}
}
pub fn read_hash_sync<P>(cache: P, sri: &Integrity) -> Result<Vec<u8>>
where
P: AsRef<Path>,
{
read::read(cache.as_ref(), sri)
}
pub fn copy_sync<P, K, Q>(cache: P, key: K, to: Q) -> Result<u64>
where
P: AsRef<Path>,
K: AsRef<str>,
Q: AsRef<Path>,
{
if let Some(entry) = index::find(cache.as_ref(), key.as_ref())? {
copy_hash_sync(cache, &entry.integrity, to)
} else {
return Err(Error::EntryNotFound(
cache.as_ref().to_path_buf(),
key.as_ref().into(),
))
}
}
pub fn copy_hash_sync<P, Q>(cache: P, sri: &Integrity, to: Q) -> Result<u64>
where
P: AsRef<Path>,
Q: AsRef<Path>,
{
read::copy(cache.as_ref(), sri, to.as_ref())
}
pub fn metadata_sync<P, K>(cache: P, key: K) -> Result<Option<Metadata>>
where
P: AsRef<Path>,
K: AsRef<str>,
{
index::find(cache.as_ref(), key.as_ref())
}
pub fn exists_sync<P: AsRef<Path>>(cache: P, sri: &Integrity) -> bool {
read::has_content(cache.as_ref(), sri).is_some()
}
#[cfg(test)]
mod tests {
use async_std::fs as afs;
use async_std::prelude::*;
use std::fs;
#[async_attributes::test]
async fn test_open() {
let tmp = tempfile::tempdir().unwrap();
let dir = tmp.path().to_owned();
crate::write(&dir, "my-key", b"hello world").await.unwrap();
let mut handle = crate::Reader::open(&dir, "my-key").await.unwrap();
let mut str = String::new();
handle.read_to_string(&mut str).await.unwrap();
handle.check().unwrap();
assert_eq!(str, String::from("hello world"));
}
#[async_attributes::test]
async fn test_open_hash() {
let tmp = tempfile::tempdir().unwrap();
let dir = tmp.path().to_owned();
let sri = crate::write(&dir, "my-key", b"hello world").await.unwrap();
let mut handle = crate::Reader::open_hash(&dir, sri).await.unwrap();
let mut str = String::new();
handle.read_to_string(&mut str).await.unwrap();
handle.check().unwrap();
assert_eq!(str, String::from("hello world"));
}
#[test]
fn test_open_sync() {
use std::io::prelude::*;
let tmp = tempfile::tempdir().unwrap();
let dir = tmp.path().to_owned();
crate::write_sync(&dir, "my-key", b"hello world").unwrap();
let mut handle = crate::SyncReader::open(&dir, "my-key").unwrap();
let mut str = String::new();
handle.read_to_string(&mut str).unwrap();
handle.check().unwrap();
assert_eq!(str, String::from("hello world"));
}
#[test]
fn test_open_hash_sync() {
use std::io::prelude::*;
let tmp = tempfile::tempdir().unwrap();
let dir = tmp.path().to_owned();
let sri = crate::write_sync(&dir, "my-key", b"hello world").unwrap();
let mut handle = crate::SyncReader::open_hash(&dir, sri).unwrap();
let mut str = String::new();
handle.read_to_string(&mut str).unwrap();
handle.check().unwrap();
assert_eq!(str, String::from("hello world"));
}
#[async_attributes::test]
async fn test_read() {
let tmp = tempfile::tempdir().unwrap();
let dir = tmp.path().to_owned();
crate::write(&dir, "my-key", b"hello world").await.unwrap();
let data = crate::read(&dir, "my-key").await.unwrap();
assert_eq!(data, b"hello world");
}
#[async_attributes::test]
async fn test_read_hash() {
let tmp = tempfile::tempdir().unwrap();
let dir = tmp.path().to_owned();
let sri = crate::write(&dir, "my-key", b"hello world").await.unwrap();
let data = crate::read_hash(&dir, &sri).await.unwrap();
assert_eq!(data, b"hello world");
}
#[test]
fn test_read_sync() {
let tmp = tempfile::tempdir().unwrap();
let dir = tmp.path().to_owned();
crate::write_sync(&dir, "my-key", b"hello world").unwrap();
let data = crate::read_sync(&dir, "my-key").unwrap();
assert_eq!(data, b"hello world");
}
#[test]
fn test_read_hash_sync() {
let tmp = tempfile::tempdir().unwrap();
let dir = tmp.path().to_owned();
let sri = crate::write_sync(&dir, "my-key", b"hello world").unwrap();
let data = crate::read_hash_sync(&dir, &sri).unwrap();
assert_eq!(data, b"hello world");
}
#[async_attributes::test]
async fn test_copy() {
let tmp = tempfile::tempdir().unwrap();
let dir = tmp.path();
let dest = dir.join("data");
crate::write(&dir, "my-key", b"hello world").await.unwrap();
crate::copy(&dir, "my-key", &dest).await.unwrap();
let data = afs::read(&dest).await.unwrap();
assert_eq!(data, b"hello world");
}
#[async_attributes::test]
async fn test_copy_hash() {
let tmp = tempfile::tempdir().unwrap();
let dir = tmp.path();
let dest = dir.join("data");
let sri = crate::write(&dir, "my-key", b"hello world").await.unwrap();
crate::copy_hash(&dir, &sri, &dest).await.unwrap();
let data = afs::read(&dest).await.unwrap();
assert_eq!(data, b"hello world");
}
#[test]
fn test_copy_sync() {
let tmp = tempfile::tempdir().unwrap();
let dir = tmp.path();
let dest = dir.join("data");
crate::write_sync(&dir, "my-key", b"hello world").unwrap();
crate::copy_sync(&dir, "my-key", &dest).unwrap();
let data = fs::read(&dest).unwrap();
assert_eq!(data, b"hello world");
}
#[test]
fn test_copy_hash_sync() {
let tmp = tempfile::tempdir().unwrap();
let dir = tmp.path();
let dest = dir.join("data");
let sri = crate::write_sync(&dir, "my-key", b"hello world").unwrap();
crate::copy_hash_sync(&dir, &sri, &dest).unwrap();
let data = fs::read(&dest).unwrap();
assert_eq!(data, b"hello world");
}
}