use std::hash::Hash;
use std::sync::Arc;
use crate::error::{DbError, DbResult};
use crate::{CollectionMeta, Key, NoHook, TtlHook, ZeroMap};
use super::ClaimTarget;
use super::row::{UniqueOwner, UniqueRow};
pub trait UniqueNamespace:
CollectionMeta
+ Copy
+ zerocopy::FromBytes
+ zerocopy::IntoBytes
+ zerocopy::Immutable
+ Send
+ Sync
+ 'static
{
fn from_row(row: UniqueRow) -> Self;
fn row(&self) -> UniqueRow;
}
pub(crate) type Inner<N> = ZeroMap<
<N as CollectionMeta>::SelfId,
{ size_of::<UniqueRow>() },
N,
TtlHook<N, NoHook>,
crate::durability::Fixed,
>;
pub struct UniqueIndex<N>
where
N: UniqueNamespace,
N::SelfId: Key + Send + Sync + Hash + Eq,
{
inner: Arc<Inner<N>>,
}
impl<N> UniqueIndex<N>
where
N: UniqueNamespace,
N::SelfId: Key + Send + Sync + Hash + Eq,
{
pub(crate) fn from_inner(inner: Arc<Inner<N>>) -> Self {
Self { inner }
}
pub fn name(&self) -> &'static str {
N::NAME
}
pub fn owner_of(&self, key: &N::SelfId) -> Option<UniqueOwner> {
let row = self.inner.get(key)?.row();
row.is_well_formed().then(|| row.owner())
}
pub fn contains(&self, key: &N::SelfId) -> bool {
self.inner.contains(key)
}
}
impl<N> ClaimTarget for UniqueIndex<N>
where
N: UniqueNamespace,
N::SelfId: Key + Send + Sync + Hash + Eq,
{
fn collection_name(&self) -> &'static str {
N::NAME
}
fn write_row(&self, key: &[u8], row: UniqueRow) -> DbResult<()> {
if key.len() != size_of::<N::SelfId>() {
return Err(DbError::CorruptedEntry { offset: 0 });
}
let k = <N::SelfId as Key>::from_bytes(key);
self.inner.put(&k, &N::from_row(row))?;
Ok(())
}
fn delete_row(&self, key: &[u8]) -> DbResult<()> {
if key.len() != size_of::<N::SelfId>() {
return Err(DbError::CorruptedEntry { offset: 0 });
}
let k = <N::SelfId as Key>::from_bytes(key);
self.inner.delete(&k)?;
Ok(())
}
fn scan_rows(&self, f: &mut dyn FnMut(&[u8], UniqueRow) -> DbResult<()>) -> DbResult<()> {
let mut err: Option<DbError> = None;
self.inner.for_each(|k, v| {
if err.is_some() {
return;
}
if let Err(e) = f(k.as_bytes(), v.row()) {
err = Some(e);
}
});
match err {
Some(e) => Err(e),
None => Ok(()),
}
}
fn as_tx_participant(&self) -> Arc<dyn crate::txn::participant::TxParticipant> {
Arc::clone(&self.inner) as Arc<dyn crate::txn::participant::TxParticipant>
}
}
#[macro_export]
macro_rules! unique_index {
($name:ident, key = $key:ty, name = $lit:literal) => {
#[derive(
Clone,
Copy,
Debug,
PartialEq,
Eq,
$crate::zerocopy::FromBytes,
$crate::zerocopy::IntoBytes,
$crate::zerocopy::Immutable,
$crate::zerocopy::KnownLayout,
)]
#[zerocopy(crate = "armdb::zerocopy")]
#[repr(transparent)]
pub struct $name($crate::UniqueRow);
impl $crate::armour_core::GetType for $name {
const TYPE: $crate::armour_core::Typ =
<$crate::UniqueRow as $crate::armour_core::GetType>::TYPE;
}
impl $crate::CollectionMeta for $name {
type SelfId = $key;
const NAME: &'static str = $lit;
const TTL: Option<$crate::TtlPolicy<Self>> = Some($crate::TtlPolicy {
revision: 1,
deadline: |v: &Self, _k: &$key| v.0.deadline(),
});
}
impl $crate::UniqueNamespace for $name {
fn from_row(row: $crate::UniqueRow) -> Self {
Self(row)
}
fn row(&self) -> $crate::UniqueRow {
self.0
}
}
};
}