use {
crate::{
core::{Ident, Symbol, SymbolPath, SymbolSortKey, Value},
partitions::{file::FileSymbols, symbols::Symbols},
},
laburnum::database::{
HasPartition, PartitionKey, PartitionWriteContextRef, RecordHandle,
storage::Partitions,
},
};
super::symbol_writer_macro::define_symbol_writer! {
trait_name: SymboliqueWriteExt,
index_partition: FileSymbols,
clear_method: clear_file_symbols,
method_prefix: write_symbol_,
}
#[cfg(test)]
mod tests {
use crate::{
Symbol, SymbolVisibility,
partitions::{
FileSymbols, Symbols,
test_support::{TestPartitions, TestStores},
},
test_helpers::{DV, SI, TP, test_span, test_span_cache},
};
use laburnum::database::{
HasPartition, PartitionWriteContextRef,
chunk::RecordWriter,
};
use super::SymboliqueWriteExt;
fn make_writer() -> RecordWriter<TestPartitions> {
RecordWriter::<TestPartitions>::new(laburnum::Ident::new("test"))
}
#[test]
fn write_definition_round_trip() {
let mut writer = make_writer();
let mut cache = test_span_cache();
let span = test_span(&mut cache, 0);
let handle = {
let mut ctx = PartitionWriteContextRef::new(&mut writer);
ctx.write_symbol_definition::<DV, SI, TP>(
"file|fn|my_func".to_string(),
span,
SI::new("my_func"),
Some(DV::Integer(42)),
SymbolVisibility::Public,
)
};
let chunk = writer.build();
let stores = chunk.storage();
let sym_store =
<TestStores as HasPartition<Symbols<DV, SI, TP>>>::store(stores);
let record_ref = sym_store.get_by_handle(&handle);
assert!(record_ref.is_some());
let record = record_ref.as_ref().and_then(|r| r.record());
assert!(record.is_some());
match record {
Some(Symbol::Definition {
name, value, visibility,
}) => {
assert_eq!(name.as_str(), "my_func");
assert_eq!(*value, Some(DV::Integer(42)));
assert_eq!(*visibility, SymbolVisibility::Public);
}
_ => panic!("expected Definition"),
}
let idx_store =
<TestStores as HasPartition<FileSymbols<DV, SI, TP>>>::store(stores);
let entry = idx_store.index_get("file|fn|my_func");
assert!(entry.is_some());
}
#[test]
fn write_reference_round_trip() {
let mut writer = make_writer();
let mut cache = test_span_cache();
let span = test_span(&mut cache, 1);
let handle = {
let mut ctx = PartitionWriteContextRef::new(&mut writer);
ctx.write_symbol_reference::<DV, SI, TP>(
"file|ref|other".to_string(),
span,
Some(SI::new("other")),
"file|fn|other".to_string(),
false,
true,
)
};
let chunk = writer.build();
let stores = chunk.storage();
let sym_store =
<TestStores as HasPartition<Symbols<DV, SI, TP>>>::store(stores);
let record = sym_store
.get_by_handle(&handle)
.as_ref()
.and_then(|r| r.record())
.cloned();
match record {
Some(Symbol::Reference {
path: _,
name,
target_path,
is_absolute,
nameable,
}) => {
assert_eq!(name.as_ref().map(|n| n.as_str()), Some("other"));
assert_eq!(target_path, "file|fn|other");
assert!(!is_absolute);
assert!(nameable);
}
_ => panic!("expected Reference"),
}
let idx_store =
<TestStores as HasPartition<FileSymbols<DV, SI, TP>>>::store(stores);
assert!(idx_store.index_get("file|ref|other").is_some());
}
#[test]
fn write_keyword_round_trip() {
let mut writer = make_writer();
let mut cache = test_span_cache();
let span = test_span(&mut cache, 2);
let handle = {
let mut ctx = PartitionWriteContextRef::new(&mut writer);
ctx.write_symbol_keyword::<DV, SI, TP>(
"file|kw|if".to_string(),
span,
SI::new("if"),
)
};
let chunk = writer.build();
let stores = chunk.storage();
let sym_store =
<TestStores as HasPartition<Symbols<DV, SI, TP>>>::store(stores);
let record = sym_store
.get_by_handle(&handle)
.as_ref()
.and_then(|r| r.record())
.cloned();
match record {
Some(Symbol::Keyword { name }) => {
assert_eq!(name.as_str(), "if");
}
_ => panic!("expected Keyword"),
}
}
#[test]
fn write_value_round_trip() {
let mut writer = make_writer();
let mut cache = test_span_cache();
let span = test_span(&mut cache, 3);
let handle = {
let mut ctx = PartitionWriteContextRef::new(&mut writer);
ctx.write_symbol_value::<DV, SI, TP>(
"file|val|lit".to_string(),
span,
DV::Boolean(true),
)
};
let chunk = writer.build();
let stores = chunk.storage();
let sym_store =
<TestStores as HasPartition<Symbols<DV, SI, TP>>>::store(stores);
let record = sym_store
.get_by_handle(&handle)
.as_ref()
.and_then(|r| r.record())
.cloned();
match record {
Some(Symbol::Value { value }) => {
assert_eq!(value, DV::Boolean(true));
}
_ => panic!("expected Value"),
}
}
#[test]
fn write_scope_round_trip() {
let mut writer = make_writer();
let mut cache = test_span_cache();
let span = test_span(&mut cache, 4);
let handle = {
let mut ctx = PartitionWriteContextRef::new(&mut writer);
ctx.write_symbol_scope::<DV, SI, TP>(
"file|scope|block".to_string(),
span,
Some(DV::String("module".to_string())),
)
};
let chunk = writer.build();
let stores = chunk.storage();
let sym_store =
<TestStores as HasPartition<Symbols<DV, SI, TP>>>::store(stores);
let record = sym_store
.get_by_handle(&handle)
.as_ref()
.and_then(|r| r.record())
.cloned();
match record {
Some(Symbol::Scope { value }) => {
assert_eq!(value, Some(DV::String("module".to_string())));
}
_ => panic!("expected Scope"),
}
}
#[test]
fn write_import_round_trip() {
let mut writer = make_writer();
let mut cache = test_span_cache();
let span = test_span(&mut cache, 5);
let handle = {
let mut ctx = PartitionWriteContextRef::new(&mut writer);
ctx.write_symbol_import::<DV, SI, TP>(
"file|import|std".to_string(),
span,
"std::io".to_string(),
Some(SI::new("io")),
None,
)
};
let chunk = writer.build();
let stores = chunk.storage();
let sym_store =
<TestStores as HasPartition<Symbols<DV, SI, TP>>>::store(stores);
let record = sym_store
.get_by_handle(&handle)
.as_ref()
.and_then(|r| r.record())
.cloned();
match record {
Some(Symbol::Import { path, alias, value }) => {
assert_eq!(path, "std::io");
assert_eq!(alias.as_ref().map(|a| a.as_str()), Some("io"));
assert_eq!(value, None);
}
_ => panic!("expected Import"),
}
}
#[test]
fn write_multiple_symbols() {
let mut writer = make_writer();
let mut cache = test_span_cache();
{
let mut ctx = PartitionWriteContextRef::new(&mut writer);
ctx.write_symbol_definition::<DV, SI, TP>(
"file|fn|a".to_string(),
test_span(&mut cache, 0),
SI::new("a"),
None,
SymbolVisibility::Public,
);
ctx.write_symbol_definition::<DV, SI, TP>(
"file|fn|b".to_string(),
test_span(&mut cache, 1),
SI::new("b"),
None,
SymbolVisibility::Private,
);
ctx.write_symbol_keyword::<DV, SI, TP>(
"file|kw|let".to_string(),
test_span(&mut cache, 2),
SI::new("let"),
);
}
let chunk = writer.build();
let stores = chunk.storage();
let idx_store =
<TestStores as HasPartition<FileSymbols<DV, SI, TP>>>::store(stores);
assert!(idx_store.index_get("file|fn|a").is_some());
assert!(idx_store.index_get("file|fn|b").is_some());
assert!(idx_store.index_get("file|kw|let").is_some());
let all = idx_store.index_range("file|");
assert_eq!(all.len(), 3);
}
#[test]
fn clear_file_symbols_records_prefix() {
let mut writer = make_writer();
{
let mut ctx = PartitionWriteContextRef::new(&mut writer);
ctx.clear_file_symbols::<DV, SI, TP>(
&"file|".to_string(),
);
}
let prefixes = writer.clear_prefixes();
assert_eq!(prefixes.len(), 1);
assert_eq!(prefixes[0].1, "file|");
}
#[test]
fn identical_shapes_deduplicated() {
let mut writer = make_writer();
let mut cache = test_span_cache();
let (handle1, handle2) = {
let mut ctx = PartitionWriteContextRef::new(&mut writer);
let h1 = ctx.write_symbol_definition::<DV, SI, TP>(
"file|fn|dup1".to_string(),
test_span(&mut cache, 0),
SI::new("same_name"),
Some(DV::Integer(1)),
SymbolVisibility::Public,
);
let h2 = ctx.write_symbol_definition::<DV, SI, TP>(
"file|fn|dup2".to_string(),
test_span(&mut cache, 1),
SI::new("same_name"),
Some(DV::Integer(1)),
SymbolVisibility::Public,
);
(h1, h2)
};
assert_eq!(handle1.content_hash(), handle2.content_hash());
}
}