use derive_more::Deref;
use rapira::{Rapira, RapiraError};
use serde::Serialize;
use crate::{Cid, Record};
#[derive(Clone, Debug, Serialize, Deref)]
pub struct Entry<Val: Record> {
#[serde(flatten)]
pub key: Val::SelfId,
#[deref]
#[serde(flatten)]
pub val: Val,
}
impl<Val: Record> Entry<Val> {
pub fn new(key: Val::SelfId, val: Val) -> Self {
Self { key, val }
}
pub fn key(self) -> Val::SelfId {
self.key
}
pub fn value(&self) -> &Val {
&self.val
}
#[deprecated]
pub fn get_id(self) -> Val::SelfId {
self.key
}
#[deprecated]
pub fn get_val(&self) -> &Val {
&self.val
}
pub fn split(self) -> (Val::SelfId, Val) {
let Self { key, val } = self;
(key, val)
}
pub fn split_ref(&self) -> (&Val::SelfId, &Val) {
let Self { key, val } = self;
(key, val)
}
pub fn split_mut(&mut self) -> (&mut Val::SelfId, &mut Val) {
let Self { key, val } = self;
(key, val)
}
}
impl<Val: Record> From<(Val::SelfId, Val)> for Entry<Val> {
fn from(tuple: (Val::SelfId, Val)) -> Self {
Self::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 + Rapira,
<Val::SelfId as Cid>::B: Rapira,
{
const STATIC_SIZE: Option<usize> =
a_b_size(Val::STATIC_SIZE, <Val::SelfId as Cid>::B::STATIC_SIZE);
const MIN_SIZE: usize = {
let a = Val::MIN_SIZE;
let b = <Val::SelfId as Cid>::B::MIN_SIZE;
a + b
};
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(())
}
unsafe fn from_slice_unchecked(slice: &mut &[u8]) -> rapira::Result<Self>
where
Self: Sized,
{
unsafe {
let key = <Val::SelfId as Cid>::B::from_slice_unchecked(slice)?;
let key = <Val::SelfId>::from_bytes(key.as_ref())
.map_err(|_| RapiraError::Other("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::Other("Entry Cid error"))?;
let val = Val::from_slice(slice)?;
Ok(Self::new(key, val))
}
unsafe fn from_slice_unsafe(slice: &mut &[u8]) -> rapira::Result<Self>
where
Self: Sized,
{
unsafe {
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(Self::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-rs")]
mod fake_id {
use rapira::Rapira;
use crate::GetType;
#[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Clone, Copy, Hash, ts_rs::TS, Rapira)]
pub struct Fake {
data: (),
}
impl GetType for Fake {
const TYPE: crate::Typ = crate::Typ::Void;
}
crate::rapira_record!(Fake, crate::Fuid<()>, crate::Slice, "fake");
}
#[cfg(feature = "ts-rs")]
impl<Val: Record> ts_rs::TS for Entry<Val>
where
Val: ts_rs::TS,
Val::SelfId: ts_rs::TS,
{
type OptionInnerType = Self;
type WithoutGenerics = Entry<fake_id::Fake>;
fn ident(_: &ts_rs::Config) -> String {
"Entry".to_owned()
}
fn name(c: &ts_rs::Config) -> String {
{
let val_name = <Val as ts_rs::TS>::name(c);
let id_name = <Val::SelfId as ts_rs::TS>::name(c);
format!("Entry<{val_name}, {id_name}>")
}
}
fn decl_concrete(c: &ts_rs::Config) -> String {
Self::decl(c)
}
fn decl(_: &ts_rs::Config) -> String {
"type Entry<Val, Key> = Val & Key;".to_string()
}
fn inline(c: &ts_rs::Config) -> String {
<[String]>::join(
&[
<Val::SelfId as ts_rs::TS>::inline_flattened(c),
<Val as ts_rs::TS>::inline_flattened(c),
],
" & ",
)
.replace(" } & { ", " ")
}
fn inline_flattened(c: &ts_rs::Config) -> String {
Self::inline(c)
}
fn visit_generics(v: &mut impl ts_rs::TypeVisitor)
where
Self: 'static,
{
v.visit::<Val>();
v.visit::<Val::SelfId>();
<Val as ts_rs::TS>::visit_generics(v);
<Val::SelfId as ts_rs::TS>::visit_generics(v);
}
fn output_path() -> Option<std::path::PathBuf> {
Some(std::path::PathBuf::from("entry.ts"))
}
fn visit_dependencies(v: &mut impl ts_rs::TypeVisitor)
where
Self: 'static,
{
<Val as ts_rs::TS>::visit_dependencies(v);
<Val::SelfId as ts_rs::TS>::visit_dependencies(v);
}
fn dependencies(c: &ts_rs::Config) -> Vec<ts_rs::Dependency>
where
Self: 'static,
{
let mut d1 = <Val::SelfId as ts_rs::TS>::dependencies(c);
let d2 = <Val as ts_rs::TS>::dependencies(c);
d1.extend(d2);
d1
}
}
#[cfg(feature = "fake")]
impl<Val: Record, T> fake::Dummy<T> for Entry<Val>
where
Val: fake::Dummy<T>,
Val::SelfId: fake::Dummy<T>,
{
fn dummy_with_rng<R: rand::Rng + ?Sized>(config: &T, rng: &mut R) -> Self {
Self {
key: Val::SelfId::dummy_with_rng(config, rng),
val: Val::dummy_with_rng(config, rng),
}
}
}