use {
crate::{
core::{Ident, SymbolPath, Value, Visibility},
partitions::{
records::ResolutionEntry, resolution::SymbolResolution, symbols::Symbols,
},
},
laburnum::database::{
HasPartition, PartitionWriteContextRef, RecordHandle,
storage::Partitions,
},
};
pub trait ResolutionWriteExt<P: Partitions> {
fn clear_resolutions<V, I, Path, S>(
&mut self,
prefix: &Path,
) where
V: Value<I>,
I: Ident,
Path: SymbolPath,
S: Visibility,
P::Stores: HasPartition<SymbolResolution<V, I, Path, S>>,
SymbolResolution<V, I, Path, S>: laburnum::database::partitions::SortKeyOf<P>
+ laburnum::database::Partition<
SortKey = Path,
IndexEntry = ResolutionEntry<V, I, Path, S>,
>
+ 'static;
fn write_resolution<V, I, Path, S>(
&mut self,
reference_path: Path,
target_path: Path,
target_handle: RecordHandle<Symbols<V, I, Path, S>>,
) where
V: Value<I>,
I: Ident,
Path: SymbolPath,
S: Visibility,
P::Stores: HasPartition<SymbolResolution<V, I, Path, S>>,
SymbolResolution<V, I, Path, S>: laburnum::database::partitions::SortKeyOf<P>
+ laburnum::database::Partition<
SortKey = Path,
IndexEntry = ResolutionEntry<V, I, Path, S>,
>;
fn write_inaccessible<V, I, Path, S>(
&mut self,
reference_path: Path,
target_path: Path,
target_handle: RecordHandle<Symbols<V, I, Path, S>>,
) where
V: Value<I>,
I: Ident,
Path: SymbolPath,
S: Visibility,
P::Stores: HasPartition<SymbolResolution<V, I, Path, S>>,
SymbolResolution<V, I, Path, S>: laburnum::database::partitions::SortKeyOf<P>
+ laburnum::database::Partition<
SortKey = Path,
IndexEntry = ResolutionEntry<V, I, Path, S>,
>;
fn write_unresolved<V, I, Path, S>(
&mut self,
reference_path: Path,
target_path: Path,
) where
V: Value<I>,
I: Ident,
Path: SymbolPath,
S: Visibility,
P::Stores: HasPartition<SymbolResolution<V, I, Path, S>>,
SymbolResolution<V, I, Path, S>: laburnum::database::partitions::SortKeyOf<P>
+ laburnum::database::Partition<
SortKey = Path,
IndexEntry = ResolutionEntry<V, I, Path, S>,
>;
}
impl<P: Partitions> ResolutionWriteExt<P> for PartitionWriteContextRef<'_, P> {
fn clear_resolutions<V, I, Path, S>(
&mut self,
prefix: &Path,
) where
V: Value<I>,
I: Ident,
Path: SymbolPath,
S: Visibility,
P::Stores: HasPartition<SymbolResolution<V, I, Path, S>>,
SymbolResolution<V, I, Path, S>: laburnum::database::partitions::SortKeyOf<P>
+ laburnum::database::Partition<
SortKey = Path,
IndexEntry = ResolutionEntry<V, I, Path, S>,
>
+ 'static,
{
self.clear_prefix::<SymbolResolution<V, I, Path, S>>(
prefix.clone(),
);
}
fn write_resolution<V, I, Path, S>(
&mut self,
reference_path: Path,
target_path: Path,
target_handle: RecordHandle<Symbols<V, I, Path, S>>,
) where
V: Value<I>,
I: Ident,
Path: SymbolPath,
S: Visibility,
P::Stores: HasPartition<SymbolResolution<V, I, Path, S>>,
SymbolResolution<V, I, Path, S>: laburnum::database::partitions::SortKeyOf<P>
+ laburnum::database::Partition<
SortKey = Path,
IndexEntry = ResolutionEntry<V, I, Path, S>,
>,
{
let entry = ResolutionEntry::resolved(target_path, target_handle);
self.index_entry::<SymbolResolution<V, I, Path, S>>(
reference_path.clone(),
entry,
);
}
fn write_inaccessible<V, I, Path, S>(
&mut self,
reference_path: Path,
target_path: Path,
target_handle: RecordHandle<Symbols<V, I, Path, S>>,
) where
V: Value<I>,
I: Ident,
Path: SymbolPath,
S: Visibility,
P::Stores: HasPartition<SymbolResolution<V, I, Path, S>>,
SymbolResolution<V, I, Path, S>: laburnum::database::partitions::SortKeyOf<P>
+ laburnum::database::Partition<
SortKey = Path,
IndexEntry = ResolutionEntry<V, I, Path, S>,
>,
{
let entry = ResolutionEntry::inaccessible(target_path, target_handle);
self.index_entry::<SymbolResolution<V, I, Path, S>>(
reference_path.clone(),
entry,
);
}
fn write_unresolved<V, I, Path, S>(
&mut self,
reference_path: Path,
target_path: Path,
) where
V: Value<I>,
I: Ident,
Path: SymbolPath,
S: Visibility,
P::Stores: HasPartition<SymbolResolution<V, I, Path, S>>,
SymbolResolution<V, I, Path, S>: laburnum::database::partitions::SortKeyOf<P>
+ laburnum::database::Partition<
SortKey = Path,
IndexEntry = ResolutionEntry<V, I, Path, S>,
>,
{
let entry = ResolutionEntry::<V, I, Path, S>::not_found(target_path);
self.index_entry::<SymbolResolution<V, I, Path, S>>(
reference_path.clone(),
entry,
);
}
}
#[cfg(test)]
mod tests {
use crate::{
ResolutionTarget, Symbol, SymbolVisibility,
partitions::{
SymbolResolution, Symbols,
test_support::{TestPartitions, TestStores},
},
test_helpers::{DV, SI, TP, test_span, test_span_cache},
};
use laburnum::database::{
HasPartition, PartitionWriteContextRef,
chunk::RecordWriter,
};
use super::ResolutionWriteExt;
use crate::SymboliqueWriteExt;
fn make_writer() -> RecordWriter<TestPartitions> {
RecordWriter::<TestPartitions>::new(laburnum::Ident::new("test"))
}
#[test]
fn write_resolution_round_trip() {
let mut writer = make_writer();
let mut cache = test_span_cache();
let span = test_span(&mut cache, 0);
{
let mut ctx = PartitionWriteContextRef::new(&mut writer);
let target_handle = ctx.write_symbol_definition::<DV, SI, TP, SymbolVisibility>(
"file|fn|target".to_string(),
span,
SI::new("target"),
None,
SymbolVisibility::Public,
);
ctx.write_resolution::<DV, SI, TP, SymbolVisibility>(
"file|ref|call_target".to_string(),
"file|fn|target".to_string(),
target_handle,
);
}
let chunk = writer.build();
let stores = chunk.storage();
let res_store =
<TestStores as HasPartition<SymbolResolution<DV, SI, TP>>>::store(
stores,
);
let entry = res_store.index_get(&"file|ref|call_target".to_string());
assert!(entry.is_some());
let entry = entry.as_ref();
assert_eq!(
entry.map(|e| e.target_path.as_str()),
Some("file|fn|target"),
);
let sym_store =
<TestStores as HasPartition<Symbols<DV, SI, TP>>>::store(stores);
let record = entry
.and_then(|e| e.target.handle())
.and_then(|h| sym_store.get_by_handle(&h))
.as_ref()
.and_then(|r| r.record())
.cloned();
match record {
Some(Symbol::Definition { name, .. }) => {
assert_eq!(name.as_str(), "target");
}
_ => panic!("expected Definition"),
}
}
#[test]
fn write_inaccessible_and_unresolved_round_trip() {
let mut writer = make_writer();
let mut cache = test_span_cache();
let span = test_span(&mut cache, 0);
{
let mut ctx = PartitionWriteContextRef::new(&mut writer);
let target_handle = ctx
.write_symbol_definition::<DV, SI, TP, SymbolVisibility>(
"file|fn|hidden".to_string(),
span,
SI::new("hidden"),
None,
SymbolVisibility::Private,
);
ctx.write_inaccessible::<DV, SI, TP, SymbolVisibility>(
"file|ref|to_hidden".to_string(),
"file|fn|hidden".to_string(),
target_handle,
);
ctx.write_unresolved::<DV, SI, TP, SymbolVisibility>(
"file|ref|to_missing".to_string(),
"file|fn|missing".to_string(),
);
}
let chunk = writer.build();
let stores = chunk.storage();
let res_store =
<TestStores as HasPartition<SymbolResolution<DV, SI, TP>>>::store(
stores,
);
let inaccessible =
res_store.index_get(&"file|ref|to_hidden".to_string()).expect("inaccessible entry");
assert!(matches!(
inaccessible.target,
ResolutionTarget::Inaccessible(_)
));
assert_eq!(inaccessible.target_path.as_str(), "file|fn|hidden");
assert!(
inaccessible.target.handle().is_some(),
"inaccessible retains the target handle for go-to-definition",
);
let missing =
res_store.index_get(&"file|ref|to_missing".to_string()).expect("not-found entry");
assert!(matches!(missing.target, ResolutionTarget::NotFound));
assert_eq!(missing.target_path.as_str(), "file|fn|missing");
assert!(missing.target.handle().is_none());
}
#[test]
fn clear_resolutions_records_prefix() {
let mut writer = make_writer();
{
let mut ctx = PartitionWriteContextRef::new(&mut writer);
ctx.clear_resolutions::<DV, SI, TP, SymbolVisibility>(
&"file|".to_string(),
);
}
let prefixes = writer.clear_prefixes();
assert_eq!(prefixes.len(), 1);
assert_eq!(
prefixes[0].1,
<SymbolResolution<DV, SI, TP, SymbolVisibility> as laburnum::database::partitions::SortKeyOf<TestPartitions>>::wrap_sort_key(
"file|".to_string(),
)
);
}
}