use {
crate::{
Ident,
database::{
Partition,
PartitionKey,
storage::{
PartitionsBuilder,
RecordStorage,
},
},
hash::ContentHasher,
record::{
LaburnumRecord,
Record,
},
scheduler::Scheduler,
},
std::{
sync::Arc,
time::Duration,
},
};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize)]
pub struct TestIndex(usize);
#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize)]
pub struct TestRecordData {
pub value: String,
pub count: usize,
}
impl TestRecordData {
pub fn new(value: String, count: usize) -> Self {
Self { value, count }
}
}
impl Record for TestRecordData {
fn content_hash(&self) -> crate::ContentHash {
crate::record::hash_record(self)
}
}
impl bluegum::Bluegum for TestRecordData {
fn node(&self, b: &mut bluegum::Builder) {
b.name("TestRecordData")
.field("value", &self.value)
.field("count", self.count);
}
}
impl bluegum::BluegumWithState<dyn crate::SpanResolver> for TestRecordData {}
impl<P: crate::database::storage::Partitions> crate::record::CollectReferences<P>
for TestRecordData
{
}
impl crate::record::LaburnumRecordRef for &TestRecordData {
fn as_laburnum_record(&self) -> Option<&LaburnumRecord> {
None
}
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,
{
use serde::Serialize;
self.serialize(serializer)
}
}
impl From<LaburnumRecord> for TestRecordData {
fn from(_record: LaburnumRecord) -> Self {
panic!("TestRecordData does not support LaburnumRecord conversion")
}
}
#[derive(Debug)]
pub struct TestStorage {
records: Vec<TestRecordData>,
}
impl RecordStorage for TestStorage {
type Builder = TestStorageBuilder;
type Index = TestIndex;
type RecordRef<'a> = &'a TestRecordData;
fn get(&self, idx: &Self::Index) -> Option<Self::RecordRef<'_>> {
self.records.get(idx.0)
}
fn hash_contents(&self, hasher: &mut ContentHasher) {
for record in &self.records {
hasher.update(record.value.as_bytes());
hasher.update(&record.count.to_le_bytes());
}
}
}
#[derive(Default)]
pub struct TestStorageBuilder {
records: Vec<TestRecordData>,
}
impl PartitionsBuilder for TestStorageBuilder {
type Record = TestRecordData;
type Storage = TestStorage;
fn push(&mut self, record: Self::Record) -> TestIndex {
let idx = TestIndex(self.records.len());
self.records.push(record);
idx
}
fn build(self) -> Self::Storage {
TestStorage {
records: self.records,
}
}
}
pub struct TestPartition;
impl PartitionKey for TestPartition {
const KEY: Ident = Ident::new("scheduler_test::records");
}
impl Partition for TestPartition {
type Record = TestRecordData;
type IndexEntry = crate::database::partitions::HandleEntry<Self>;
type SortKey = String;
fn index_entry_from_handle(
handle: crate::database::RecordHandle<Self>,
) -> Self::IndexEntry {
crate::database::partitions::HandleEntry::new(handle)
}
}
crate::define_partitions! {
Test,
partitions = [Test,],
}
pub fn test_scheduler() -> (
Arc<Scheduler<TestPartitions, crate::server::LaburnumLanguageServer>>,
crate::connect::ipc::Connection,
) {
let (server_conn, client_conn) = crate::connect::ipc::Connection::memory();
let filesystems = std::sync::Arc::new(parking_lot::RwLock::new(Vec::new()));
let source_cache =
std::sync::Arc::new(parking_lot::RwLock::new(crate::SourceCache::new()));
let config = crate::scheduler::SchedulerConfiguration {
rpc_response_capacity: 100,
enable_periodic_gc: false,
};
let scheduler = Scheduler::new_with_config(
server_conn,
std::sync::Arc::new(crate::server::LaburnumLanguageServer),
filesystems,
source_cache,
1,
config,
);
(scheduler, client_conn)
}
pub async fn wait_for<F: Fn() -> bool>(
condition: F,
timeout: Duration,
) -> bool {
let start = std::time::Instant::now();
while start.elapsed() < timeout {
if condition() {
return true;
}
futures_lite::future::yield_now().await;
}
false
}
pub async fn wait_for_value<T, F: Fn() -> Option<T>>(
condition: F,
timeout: Duration,
) -> Option<T> {
let start = std::time::Instant::now();
while start.elapsed() < timeout {
if let Some(value) = condition() {
return Some(value);
}
futures_lite::future::yield_now().await;
}
None
}