extend-docx 0.1.1

Rust parser, document model, and serializer for DOCX and legacy Word documents
Documentation
use std::sync::{
    mpsc::{sync_channel, SyncSender},
    Arc, OnceLock,
};

use arc_swap::ArcSwap;

type Update = Box<dyn FnOnce() + Send>;

fn writer() -> Option<&'static SyncSender<Update>> {
    static WRITER: OnceLock<Option<SyncSender<Update>>> = OnceLock::new();
    WRITER
        .get_or_init(|| {
            let (send, receive) = sync_channel::<Update>(8);
            std::thread::Builder::new()
                .name("docx-cache".into())
                .spawn(move || {
                    while let Ok(update) = receive.recv() {
                        let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(update));
                    }
                })
                .ok()?;
            Some(send)
        })
        .as_ref()
}

pub(super) struct Snapshot<T> {
    value: ArcSwap<T>,
}

impl<T: Send + Sync + 'static> Snapshot<T> {
    pub(super) fn new(value: T) -> Self {
        Self {
            value: ArcSwap::from_pointee(value),
        }
    }

    pub(super) fn read<R>(&self, read: impl FnOnce(&T) -> R) -> R {
        read(&self.value.load())
    }

    pub(super) fn reader(&'static self) -> arc_swap::cache::Cache<&'static ArcSwap<T>, Arc<T>> {
        arc_swap::cache::Cache::new(&self.value)
    }

    pub(super) fn publish(&'static self, update: impl FnOnce(&T) -> T + Send + 'static) -> bool {
        let Some(writer) = writer() else { return false };
        writer
            .try_send(Box::new(move || {
                let next = update(&self.value.load());
                self.value.store(Arc::new(next));
            }))
            .is_ok()
    }

    pub(super) fn update<R: Send + 'static>(
        &'static self,
        update: impl FnOnce(&T) -> (T, R) + Send + 'static,
    ) -> Option<R> {
        let writer = writer()?;
        let (send, receive) = sync_channel(1);
        writer
            .send(Box::new(move || {
                let (next, result) = update(&self.value.load());
                self.value.store(Arc::new(next));
                let _ = send.send(result);
            }))
            .ok()?;
        receive.recv().ok()
    }
}