use std::{collections::HashSet, future::Future, pin::Pin};
use bytes::Bytes;
use libipld::Cid;
use serde::{de::DeserializeOwned, Serialize};
use tokio::io::{AsyncRead, AsyncReadExt};
use super::{IpldReferences, SeekableReader, StoreError, StoreResult};
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Codec {
Raw,
DagCbor,
DagJson,
DagPb,
}
pub trait IpldStore: Clone {
fn put_node<T>(&self, data: &T) -> impl Future<Output = StoreResult<Cid>> + Send
where
T: Serialize + IpldReferences + Sync;
fn put_bytes<'a>(
&'a self,
reader: impl AsyncRead + Send + Sync + 'a,
) -> impl Future<Output = StoreResult<Cid>> + 'a;
fn put_raw_block(
&self,
bytes: impl Into<Bytes> + Send,
) -> impl Future<Output = StoreResult<Cid>> + Send;
fn get_node<D>(&self, cid: &Cid) -> impl Future<Output = StoreResult<D>> + Send
where
D: DeserializeOwned + Send;
fn get_bytes<'a>(
&'a self,
cid: &'a Cid,
) -> impl Future<Output = StoreResult<Pin<Box<dyn AsyncRead + Send + Sync + 'a>>>> + 'a;
fn get_raw_block(&self, cid: &Cid) -> impl Future<Output = StoreResult<Bytes>> + Send + Sync;
fn has(&self, cid: &Cid) -> impl Future<Output = bool>;
fn get_supported_codecs(&self) -> HashSet<Codec>;
fn get_node_block_max_size(&self) -> Option<u64>;
fn get_raw_block_max_size(&self) -> Option<u64>;
fn is_empty(&self) -> impl Future<Output = StoreResult<bool>>;
fn get_size(&self) -> impl Future<Output = StoreResult<u64>>;
}
pub trait IpldStoreExt: IpldStore {
fn read_all(&self, cid: &Cid) -> impl Future<Output = StoreResult<Bytes>> {
async {
let mut reader = self.get_bytes(cid).await?;
let mut bytes = Vec::new();
reader
.read_to_end(&mut bytes)
.await
.map_err(StoreError::custom)?;
Ok(Bytes::from(bytes))
}
}
}
pub trait IpldStoreSeekable: IpldStore {
fn get_seekable_bytes<'a>(
&'a self,
cid: &'a Cid,
) -> impl Future<Output = StoreResult<Pin<Box<dyn SeekableReader + Send + 'a>>>>;
}
impl TryFrom<u64> for Codec {
type Error = StoreError;
fn try_from(value: u64) -> Result<Self, Self::Error> {
match value {
0x55 => Ok(Codec::Raw),
0x71 => Ok(Codec::DagCbor),
0x0129 => Ok(Codec::DagJson),
0x70 => Ok(Codec::DagPb),
_ => Err(StoreError::UnsupportedCodec(value)),
}
}
}
impl From<Codec> for u64 {
fn from(codec: Codec) -> Self {
match codec {
Codec::Raw => 0x55,
Codec::DagCbor => 0x71,
Codec::DagJson => 0x0129,
Codec::DagPb => 0x70,
}
}
}
impl<T> IpldStoreExt for T where T: IpldStore {}