use core::fmt;
use std::path::Path;
use rpds::RedBlackTreeMapSync;
use typst::diag::FileResult;
use crate::{Bytes, FileChangeSet, FileSnapshot, ImmutPath, PathAccessModel};
#[derive(Debug, Clone)]
pub enum MemoryEvent {
Sync(FileChangeSet),
Update(FileChangeSet),
}
#[derive(Debug)]
pub struct UpstreamUpdateEvent {
pub invalidates: Vec<ImmutPath>,
pub opaque: Box<dyn std::any::Any + Send>,
}
#[derive(Debug)]
pub enum FilesystemEvent {
Update(FileChangeSet, bool),
UpstreamUpdate {
changeset: FileChangeSet,
upstream_event: Option<UpstreamUpdateEvent>,
},
}
impl FilesystemEvent {
pub fn split(self) -> (FileChangeSet, Option<UpstreamUpdateEvent>) {
match self {
FilesystemEvent::UpstreamUpdate {
changeset,
upstream_event,
} => (changeset, upstream_event),
FilesystemEvent::Update(changeset, ..) => (changeset, None),
}
}
pub fn split_with_is_sync(self) -> (FileChangeSet, bool, Option<UpstreamUpdateEvent>) {
match self {
FilesystemEvent::UpstreamUpdate {
changeset,
upstream_event,
} => (changeset, false, upstream_event),
FilesystemEvent::Update(changeset, is_sync) => (changeset, is_sync, None),
}
}
}
pub trait NotifyDeps: fmt::Debug + Send + Sync {
fn dependencies(&self, f: &mut dyn FnMut(&ImmutPath));
}
impl NotifyDeps for Vec<ImmutPath> {
fn dependencies(&self, f: &mut dyn FnMut(&ImmutPath)) {
for path in self.iter() {
f(path);
}
}
}
#[derive(Debug)]
pub enum NotifyMessage {
Settle,
SyncDependency(Box<dyn NotifyDeps>),
UpstreamUpdate(UpstreamUpdateEvent),
}
#[derive(Debug, Clone)]
pub struct NotifyAccessModel<M> {
files: RedBlackTreeMapSync<ImmutPath, FileSnapshot>,
pub inner: M,
}
impl<M: PathAccessModel> NotifyAccessModel<M> {
pub fn new(inner: M) -> Self {
Self {
files: RedBlackTreeMapSync::default(),
inner,
}
}
pub fn notify(&mut self, changeset: FileChangeSet) {
for path in changeset.removes {
self.files.remove_mut(&path);
}
for (path, contents) in changeset.inserts {
self.files.insert_mut(path, contents);
}
}
}
impl<M: PathAccessModel> PathAccessModel for NotifyAccessModel<M> {
#[inline]
fn reset(&mut self) {
self.inner.reset();
}
fn content(&self, src: &Path) -> FileResult<Bytes> {
if let Some(entry) = self.files.get(src) {
return entry.content().cloned();
}
self.inner.content(src)
}
}