#[macro_export]
macro_rules! declare_partition {
($(#[$attr:meta])* $name:ident $key:expr) => {
$crate::paste::paste! {
$(#[$attr])*
pub struct [<$name Partition>];
impl $crate::database::PartitionKey for [<$name Partition>] {
const KEY: $crate::Ident = $crate::Ident::new($key);
const KEY_NAME: Option<&'static str> = Some($key);
}
impl $crate::database::Partition for [<$name Partition>] {
type Record = [<$name Record>];
type IndexEntry = $crate::database::partitions::HandleEntry<Self>;
type SortKey = [<$name SortKey>];
fn index_entry_from_handle(
handle: $crate::database::RecordHandle<Self>,
) -> Self::IndexEntry {
$crate::database::partitions::HandleEntry::new(handle)
}
}
}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! define_dyn_partition {
(
$(#[$attr:meta])*
$partition:ident,
$key:expr,
$sort_key:ident,
$record_trait:ident
) => {
$(#[$attr])*
pub struct $partition;
impl $crate::database::PartitionKey for $partition {
const KEY: $crate::Ident = $crate::Ident::new($key);
const KEY_NAME: Option<&'static str> = Some($key);
}
impl $crate::database::DynPartition for $partition {
type DynSortKey = $sort_key;
type RecordConstraint = dyn $record_trait;
}
impl<R: $record_trait + $crate::record::Record>
$crate::database::DynPartitionRecord<$partition> for R
{}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! partition_stores {
() => { $crate::database::hlist::HNil };
($p:ty $(,)?) => {
$crate::database::hlist::HCons<
$crate::database::partitions::partition_store::PartitionStore<$p>,
$crate::database::hlist::HNil
>
};
($p:ty, $($rest:ty),+ $(,)?) => {
$crate::database::hlist::HCons<
$crate::database::partitions::partition_store::PartitionStore<$p>,
$crate::partition_stores![$($rest),+]
>
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! define_partitions_impl {
(
@partitions_block
stores = $stores:expr,
partition_key = $partition_key:ident,
content_hash = $content_hash:ident,
record_ref = $record_ref:ty,
idx = [$($idx:tt)*],
entry = ($variant:ident, $partition:ty),
rest = []
) => {
if $partition_key == <$partition as $crate::database::partitions::PartitionKey>::KEY {
if let Some(guard) = $crate::database::partitions::partition_store::HasPartitionAt::<$partition, $($idx)*>::store_at($stores).get(&$content_hash) {
if let Some(record) = guard.record() {
let record: <$partition as $crate::database::partitions::Partition>::Record = record.clone();
return Some(<$record_ref>::$variant(record));
}
}
}
};
(
@partitions_block
stores = $stores:expr,
partition_key = $partition_key:ident,
content_hash = $content_hash:ident,
record_ref = $record_ref:ty,
idx = [$($idx:tt)*],
entry = ($variant:ident, $partition:ty),
rest = [($next_v:ident, $next:ty) $(, ($rem_v:ident, $rem:ty))*]
) => {
if $partition_key == <$partition as $crate::database::partitions::PartitionKey>::KEY {
if let Some(guard) = $crate::database::partitions::partition_store::HasPartitionAt::<$partition, $($idx)*>::store_at($stores).get(&$content_hash) {
if let Some(record) = guard.record() {
let record: <$partition as $crate::database::partitions::Partition>::Record = record.clone();
return Some(<$record_ref>::$variant(record));
}
}
}
$crate::define_partitions_impl! {
@partitions_block
stores = $stores,
partition_key = $partition_key,
content_hash = $content_hash,
record_ref = $record_ref,
idx = [$crate::database::hlist::There<$($idx)*>],
entry = ($next_v, $next),
rest = [$(($rem_v, $rem)),*]
}
};
(
@index_remove_prefix_block
stores = $stores:expr,
partition_key = $partition_key:ident,
prefix = $prefix:ident,
idx = [$($idx:tt)*],
entry = ($_variant:ident, $partition:ty),
rest = []
) => {
if $partition_key == <$partition as $crate::database::partitions::PartitionKey>::KEY {
let store = $crate::database::partitions::partition_store::HasPartitionAt::<$partition, $($idx)*>::store_at($stores);
store.index_remove_prefix($prefix);
}
};
(
@index_remove_prefix_block
stores = $stores:expr,
partition_key = $partition_key:ident,
prefix = $prefix:ident,
idx = [$($idx:tt)*],
entry = ($_variant:ident, $partition:ty),
rest = [($next_v:ident, $next:ty) $(, ($rem_v:ident, $rem:ty))*]
) => {
if $partition_key == <$partition as $crate::database::partitions::PartitionKey>::KEY {
let store = $crate::database::partitions::partition_store::HasPartitionAt::<$partition, $($idx)*>::store_at($stores);
store.index_remove_prefix($prefix);
}
$crate::define_partitions_impl! {
@index_remove_prefix_block
stores = $stores,
partition_key = $partition_key,
prefix = $prefix,
idx = [$crate::database::hlist::There<$($idx)*>],
entry = ($next_v, $next),
rest = [$(($rem_v, $rem)),*]
}
};
(
@index_insert_block
stores = $stores:expr,
partition_key = $partition_key:ident,
sort_key = $sort_key:ident,
content_hash = $content_hash:ident,
idx = [$($idx:tt)*],
entry = ($_variant:ident, $partition:ty),
rest = []
) => {
if $partition_key == <$partition as $crate::database::partitions::PartitionKey>::KEY {
let store = $crate::database::partitions::partition_store::HasPartitionAt::<$partition, $($idx)*>::store_at($stores);
let handle = $crate::database::handle::RecordHandle::<$partition>::new($content_hash);
let entry = <$partition as $crate::database::partitions::Partition>::index_entry_from_handle(handle);
store.index_insert($sort_key.clone(), entry);
}
};
(
@index_insert_block
stores = $stores:expr,
partition_key = $partition_key:ident,
sort_key = $sort_key:ident,
content_hash = $content_hash:ident,
idx = [$($idx:tt)*],
entry = ($_variant:ident, $partition:ty),
rest = [($next_v:ident, $next:ty) $(, ($rem_v:ident, $rem:ty))*]
) => {
if $partition_key == <$partition as $crate::database::partitions::PartitionKey>::KEY {
let store = $crate::database::partitions::partition_store::HasPartitionAt::<$partition, $($idx)*>::store_at($stores);
let handle = $crate::database::handle::RecordHandle::<$partition>::new($content_hash);
let entry = <$partition as $crate::database::partitions::Partition>::index_entry_from_handle(handle);
store.index_insert($sort_key.clone(), entry);
}
$crate::define_partitions_impl! {
@index_insert_block
stores = $stores,
partition_key = $partition_key,
sort_key = $sort_key,
content_hash = $content_hash,
idx = [$crate::database::hlist::There<$($idx)*>],
entry = ($next_v, $next),
rest = [$(($rem_v, $rem)),*]
}
};
(
@index_range_block
stores = $stores:expr,
partition_key = $partition_key:ident,
prefix = $prefix:ident,
result = $result:ident,
idx = [$($idx:tt)*],
entry = ($_variant:ident, $partition:ty),
rest = []
) => {
if $partition_key == <$partition as $crate::database::partitions::PartitionKey>::KEY {
let store = $crate::database::partitions::partition_store::HasPartitionAt::<$partition, $($idx)*>::store_at($stores);
for (sort_key, entry) in store.index_range($prefix) {
if let Some(hash) = $crate::database::partitions::IndexEntry::primary_hash(&entry) {
$result.push(($partition_key, sort_key, hash));
}
}
}
};
(
@index_range_block
stores = $stores:expr,
partition_key = $partition_key:ident,
prefix = $prefix:ident,
result = $result:ident,
idx = [$($idx:tt)*],
entry = ($_variant:ident, $partition:ty),
rest = [($next_v:ident, $next:ty) $(, ($rem_v:ident, $rem:ty))*]
) => {
if $partition_key == <$partition as $crate::database::partitions::PartitionKey>::KEY {
let store = $crate::database::partitions::partition_store::HasPartitionAt::<$partition, $($idx)*>::store_at($stores);
for (sort_key, entry) in store.index_range($prefix) {
if let Some(hash) = $crate::database::partitions::IndexEntry::primary_hash(&entry) {
$result.push(($partition_key, sort_key, hash));
}
}
}
$crate::define_partitions_impl! {
@index_range_block
stores = $stores,
partition_key = $partition_key,
prefix = $prefix,
result = $result,
idx = [$crate::database::hlist::There<$($idx)*>],
entry = ($next_v, $next),
rest = [$(($rem_v, $rem)),*]
}
};
(
@index_less_than_block
stores = $stores:expr,
partition_key = $partition_key:ident,
value = $value:ident,
inclusive = $inclusive:ident,
result = $result:ident,
idx = [$($idx:tt)*],
entry = ($_variant:ident, $partition:ty),
rest = []
) => {
if $partition_key == <$partition as $crate::database::partitions::PartitionKey>::KEY {
let store = $crate::database::partitions::partition_store::HasPartitionAt::<$partition, $($idx)*>::store_at($stores);
for (sort_key, entry) in store.index_less_than($value, $inclusive) {
if let Some(hash) = $crate::database::partitions::IndexEntry::primary_hash(&entry) {
$result.push(($partition_key, sort_key, hash));
}
}
}
};
(
@index_less_than_block
stores = $stores:expr,
partition_key = $partition_key:ident,
value = $value:ident,
inclusive = $inclusive:ident,
result = $result:ident,
idx = [$($idx:tt)*],
entry = ($_variant:ident, $partition:ty),
rest = [($next_v:ident, $next:ty) $(, ($rem_v:ident, $rem:ty))*]
) => {
if $partition_key == <$partition as $crate::database::partitions::PartitionKey>::KEY {
let store = $crate::database::partitions::partition_store::HasPartitionAt::<$partition, $($idx)*>::store_at($stores);
for (sort_key, entry) in store.index_less_than($value, $inclusive) {
if let Some(hash) = $crate::database::partitions::IndexEntry::primary_hash(&entry) {
$result.push(($partition_key, sort_key, hash));
}
}
}
$crate::define_partitions_impl! {
@index_less_than_block
stores = $stores,
partition_key = $partition_key,
value = $value,
inclusive = $inclusive,
result = $result,
idx = [$crate::database::hlist::There<$($idx)*>],
entry = ($next_v, $next),
rest = [$(($rem_v, $rem)),*]
}
};
(
@index_greater_than_block
stores = $stores:expr,
partition_key = $partition_key:ident,
value = $value:ident,
inclusive = $inclusive:ident,
result = $result:ident,
idx = [$($idx:tt)*],
entry = ($_variant:ident, $partition:ty),
rest = []
) => {
if $partition_key == <$partition as $crate::database::partitions::PartitionKey>::KEY {
let store = $crate::database::partitions::partition_store::HasPartitionAt::<$partition, $($idx)*>::store_at($stores);
for (sort_key, entry) in store.index_greater_than($value, $inclusive) {
if let Some(hash) = $crate::database::partitions::IndexEntry::primary_hash(&entry) {
$result.push(($partition_key, sort_key, hash));
}
}
}
};
(
@index_greater_than_block
stores = $stores:expr,
partition_key = $partition_key:ident,
value = $value:ident,
inclusive = $inclusive:ident,
result = $result:ident,
idx = [$($idx:tt)*],
entry = ($_variant:ident, $partition:ty),
rest = [($next_v:ident, $next:ty) $(, ($rem_v:ident, $rem:ty))*]
) => {
if $partition_key == <$partition as $crate::database::partitions::PartitionKey>::KEY {
let store = $crate::database::partitions::partition_store::HasPartitionAt::<$partition, $($idx)*>::store_at($stores);
for (sort_key, entry) in store.index_greater_than($value, $inclusive) {
if let Some(hash) = $crate::database::partitions::IndexEntry::primary_hash(&entry) {
$result.push(($partition_key, sort_key, hash));
}
}
}
$crate::define_partitions_impl! {
@index_greater_than_block
stores = $stores,
partition_key = $partition_key,
value = $value,
inclusive = $inclusive,
result = $result,
idx = [$crate::database::hlist::There<$($idx)*>],
entry = ($next_v, $next),
rest = [$(($rem_v, $rem)),*]
}
};
(
@index_between_block
stores = $stores:expr,
partition_key = $partition_key:ident,
from = $from:ident,
to = $to:ident,
result = $result:ident,
idx = [$($idx:tt)*],
entry = ($_variant:ident, $partition:ty),
rest = []
) => {
if $partition_key == <$partition as $crate::database::partitions::PartitionKey>::KEY {
let store = $crate::database::partitions::partition_store::HasPartitionAt::<$partition, $($idx)*>::store_at($stores);
for (sort_key, entry) in store.index_between($from, $to) {
if let Some(hash) = $crate::database::partitions::IndexEntry::primary_hash(&entry) {
$result.push(($partition_key, sort_key, hash));
}
}
}
};
(
@index_between_block
stores = $stores:expr,
partition_key = $partition_key:ident,
from = $from:ident,
to = $to:ident,
result = $result:ident,
idx = [$($idx:tt)*],
entry = ($_variant:ident, $partition:ty),
rest = [($next_v:ident, $next:ty) $(, ($rem_v:ident, $rem:ty))*]
) => {
if $partition_key == <$partition as $crate::database::partitions::PartitionKey>::KEY {
let store = $crate::database::partitions::partition_store::HasPartitionAt::<$partition, $($idx)*>::store_at($stores);
for (sort_key, entry) in store.index_between($from, $to) {
if let Some(hash) = $crate::database::partitions::IndexEntry::primary_hash(&entry) {
$result.push(($partition_key, sort_key, hash));
}
}
}
$crate::define_partitions_impl! {
@index_between_block
stores = $stores,
partition_key = $partition_key,
from = $from,
to = $to,
result = $result,
idx = [$crate::database::hlist::There<$($idx)*>],
entry = ($next_v, $next),
rest = [$(($rem_v, $rem)),*]
}
};
(
@index_get_block
stores = $stores:expr,
partition_key = $partition_key:ident,
sort_key = $sort_key:ident,
idx = [$($idx:tt)*],
entry = ($_variant:ident, $partition:ty),
rest = []
) => {
if $partition_key == <$partition as $crate::database::partitions::PartitionKey>::KEY {
let store = $crate::database::partitions::partition_store::HasPartitionAt::<$partition, $($idx)*>::store_at($stores);
if let Some(entry) = store.index_get($sort_key) {
return $crate::database::partitions::IndexEntry::primary_hash(&entry);
}
}
};
(
@index_get_block
stores = $stores:expr,
partition_key = $partition_key:ident,
sort_key = $sort_key:ident,
idx = [$($idx:tt)*],
entry = ($_variant:ident, $partition:ty),
rest = [($next_v:ident, $next:ty) $(, ($rem_v:ident, $rem:ty))*]
) => {
if $partition_key == <$partition as $crate::database::partitions::PartitionKey>::KEY {
let store = $crate::database::partitions::partition_store::HasPartitionAt::<$partition, $($idx)*>::store_at($stores);
if let Some(entry) = store.index_get($sort_key) {
return $crate::database::partitions::IndexEntry::primary_hash(&entry);
}
}
$crate::define_partitions_impl! {
@index_get_block
stores = $stores,
partition_key = $partition_key,
sort_key = $sort_key,
idx = [$crate::database::hlist::There<$($idx)*>],
entry = ($next_v, $next),
rest = [$(($rem_v, $rem)),*]
}
};
(
@span_index_replace_block
stores = $stores:expr,
partition_key = $partition_key:ident,
uri = $uri:ident,
index = $index:ident,
idx = [$($idx:tt)*],
entry = ($_variant:ident, $partition:ty),
rest = []
) => {
if $partition_key == <$partition as $crate::database::partitions::PartitionKey>::KEY {
let store = $crate::database::partitions::partition_store::HasPartitionAt::<$partition, $($idx)*>::store_at($stores);
store.span_index_replace($uri, $index);
}
};
(
@span_index_replace_block
stores = $stores:expr,
partition_key = $partition_key:ident,
uri = $uri:ident,
index = $index:ident,
idx = [$($idx:tt)*],
entry = ($_variant:ident, $partition:ty),
rest = [($next_v:ident, $next:ty) $(, ($rem_v:ident, $rem:ty))*]
) => {
if $partition_key == <$partition as $crate::database::partitions::PartitionKey>::KEY {
let store = $crate::database::partitions::partition_store::HasPartitionAt::<$partition, $($idx)*>::store_at($stores);
store.span_index_replace($uri, $index);
} else {
$crate::define_partitions_impl! {
@span_index_replace_block
stores = $stores,
partition_key = $partition_key,
uri = $uri,
index = $index,
idx = [$crate::database::hlist::There<$($idx)*>],
entry = ($next_v, $next),
rest = [$(($rem_v, $rem)),*]
}
}
};
(
@span_index_remove_block
stores = $stores:expr,
partition_key = $partition_key:ident,
uri = $uri:ident,
idx = [$($idx:tt)*],
entry = ($_variant:ident, $partition:ty),
rest = []
) => {
if $partition_key == <$partition as $crate::database::partitions::PartitionKey>::KEY {
let store = $crate::database::partitions::partition_store::HasPartitionAt::<$partition, $($idx)*>::store_at($stores);
store.span_index_remove($uri);
}
};
(
@span_index_remove_block
stores = $stores:expr,
partition_key = $partition_key:ident,
uri = $uri:ident,
idx = [$($idx:tt)*],
entry = ($_variant:ident, $partition:ty),
rest = [($next_v:ident, $next:ty) $(, ($rem_v:ident, $rem:ty))*]
) => {
if $partition_key == <$partition as $crate::database::partitions::PartitionKey>::KEY {
let store = $crate::database::partitions::partition_store::HasPartitionAt::<$partition, $($idx)*>::store_at($stores);
store.span_index_remove($uri);
} else {
$crate::define_partitions_impl! {
@span_index_remove_block
stores = $stores,
partition_key = $partition_key,
uri = $uri,
idx = [$crate::database::hlist::There<$($idx)*>],
entry = ($next_v, $next),
rest = [$(($rem_v, $rem)),*]
}
}
};
(
@span_index_query_block
stores = $stores:expr,
partition_key = $partition_key:ident,
uri = $uri:ident,
byte_offset = $byte_offset:ident,
idx = [$($idx:tt)*],
entry = ($_variant:ident, $partition:ty),
rest = []
) => {
if $partition_key == <$partition as $crate::database::partitions::PartitionKey>::KEY {
let store = $crate::database::partitions::partition_store::HasPartitionAt::<$partition, $($idx)*>::store_at($stores);
return store.span_index_query($uri, $byte_offset);
}
};
(
@span_index_query_block
stores = $stores:expr,
partition_key = $partition_key:ident,
uri = $uri:ident,
byte_offset = $byte_offset:ident,
idx = [$($idx:tt)*],
entry = ($_variant:ident, $partition:ty),
rest = [($next_v:ident, $next:ty) $(, ($rem_v:ident, $rem:ty))*]
) => {
if $partition_key == <$partition as $crate::database::partitions::PartitionKey>::KEY {
let store = $crate::database::partitions::partition_store::HasPartitionAt::<$partition, $($idx)*>::store_at($stores);
return store.span_index_query($uri, $byte_offset);
} else {
$crate::define_partitions_impl! {
@span_index_query_block
stores = $stores,
partition_key = $partition_key,
uri = $uri,
byte_offset = $byte_offset,
idx = [$crate::database::hlist::There<$($idx)*>],
entry = ($next_v, $next),
rest = [$(($rem_v, $rem)),*]
}
}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! impl_has_partition {
(
stores = $stores:ty,
inner = $inner:ty,
idx = [$($idx:tt)*],
entry = ($_variant:ident, $partition:ty),
rest = []
) => {
impl $crate::database::partitions::partition_store::HasPartition<$partition> for $stores {
fn store(&self) -> &$crate::database::partitions::partition_store::PartitionStore<$partition> {
<$inner as $crate::database::partitions::partition_store::HasPartitionAt<$partition, $($idx)*>>::store_at(&self.0)
}
}
};
(
stores = $stores:ty,
inner = $inner:ty,
idx = [$($idx:tt)*],
entry = ($_variant:ident, $partition:ty),
rest = [($next_v:ident, $next:ty) $(, ($rem_v:ident, $rem:ty))*]
) => {
impl $crate::database::partitions::partition_store::HasPartition<$partition> for $stores {
fn store(&self) -> &$crate::database::partitions::partition_store::PartitionStore<$partition> {
<$inner as $crate::database::partitions::partition_store::HasPartitionAt<$partition, $($idx)*>>::store_at(&self.0)
}
}
$crate::impl_has_partition! {
stores = $stores,
inner = $inner,
idx = [$crate::database::hlist::There<$($idx)*>],
entry = ($next_v, $next),
rest = [$(($rem_v, $rem)),*]
}
};
}
#[macro_export]
macro_rules! define_partitions {
(
$name:ident,
partitions = [ $($p_entries:tt)* ]
$(, index = [ $($i_entries:tt)* ])?
$(,)?
) => {
$crate::define_partitions! {
@munch_partitions
name = $name,
entries = [],
readers = [],
sc_readers = [],
rest = [ $($p_entries)* ],
index_rest = [ $($($i_entries)*)? ],
lsp_map = []
}
};
(
@munch_partitions
name = $name:ident,
entries = [ $(($ev:ident, $et:ty)),* ],
readers = [ $($r:ident),* ],
sc_readers = [ $($sc:ident),* ],
rest = [ @with_source_cache $base:ident, $($rem:tt)* ],
index_rest = [ $($i_rem:tt)* ],
lsp_map = [ $($lm:tt)* ]
) => {
$crate::paste::paste! {
$crate::define_partitions! {
@munch_partitions
name = $name,
entries = [ $(($ev, $et),)* ($base, [<$base Partition>]) ],
readers = [ $($r),* ],
sc_readers = [ $($sc,)* $base ],
rest = [ $($rem)* ],
index_rest = [ $($i_rem)* ],
lsp_map = [ $($lm)* ]
}
}
};
(
@munch_partitions
name = $name:ident,
entries = [ $(($ev:ident, $et:ty)),* ],
readers = [ $($r:ident),* ],
sc_readers = [ $($sc:ident),* ],
rest = [ $base:ident, $($rem:tt)* ],
index_rest = [ $($i_rem:tt)* ],
lsp_map = [ $($lm:tt)* ]
) => {
$crate::paste::paste! {
$crate::define_partitions! {
@munch_partitions
name = $name,
entries = [ $(($ev, $et),)* ($base, [<$base Partition>]) ],
readers = [ $($r,)* $base ],
sc_readers = [ $($sc),* ],
rest = [ $($rem)* ],
index_rest = [ $($i_rem)* ],
lsp_map = [ $($lm)* ]
}
}
};
(
@munch_partitions
name = $name:ident,
entries = [ $(($ev:ident, $et:ty)),* ],
readers = [ $($r:ident),* ],
sc_readers = [ $($sc:ident),* ],
rest = [],
index_rest = [ $($i_rem:tt)* ],
lsp_map = [ $($lm:tt)* ]
) => {
$crate::define_partitions! {
@munch_index
name = $name,
entries = [ $(($ev, $et)),* ],
readers = [ $($r),* ],
sc_readers = [ $($sc),* ],
index_readers = [],
lsp_map = [ $($lm)* ],
rest = [ $($i_rem)* ]
}
};
(
@munch_index
name = $name:ident,
entries = [ $(($ev:ident, $et:ty)),* ],
readers = [ $($r:ident),* ],
sc_readers = [ $($sc:ident),* ],
index_readers = [ $($ir:ident),* ],
lsp_map = [ $(($lf:ident, $li:ident),)* ],
rest = [ $idx:ident $(=> lsp::$feature:ident)?, $($rem:tt)* ]
) => {
$crate::paste::paste! {
$crate::define_partitions! {
@munch_index
name = $name,
entries = [ $(($ev, $et),)* ($idx, [<$idx Partition>]) ],
readers = [ $($r),* ],
sc_readers = [ $($sc),* ],
index_readers = [ $($ir,)* $idx ],
lsp_map = [ $(($lf, $li),)* $(($feature, $idx),)? ],
rest = [ $($rem)* ]
}
}
};
(
@munch_index
name = $name:ident,
entries = [ $(($ev:ident, $et:ty)),* ],
readers = [ $($r:ident),* ],
sc_readers = [ $($sc:ident),* ],
index_readers = [ $($ir:ident),* ],
lsp_map = [ $(($lsp_feature:ident, $lsp_variant:ident),)* ],
rest = []
) => {
$crate::paste::paste! {
#[derive(Debug, Clone)]
pub enum [<$name Record>] {
Laburnum($crate::record::LaburnumRecord),
$( $r(<[<$r Partition>] as $crate::Partition>::Record), )*
$( $sc(<[<$sc Partition>] as $crate::Partition>::Record), )*
$( $ir(<[<$ir Partition>] as $crate::Partition>::Record), )*
}
$(
impl $crate::PartitionReader<[<$r Partition>]> for [<$name Partitions>] {
fn as_record(
record_ref: &[<$name Record>],
) -> Option<<[<$r Partition>] as $crate::Partition>::Record> {
match record_ref {
[<$name Record>]::$r(record) => Some(record.clone()),
_ => None,
}
}
}
)*
$(
impl $crate::PartitionReader<[<$sc Partition>]> for [<$name Partitions>] {
fn as_record(
record_ref: &[<$name Record>],
) -> Option<<[<$sc Partition>] as $crate::Partition>::Record> {
match record_ref {
[<$name Record>]::$sc(record) => Some(record.clone()),
_ => None,
}
}
}
)*
impl $crate::record::LaburnumRecordRef for [<$name Record>] {
fn as_laburnum_record(&self) -> Option<&$crate::record::LaburnumRecord> {
match self {
| [<$name Record>]::Laburnum(lr) => Some(lr),
| _ => None,
}
}
$(
$crate::define_partitions!(@lsp_method_override
record_enum = [<$name Record>],
feature = $lsp_feature,
variant = $lsp_variant
);
)*
fn serialize_with_source_cache<P, T, Ser>(
&self,
_source_cache: &$crate::source::SourceCache<P, T>,
serializer: Ser,
) -> Result<Ser::Ok, Ser::Error>
where
P: $crate::database::storage::Partitions,
T: $crate::protocol::lsp::LanguageServer<P>,
Ser: serde::Serializer,
{
match self {
| [<$name Record>]::Laburnum(record) => {
serde::Serialize::serialize(record, serializer)
},
$(
| [<$name Record>]::$r(record) => {
serde::Serialize::serialize(record, serializer)
},
)*
$(
| [<$name Record>]::$sc(record) => {
$crate::record::SerializeWithSourceCache::serialize_with_source_cache(
record, _source_cache, serializer,
)
},
)*
$(
| [<$name Record>]::$ir(_) => {
unreachable!("Index-only partitions do not produce CAS records")
},
)*
}
}
}
impl serde::Serialize for [<$name Record>] {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
#[allow(unused_imports, reason = "conditionally used when the macro is invoked with scalar variants ($sc)")]
use serde::ser::SerializeMap;
match self {
| [<$name Record>]::Laburnum(record) => {
serde::Serialize::serialize(record, serializer)
},
$(
| [<$name Record>]::$r(record) => {
serde::Serialize::serialize(record, serializer)
},
)*
$(
| [<$name Record>]::$sc(_) => {
let mut map = serializer.serialize_map(Some(1))?;
map.serialize_entry("type", stringify!($sc))?;
map.end()
},
)*
$(
| [<$name Record>]::$ir(record) => {
$crate::define_partitions!(
@serialize_index_variant
map = serializer,
name = $ir,
record = record
)
},
)*
}
}
}
}
$crate::define_partitions!(
@core
name = $name,
entries = [ $(($ev, $et)),* ],
);
};
(@lsp_method_override
record_enum = $re:ident,
feature = diagnostic,
variant = $v:ident
) => {
fn as_dyn_diagnostic(
&self,
) -> Option<&dyn $crate::partitions::diagnostics::DiagnosticRecord> {
match self {
| $re::$v(record) => Some(record),
| _ => None,
}
}
};
(@lsp_method_override
record_enum = $re:ident,
feature = document_symbol,
variant = $v:ident
) => {
fn as_document_symbol(
&self,
) -> Option<&dyn $crate::partitions::document_symbols::DocumentSymbolRecord> {
match self {
| $re::$v(record) => Some(record),
| _ => None,
}
}
};
(@lsp_method_override
record_enum = $re:ident,
feature = text_document_position,
variant = $v:ident
) => {
fn as_text_document_position(
&self,
) -> Option<&dyn $crate::partitions::text_document_position::TextDocumentPositionRecord> {
match self {
| $re::$v(record) => Some(record),
| _ => None,
}
}
};
(@lsp_method_override
record_enum = $re:ident,
feature = text_document_reference,
variant = $v:ident
) => {
fn as_text_document_reference(
&self,
) -> Option<&dyn $crate::partitions::text_document_references::TextDocumentReferenceRecord> {
match self {
| $re::$v(record) => Some(record),
| _ => None,
}
}
};
(@serialize_index_variant
map = $serializer:expr,
name = $name:ident,
record = $record:expr
) => {
{
let _ = $serializer;
let _ = $record;
unreachable!("Index-only partitions do not produce CAS records")
}
};
(
@core
name = $name:ident,
entries = [($first_v:ident, $first:ty) $(, ($rest_v:ident, $rest:ty))*] $(,)?
) => {
$crate::paste::paste! {
pub struct [<$name Partitions>];
type [<$name StoresInner>] = $crate::partition_stores![$first $(, $rest)*];
#[repr(transparent)]
pub struct [<$name Stores>]([<$name StoresInner>]);
impl std::ops::Deref for [<$name Stores>] {
type Target = [<$name StoresInner>];
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl std::ops::DerefMut for [<$name Stores>] {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl $crate::database::partitions::partition_store::RefcountOps for [<$name Stores>] {
fn increment_refcount(&self, partition: $crate::Ident, hash: $crate::ContentHash) {
$crate::database::partitions::partition_store::RefcountOps::increment_refcount(&self.0, partition, hash)
}
fn decrement_refcount(&self, partition: $crate::Ident, hash: $crate::ContentHash) -> usize {
$crate::database::partitions::partition_store::RefcountOps::decrement_refcount(&self.0, partition, hash)
}
fn remove_record(&self, partition: $crate::Ident, hash: $crate::ContentHash) -> bool {
$crate::database::partitions::partition_store::RefcountOps::remove_record(&self.0, partition, hash)
}
fn get_refcount(&self, partition: $crate::Ident, hash: $crate::ContentHash) -> usize {
$crate::database::partitions::partition_store::RefcountOps::get_refcount(&self.0, partition, hash)
}
}
impl $crate::database::partitions::partition_store::BluegumStores for [<$name Stores>] {
fn bluegum_partition_nodes(
&self,
state: &(dyn $crate::SpanResolver + 'static),
) -> Vec<bluegum::Builder> {
$crate::database::partitions::partition_store::BluegumStores::bluegum_partition_nodes(&self.0, state)
}
}
impl $crate::database::partitions::partition_store::CollectCascadingRefs<[<$name Partitions>]> for [<$name Stores>] {
fn collect_cascading_refs(
&self,
partition: $crate::Ident,
hash: $crate::ContentHash,
) -> Vec<($crate::Ident, $crate::ContentHash)> {
$crate::database::partitions::partition_store::CollectCascadingRefs::<[<$name Partitions>]>::collect_cascading_refs(&self.0, partition, hash)
}
}
impl $crate::database::storage::Partitions for [<$name Partitions>] {
type Stores = [<$name Stores>];
type RecordRef<'a> = [<$name Record>] where Self: 'a;
fn new_stores() -> Self::Stores {
[<$name Stores>](
<[<$name StoresInner>] as $crate::database::partitions::partition_store::NewStores>::new_stores()
)
}
fn get_any(
stores: &Self::Stores,
partition_key: $crate::Ident,
content_hash: $crate::ContentHash,
) -> Option<Self::RecordRef<'_>> {
$crate::define_partitions_impl! {
@partitions_block
stores = &stores.0,
partition_key = partition_key,
content_hash = content_hash,
record_ref = [<$name Record>],
idx = [$crate::database::hlist::Here],
entry = ($first_v, $first),
rest = [$(($rest_v, $rest)),*]
}
None
}
fn partition_keys() -> &'static [$crate::Ident] {
use $crate::database::partitions::PartitionKey;
static KEYS: std::sync::LazyLock<Vec<$crate::Ident>> = std::sync::LazyLock::new(|| {
vec![
<$first as PartitionKey>::KEY
$(, <$rest as PartitionKey>::KEY)*
]
});
&KEYS
}
fn merge_stores(
global_stores: &Self::Stores,
source: &Self::Stores,
epoch: $crate::database::GenerationEpoch,
) -> $crate::database::MergeResult {
<[<$name StoresInner>] as $crate::database::partitions::partition_store::MergeFrom>::merge_from(&global_stores.0, &source.0, epoch)
}
fn collect_index_hashes(stores: &Self::Stores) -> Vec<$crate::database::ContentHashRef> {
let mut result = Vec::new();
<[<$name StoresInner>] as $crate::database::partitions::partition_store::CollectIndexHashes>::collect_index_hashes(&stores.0, &mut result);
result
}
fn index_remove_prefix(stores: &Self::Stores, partition_key: $crate::Ident, prefix: &str) {
$crate::define_partitions_impl! {
@index_remove_prefix_block
stores = &stores.0,
partition_key = partition_key,
prefix = prefix,
idx = [$crate::database::hlist::Here],
entry = ($first_v, $first),
rest = [$(($rest_v, $rest)),*]
}
}
fn index_insert(
stores: &Self::Stores,
partition_key: $crate::Ident,
sort_key: String,
content_hash: $crate::ContentHash,
) {
$crate::define_partitions_impl! {
@index_insert_block
stores = &stores.0,
partition_key = partition_key,
sort_key = sort_key,
content_hash = content_hash,
idx = [$crate::database::hlist::Here],
entry = ($first_v, $first),
rest = [$(($rest_v, $rest)),*]
}
}
fn index_range(
stores: &Self::Stores,
partition_key: $crate::Ident,
prefix: &str,
) -> Vec<($crate::Ident, String, $crate::ContentHash)> {
let mut result = Vec::new();
$crate::define_partitions_impl! {
@index_range_block
stores = &stores.0,
partition_key = partition_key,
prefix = prefix,
result = result,
idx = [$crate::database::hlist::Here],
entry = ($first_v, $first),
rest = [$(($rest_v, $rest)),*]
}
result
}
fn index_get(
stores: &Self::Stores,
partition_key: $crate::Ident,
sort_key: &str,
) -> Option<$crate::ContentHash> {
$crate::define_partitions_impl! {
@index_get_block
stores = &stores.0,
partition_key = partition_key,
sort_key = sort_key,
idx = [$crate::database::hlist::Here],
entry = ($first_v, $first),
rest = [$(($rest_v, $rest)),*]
}
None
}
fn index_less_than(
stores: &Self::Stores,
partition_key: $crate::Ident,
value: &str,
inclusive: bool,
) -> Vec<($crate::Ident, String, $crate::ContentHash)> {
let mut result = Vec::new();
$crate::define_partitions_impl! {
@index_less_than_block
stores = &stores.0,
partition_key = partition_key,
value = value,
inclusive = inclusive,
result = result,
idx = [$crate::database::hlist::Here],
entry = ($first_v, $first),
rest = [$(($rest_v, $rest)),*]
}
result
}
fn index_greater_than(
stores: &Self::Stores,
partition_key: $crate::Ident,
value: &str,
inclusive: bool,
) -> Vec<($crate::Ident, String, $crate::ContentHash)> {
let mut result = Vec::new();
$crate::define_partitions_impl! {
@index_greater_than_block
stores = &stores.0,
partition_key = partition_key,
value = value,
inclusive = inclusive,
result = result,
idx = [$crate::database::hlist::Here],
entry = ($first_v, $first),
rest = [$(($rest_v, $rest)),*]
}
result
}
fn index_between(
stores: &Self::Stores,
partition_key: $crate::Ident,
from: &str,
to: &str,
) -> Vec<($crate::Ident, String, $crate::ContentHash)> {
let mut result = Vec::new();
$crate::define_partitions_impl! {
@index_between_block
stores = &stores.0,
partition_key = partition_key,
from = from,
to = to,
result = result,
idx = [$crate::database::hlist::Here],
entry = ($first_v, $first),
rest = [$(($rest_v, $rest)),*]
}
result
}
fn span_index_replace(
stores: &Self::Stores,
partition_key: $crate::Ident,
uri: $crate::Uri,
index: $crate::database::partitions::span_index::SpanIndex,
) {
$crate::define_partitions_impl! {
@span_index_replace_block
stores = &stores.0,
partition_key = partition_key,
uri = uri,
index = index,
idx = [$crate::database::hlist::Here],
entry = ($first_v, $first),
rest = [$(($rest_v, $rest)),*]
}
}
fn span_index_remove(
stores: &Self::Stores,
partition_key: $crate::Ident,
uri: &$crate::Uri,
) {
$crate::define_partitions_impl! {
@span_index_remove_block
stores = &stores.0,
partition_key = partition_key,
uri = uri,
idx = [$crate::database::hlist::Here],
entry = ($first_v, $first),
rest = [$(($rest_v, $rest)),*]
}
}
fn span_index_query(
stores: &Self::Stores,
partition_key: $crate::Ident,
uri: &$crate::Uri,
byte_offset: u64,
) -> Option<$crate::ContentHash> {
$crate::define_partitions_impl! {
@span_index_query_block
stores = &stores.0,
partition_key = partition_key,
uri = uri,
byte_offset = byte_offset,
idx = [$crate::database::hlist::Here],
entry = ($first_v, $first),
rest = [$(($rest_v, $rest)),*]
}
None
}
fn gc_mark_tick(
gc: &$crate::database::gc::GarbageCollector,
stores: &Self::Stores,
budget: usize,
) -> bool {
let _ = gc.mark_tick_partition::<[<$name Partitions>], $first>(stores, budget);
$(
let _ = gc.mark_tick_partition::<[<$name Partitions>], $rest>(stores, budget);
)*
gc.gray_queue_len() == 0
}
fn gc_sweep(
gc: &$crate::database::gc::GarbageCollector,
stores: &Self::Stores,
) {
gc.sweep_partition::<[<$name Partitions>], $first>(stores);
$(
gc.sweep_partition::<[<$name Partitions>], $rest>(stores);
)*
}
}
$crate::impl_has_partition! {
stores = [<$name Stores>],
inner = [<$name StoresInner>],
idx = [$crate::database::hlist::Here],
entry = ($first_v, $first),
rest = [$(($rest_v, $rest)),*]
}
}
};
}