use crate::hooks::use_signal::{Signal, use_signal};
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub enum AsyncState<T, E> {
#[default]
Idle,
Loading,
Success(T),
Error(E),
}
impl<T, E> AsyncState<T, E> {
pub fn is_idle(&self) -> bool {
matches!(self, AsyncState::Idle)
}
pub fn is_loading(&self) -> bool {
matches!(self, AsyncState::Loading)
}
pub fn is_success(&self) -> bool {
matches!(self, AsyncState::Success(_))
}
pub fn is_error(&self) -> bool {
matches!(self, AsyncState::Error(_))
}
pub fn value(&self) -> Option<&T> {
match self {
AsyncState::Success(v) => Some(v),
_ => None,
}
}
pub fn error(&self) -> Option<&E> {
match self {
AsyncState::Error(e) => Some(e),
_ => None,
}
}
}
#[derive(Clone)]
pub struct AsyncHandle<T, E> {
state: Signal<AsyncState<T, E>>,
}
impl<T, E> AsyncHandle<T, E>
where
T: Clone + Send + Sync + 'static,
E: Clone + Send + Sync + 'static,
{
pub fn state(&self) -> AsyncState<T, E> {
self.state.get()
}
pub fn is_idle(&self) -> bool {
self.state.get().is_idle()
}
pub fn is_loading(&self) -> bool {
self.state.get().is_loading()
}
pub fn is_success(&self) -> bool {
self.state.get().is_success()
}
pub fn is_error(&self) -> bool {
self.state.get().is_error()
}
pub fn set_loading(&self) {
self.state.set(AsyncState::Loading);
}
pub fn set_success(&self, value: T) {
self.state.set(AsyncState::Success(value));
}
pub fn set_error(&self, error: E) {
self.state.set(AsyncState::Error(error));
}
pub fn reset(&self) {
self.state.set(AsyncState::Idle);
}
}
pub fn use_async_state<T, E>() -> AsyncHandle<T, E>
where
T: Clone + Send + Sync + Default + 'static,
E: Clone + Send + Sync + 'static,
{
let state = use_signal(|| AsyncState::Idle);
AsyncHandle { state }
}
pub fn use_async_state_with<T, E>(initial: AsyncState<T, E>) -> AsyncHandle<T, E>
where
T: Clone + Send + Sync + 'static,
E: Clone + Send + Sync + 'static,
{
let state = use_signal(|| initial);
AsyncHandle { state }
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_async_state() {
let state: AsyncState<String, String> = AsyncState::Idle;
assert!(state.is_idle());
assert!(!state.is_loading());
let state: AsyncState<String, String> = AsyncState::Loading;
assert!(state.is_loading());
let state: AsyncState<String, String> = AsyncState::Success("data".to_string());
assert!(state.is_success());
assert_eq!(state.value(), Some(&"data".to_string()));
let state: AsyncState<String, String> = AsyncState::Error("error".to_string());
assert!(state.is_error());
assert_eq!(state.error(), Some(&"error".to_string()));
}
#[test]
fn test_use_async_state_compiles() {
fn _test() {
let handle: AsyncHandle<String, String> = use_async_state();
handle.set_loading();
handle.set_success("done".to_string());
handle.reset();
}
}
}