async_component_core/
lib.rs1#![doc = include_str!("../README.md")]
2
3#[doc(hidden)]
4#[path = "exports.rs"]
5pub mod __private;
6pub mod context;
7
8use context::{with_current_context, StateContext};
9use futures_core::Stream;
10
11use std::{
12 ops::{Deref, DerefMut},
13 pin::Pin,
14 task::Poll,
15};
16
17pub trait AsyncComponent {
19 fn update_component(&mut self);
20}
21
22pub trait State {
26 type Output;
27
28 fn update(this: &mut Self) -> Option<Self::Output>;
29}
30
31#[derive(Debug)]
36pub struct StateCell<T> {
37 changed: bool,
38 inner: T,
39}
40
41impl<T> StateCell<T> {
42 pub fn new(inner: T) -> Self {
44 with_current_context(StateContext::signal);
45
46 Self {
47 changed: true,
48 inner,
49 }
50 }
51
52 pub fn invalidate(this: &mut Self) {
55 if !this.changed {
56 this.changed = true;
57 }
58
59 with_current_context(StateContext::signal);
60 }
61}
62
63impl<T> Deref for StateCell<T> {
64 type Target = T;
65
66 fn deref(&self) -> &Self::Target {
67 &self.inner
68 }
69}
70
71impl<T> DerefMut for StateCell<T> {
72 fn deref_mut(&mut self) -> &mut Self::Target {
73 StateCell::invalidate(self);
74
75 &mut self.inner
76 }
77}
78
79impl<T> State for StateCell<T> {
80 type Output = ();
81
82 fn update(this: &mut Self) -> Option<Self::Output> {
83 if this.changed {
84 this.changed = false;
85 Some(())
86 } else {
87 None
88 }
89 }
90}
91
92impl<T> From<T> for StateCell<T> {
93 fn from(inner: T) -> Self {
94 Self::new(inner)
95 }
96}
97
98impl<T: Default> Default for StateCell<T> {
99 fn default() -> Self {
100 Self::new(Default::default())
101 }
102}
103
104impl<T> Drop for StateCell<T> {
105 fn drop(&mut self) {
106 with_current_context(StateContext::signal);
107 }
108}
109
110#[derive(Debug)]
112pub struct StreamCell<T> {
113 inner: T,
114}
115
116impl<T: Stream> StreamCell<T> {
117 pub fn new(inner: T) -> Self {
118 with_current_context(StateContext::signal);
119 Self { inner }
120 }
121}
122
123impl<T: Stream + Unpin> State for StreamCell<T> {
124 type Output = T::Item;
125
126 fn update(this: &mut Self) -> Option<Self::Output> {
127 with_current_context(|cx| {
128 match Pin::new(&mut this.inner).poll_next(&mut cx.task_context()) {
129 Poll::Ready(Some(output)) => Some(output),
130 _ => None,
131 }
132 })
133 }
134}
135
136impl<T: Stream> From<T> for StreamCell<T> {
137 fn from(inner: T) -> Self {
138 Self::new(inner)
139 }
140}
141
142impl<T: Stream + Default> Default for StreamCell<T> {
143 fn default() -> Self {
144 Self::new(Default::default())
145 }
146}
147
148impl<T> Drop for StreamCell<T> {
149 fn drop(&mut self) {
150 with_current_context(StateContext::signal);
151 }
152}