use rapira::{Rapira, RapiraError};
use serde::Serialize;
#[cfg(feature = "ts-types")]
use specta::{DataType, DefOpts, Type};
#[cfg(feature = "ts-types")]
use typescript_type_def::{
type_expr::{DefinedTypeInfo, Ident, TypeDefinition, TypeExpr, TypeInfo, TypeIntersection},
TypeDef,
};
use crate::{Cid, Record};
#[derive(Clone, Debug, Serialize)]
pub struct Entry<Val>
where
Val: Record,
{
#[serde(flatten)]
pub key: Val::SelfId,
#[serde(flatten)]
pub val: Val,
}
impl<Val> Entry<Val>
where
Val: Record,
{
pub fn new(key: Val::SelfId, val: Val) -> Self {
Entry { key, val }
}
pub fn get_id(self) -> Val::SelfId {
self.key
}
pub fn get_val(&self) -> &Val {
&self.val
}
pub fn split(self) -> (Val::SelfId, Val) {
let Entry { key, val } = self;
(key, val)
}
}
impl<Val> From<(Val::SelfId, Val)> for Entry<Val>
where
Val: Record,
{
fn from(tuple: (Val::SelfId, Val)) -> Self {
Entry::new(tuple.0, tuple.1)
}
}
const fn a_b_size(a: Option<usize>, b: Option<usize>) -> Option<usize> {
match a {
Some(s) => match b {
Some(ss) => Some(s + ss),
None => None,
},
None => None,
}
}
impl<Val> Rapira for Entry<Val>
where
Val: Record,
<Val::SelfId as Cid>::B: Rapira,
{
const STATIC_SIZE: Option<usize> =
a_b_size(Val::STATIC_SIZE, <Val::SelfId as Cid>::B::STATIC_SIZE);
fn size(&self) -> usize {
match Self::STATIC_SIZE {
Some(s) => s,
None => self.key.encode().size() + self.val.size(),
}
}
fn check_bytes(slice: &mut &[u8]) -> rapira::Result<()> {
<Val::SelfId as Cid>::B::check_bytes(slice)?;
Val::check_bytes(slice)?;
Ok(())
}
fn from_slice_unchecked(slice: &mut &[u8]) -> rapira::Result<Self>
where
Self: Sized,
{
let key = <Val::SelfId as Cid>::B::from_slice_unchecked(slice)?;
let key = <Val::SelfId>::from_bytes(key.as_ref())
.map_err(|_| RapiraError::OtherError("Cid::from_bytes error"))?;
let val = Val::from_slice_unchecked(slice)?;
Ok(Entry::new(key, val))
}
fn from_slice(slice: &mut &[u8]) -> rapira::Result<Self>
where
Self: Sized,
{
let key = <Val::SelfId as Cid>::B::from_slice(slice)?;
let key = <Val::SelfId>::from_bytes(key.as_ref())
.map_err(|_| RapiraError::OtherError("Entry Cid error"))?;
let val = Val::from_slice(slice)?;
Ok(Entry::new(key, val))
}
unsafe fn from_slice_unsafe(slice: &mut &[u8]) -> rapira::Result<Self>
where
Self: Sized,
{
let key = <Val::SelfId as Cid>::B::from_slice_unsafe(slice)?;
let key = <Val::SelfId>::from_bytes_unsafe(key.as_ref());
let val = Val::from_slice_unsafe(slice)?;
Ok(Entry::new(key, val))
}
fn convert_to_bytes(&self, slice: &mut [u8], cursor: &mut usize) {
self.key.encode().convert_to_bytes(slice, cursor);
self.val.convert_to_bytes(slice, cursor);
}
fn try_convert_to_bytes(&self, slice: &mut [u8], cursor: &mut usize) -> rapira::Result<()> {
self.key.encode().try_convert_to_bytes(slice, cursor)?;
self.val.try_convert_to_bytes(slice, cursor)?;
Ok(())
}
}
#[cfg(feature = "ts-types")]
impl<Val> TypeDef for Entry<Val>
where
Self: 'static,
Val: Record + TypeDef,
Val::SelfId: TypeDef,
{
const INFO: TypeInfo = TypeInfo::Defined(DefinedTypeInfo {
def: TypeDefinition {
docs: None,
path: &[],
name: Ident("Entry"),
generic_vars: &[Ident("T"), Ident("Id")],
def: TypeExpr::Intersection(TypeIntersection {
docs: None,
members: &[TypeExpr::Ref(&Val::SelfId::INFO), TypeExpr::Ref(&Val::INFO)],
}),
},
generic_args: &[],
});
}