vg-batteries 0.1.0

glimpse into my personal madness
Documentation
use core::pin::pin;
use std::sync::{Arc, RwLock, RwLockReadGuard};

use dioxus::prelude::*;
use futures::{Future, Stream, StreamExt};

use tokio::sync::{oneshot, watch};



use super::periodic::SendOnDrop;

pub async fn cancellable<T>(
    kill: oneshot::Receiver<()>,
    task: impl Future<Output = T>,
) -> anyhow::Result<T> {
    tokio::select! {
        output = task => Ok(output),
        _ = kill => anyhow::bail!("Task was cancelled"),
    }
}

pub fn use_stream<'a, T, F, S, P>(
    cx: &'a Scope<P>,
    max_values: usize,
    stream_creator: impl Send + Sync + 'static + Fn() -> F,
) -> RwLockReadGuard<'a, Option<Vec<T>>>
where
    T: Send + Sync + 'static,
    F: Send + Future<Output = S>,
    S: Send + Stream<Item = T>,
{
    let (value, sender_max_vals, receiver_max_vals, _) = cx.use_hook(|| {
        let value = Arc::new(RwLock::new(None));

        let update = cx.schedule_update();

        let (sender_cancel, receiver_cancel) = oneshot::channel();
        let (sender_max_vals, receiver_max_vals) = watch::channel(max_values);

        {
            let mut receiver_max_vals = receiver_max_vals.clone();
            let value = value.clone();
            tokio::spawn(cancellable(receiver_cancel, async move {
                let mut stream = pin!(stream_creator().await);
                let mut cnt = 0;

                *value.write().unwrap() = Some(Vec::new());

                loop {
                    while cnt >= *receiver_max_vals.borrow() {
                        let Ok(_) = receiver_max_vals.changed().await else {
                            return;
                        };
                    }

                    let Some(val) = stream.next().await else {
                        return;
                    };

                    let mut opt = value.write().unwrap();
                    let vec = opt.as_mut().unwrap();
                    vec.push(val);
                    cnt += 1;

                    update();
                }
            }));
        }

        (
            value,
            sender_max_vals,
            receiver_max_vals,
            SendOnDrop::new(sender_cancel),
        )
    });

    if *receiver_max_vals.borrow() != max_values {
        sender_max_vals.send(max_values).unwrap();
    }

    value.read().unwrap()
}

pub fn use_last_stream_value<'a, Arg, T, F, S, P>(
    cx: &'a Scope<P>,
    arg: Arg,
    stream_creator: impl Send + Sync + 'static + Fn(Arg) -> F,
) -> RwLockReadGuard<'a, Option<T>>
where
    T: Send + Sync + 'static,
    F: Send + Future<Output = S>,
    S: Send + Stream<Item = T>,
    Arg: std::fmt::Debug + Eq + Clone + Send + Sync + 'static,
{
    let thearg = arg.clone();

    let (value, sender_args, receiver_args, _) = cx.use_hook(|| {
        let value = Arc::new(RwLock::new(None));

        let update = cx.schedule_update();

        let (sender_cancel, receiver_cancel) = oneshot::channel();
        let (sender_args, receiver_args) = watch::channel(arg);

        {
            let mut receiver_args = receiver_args.clone();
            let value = value.clone();

            tokio::spawn(cancellable(receiver_cancel, async move {
                loop {
                    let current_arg = receiver_args.borrow().clone();
                    let mut stream = pin!(stream_creator(current_arg.clone()).await);

                    loop {
                        tokio::select! {
                            _ = receiver_args.changed() => {
                                break;
                            }
                            val = stream.next() => {
                                match val {
                                    None => {
                                        break;
                                    }
                                    Some(val) => {
                                        *value.write().unwrap() = Some(val);
                                        update();
                                    }
                                }
                            }
                        }
                    }

                    if current_arg == *receiver_args.borrow()
                        && receiver_args.changed().await.is_err()
                    {
                        return;
                    }
                }
            }));
        }

        (
            value,
            sender_args,
            receiver_args,
            SendOnDrop::new(sender_cancel),
        )
    });

    if *receiver_args.borrow() != thearg {
        sender_args.send(thearg).unwrap();
    }

    value.read().unwrap()
}