use std::{hash::Hash, marker::PhantomData, sync::Arc};
use crate::{
cell::{CellImmutable, CellMutable},
cell_map::{CellMap, MapDiff},
subscription::SubscriptionGuard,
traits::CellValue,
};
pub(crate) mod properties;
pub(crate) mod reactive_map_impl;
pub mod share;
pub(crate) mod compiler;
pub use share::{MapQueryShareExt, SharedMapQuery};
pub(crate) type BoxedMapDiffSink<K, V> = Arc<dyn Fn(&MapDiff<K, V>) + Send + Sync>;
pub(crate) trait BuildQueryRuntime<K, V>: Sized + Send + Sync + 'static
where
K: CellValue + Hash + Eq,
V: CellValue,
{
fn build_into(
self,
cx: &mut compiler::CompileContext,
sink: BoxedMapDiffSink<K, V>,
) -> Vec<SubscriptionGuard>;
fn raw_source_identity(&self) -> Option<compiler::SourceIdentity> {
None
}
}
pub(crate) trait QueryRuntime: Sized + Send + Sync + 'static {
type Key: CellValue + Hash + Eq;
type Value: CellValue;
fn connect(
self,
cx: &mut compiler::CompileContext,
sink: BoxedMapDiffSink<Self::Key, Self::Value>,
) -> Vec<SubscriptionGuard>;
fn install_roots(
self,
cx: &mut compiler::CompileContext,
sink: BoxedMapDiffSink<Self::Key, Self::Value>,
) -> Vec<SubscriptionGuard> {
let mut guards = self.connect(cx, sink);
guards.extend(cx.activate());
guards
}
}
pub(crate) struct PlanRuntime<P, K, V> {
plan: P,
_types: PhantomData<fn() -> (K, V)>,
}
impl<P, K, V> QueryRuntime for PlanRuntime<P, K, V>
where
P: BuildQueryRuntime<K, V>,
K: CellValue + Hash + Eq,
V: CellValue,
{
type Key = K;
type Value = V;
fn connect(
self,
cx: &mut compiler::CompileContext,
sink: BoxedMapDiffSink<K, V>,
) -> Vec<SubscriptionGuard> {
self.plan.build_into(cx, sink)
}
}
pub(crate) trait CompileQuery<K, V>: Sized + Send + Sync + 'static
where
K: CellValue + Hash + Eq,
V: CellValue,
{
type Runtime: QueryRuntime<Key = K, Value = V>;
fn compile(self, _cx: &mut compiler::CompileContext) -> Self::Runtime;
fn raw_source_identity(&self) -> Option<compiler::SourceIdentity>;
}
impl<P, K, V> CompileQuery<K, V> for P
where
P: BuildQueryRuntime<K, V>,
K: CellValue + Hash + Eq,
V: CellValue,
{
type Runtime = PlanRuntime<P, K, V>;
fn compile(self, _cx: &mut compiler::CompileContext) -> Self::Runtime {
PlanRuntime {
plan: self,
_types: PhantomData,
}
}
fn raw_source_identity(&self) -> Option<compiler::SourceIdentity> {
BuildQueryRuntime::raw_source_identity(self)
}
}
pub(crate) fn compile_runtime_into<Q, K, V>(
query: Q,
cx: &mut compiler::CompileContext,
sink: BoxedMapDiffSink<K, V>,
) -> Vec<SubscriptionGuard>
where
Q: CompileQuery<K, V>,
K: CellValue + Hash + Eq,
V: CellValue,
{
let runtime = query.compile(cx);
runtime.connect(cx, sink)
}
#[allow(private_bounds)]
pub trait MapQuery: CompileQuery<Self::Key, Self::Value> + properties::PlanProperties {
type Key: CellValue + Hash + Eq;
type Value: CellValue;
#[track_caller]
fn materialize(self) -> CellMap<Self::Key, Self::Value, CellImmutable> {
let output = CellMap::<Self::Key, Self::Value, CellMutable>::new();
let weak = Arc::downgrade(&output.inner);
let sink = move |diff: &MapDiff<Self::Key, Self::Value>| {
let Some(inner) = weak.upgrade() else {
return;
};
let out: CellMap<Self::Key, Self::Value, CellMutable> = CellMap {
inner,
_marker: PhantomData,
};
out.apply_diff_owned(diff.clone());
};
let mut cx = compiler::CompileContext::default();
let runtime = self.compile(&mut cx);
let guards = runtime.install_roots(&mut cx, Arc::new(sink));
for g in guards {
output.own(g);
}
output.lock()
}
}