vg-batteries 0.1.0

glimpse into my personal madness
Documentation
use std::{mem::ManuallyDrop, sync::Arc, time::Duration};

use parking_lot::{MappedRwLockReadGuard, RwLock, RwLockReadGuard};

use dioxus::prelude::Scope;

use futures::Future;
use tokio::sync::oneshot::{self, Sender};

pub struct SendOnDrop {
    sender: ManuallyDrop<Sender<()>>,
}

impl SendOnDrop {
    pub fn new(sender: Sender<()>) -> Self {
        Self {
            sender: ManuallyDrop::new(sender),
        }
    }
}

impl Drop for SendOnDrop {
    fn drop(&mut self) {
        let sender = unsafe { ManuallyDrop::take(&mut self.sender) };
        sender.send(()).unwrap();
    }
}

pub fn use_periodic_update(cx: Scope, interval: Duration) {
    cx.use_hook(|| {
        let update = cx.schedule_update();

        let (sender, mut receiver) = oneshot::channel();

        tokio::spawn(async move {
            loop {
                tokio::select! {
                    _ = &mut receiver => break,
                    _ = tokio::time::sleep(interval) => {
                        update();
                    }
                }
            }
        });

        SendOnDrop {
            sender: ManuallyDrop::new(sender),
        }
    });
}

pub fn use_periodic_update_future<'a, T, F>(
    cx: &'a Scope,
    interval: Duration,
    future_fabric: impl Send + Sync + 'static + Fn() -> F,
) -> Option<MappedRwLockReadGuard<'a, T>>
where
    T: Send + Sync + 'static,
    F: Send + Future<Output = T>,
{
    let (value, _) = cx.use_hook(|| {
        let value = Arc::new(RwLock::<Option<T>>::new(None));

        let update = cx.schedule_update();

        let (sender, mut receiver) = oneshot::channel();

        {
            let value = value.clone();
            tokio::spawn(async move {
                loop {
                    let val = Some(future_fabric().await);
                    *value.write() = val;

                    tokio::select! {
                        _ = &mut receiver => break,
                        _ = tokio::time::sleep(interval) => {
                            update();
                        }
                    }
                }
            });
        }

        (
            value,
            SendOnDrop {
                sender: ManuallyDrop::new(sender),
            },
        )
    });

    let opt_v = value.read();
    if opt_v.is_none() {
        None
    } else {
        return Some(RwLockReadGuard::map(opt_v, |v| v.as_ref().unwrap()));
    }
}