1use std::{any::Any, marker::PhantomData, ptr, sync::Arc};
9
10use crate::{
11 runtime::{
12 FunctorHandle, invoke_callback_handle, invoke_callback_with_handle,
13 invoke_render_slot_handle, invoke_render_slot_with_handle, remember_callback_handle,
14 remember_callback_with_handle, remember_render_slot_handle,
15 remember_render_slot_with_handle, track_render_slot_read_dependency,
16 },
17 tessera,
18};
19
20pub struct Slot<F: ?Sized> {
25 inner: Arc<F>,
26}
27
28impl<F: ?Sized> Slot<F> {
29 pub fn from_shared(handler: Arc<F>) -> Self {
31 Self { inner: handler }
32 }
33
34 pub fn shared(&self) -> Arc<F> {
36 Arc::clone(&self.inner)
37 }
38}
39
40impl<F: ?Sized> Clone for Slot<F> {
41 fn clone(&self) -> Self {
42 Self {
43 inner: Arc::clone(&self.inner),
44 }
45 }
46}
47
48impl<F: ?Sized> PartialEq for Slot<F> {
49 fn eq(&self, other: &Self) -> bool {
50 Arc::ptr_eq(&self.inner, &other.inner)
51 }
52}
53
54impl<F: ?Sized> Eq for Slot<F> {}
55
56#[derive(Clone, Copy)]
68pub struct Callback {
69 repr: CallbackRepr,
70}
71
72#[derive(Clone, Copy, Eq, PartialEq)]
73enum CallbackRepr {
74 Noop,
75 Handle(FunctorHandle),
76}
77
78impl Callback {
79 #[track_caller]
83 pub fn new<F>(handler: F) -> Self
84 where
85 F: Fn() + Send + Sync + 'static,
86 {
87 Self {
88 repr: CallbackRepr::Handle(remember_callback_handle(handler)),
89 }
90 }
91
92 pub const fn noop() -> Self {
94 Self {
95 repr: CallbackRepr::Noop,
96 }
97 }
98
99 pub fn call(&self) {
101 match self.repr {
102 CallbackRepr::Noop => {}
103 CallbackRepr::Handle(handle) => invoke_callback_handle(handle),
104 }
105 }
106}
107
108impl<F> From<F> for Callback
109where
110 F: Fn() + Send + Sync + 'static,
111{
112 fn from(handler: F) -> Self {
113 Self::new(handler)
114 }
115}
116
117impl Default for Callback {
118 fn default() -> Self {
119 Self::noop()
120 }
121}
122
123impl PartialEq for Callback {
124 fn eq(&self, other: &Self) -> bool {
125 self.repr == other.repr
126 }
127}
128
129impl Eq for Callback {}
130
131pub struct CallbackWith<T, R = ()> {
138 repr: CallbackWithRepr<T, R>,
139}
140
141enum CallbackWithRepr<T, R> {
142 Handle(FunctorHandle),
143 Static(fn(T) -> R),
144}
145
146impl<T, R> Copy for CallbackWithRepr<T, R> {}
147
148impl<T, R> Clone for CallbackWithRepr<T, R> {
149 fn clone(&self) -> Self {
150 *self
151 }
152}
153
154impl<T, R> CallbackWith<T, R>
155where
156 T: 'static,
157 R: 'static,
158{
159 #[track_caller]
163 pub fn new<F>(handler: F) -> Self
164 where
165 F: Fn(T) -> R + Send + Sync + 'static,
166 {
167 Self {
168 repr: CallbackWithRepr::Handle(remember_callback_with_handle(handler)),
169 }
170 }
171
172 pub fn call(&self, value: T) -> R {
174 match self.repr {
175 CallbackWithRepr::Handle(handle) => invoke_callback_with_handle(handle, value),
176 CallbackWithRepr::Static(handler) => handler(value),
177 }
178 }
179
180 fn from_static(handler: fn(T) -> R) -> Self {
181 Self {
182 repr: CallbackWithRepr::Static(handler),
183 }
184 }
185}
186
187impl<T, R, F> From<F> for CallbackWith<T, R>
188where
189 T: 'static,
190 R: 'static,
191 F: Fn(T) -> R + Send + Sync + 'static,
192{
193 fn from(handler: F) -> Self {
194 Self::new(handler)
195 }
196}
197
198impl<T, R> Copy for CallbackWith<T, R> {}
199
200impl<T, R> Clone for CallbackWith<T, R> {
201 fn clone(&self) -> Self {
202 *self
203 }
204}
205
206impl<T, R> PartialEq for CallbackWith<T, R> {
207 fn eq(&self, other: &Self) -> bool {
208 match (self.repr, other.repr) {
209 (CallbackWithRepr::Handle(lhs), CallbackWithRepr::Handle(rhs)) => lhs == rhs,
210 (CallbackWithRepr::Static(lhs), CallbackWithRepr::Static(rhs)) => {
211 ptr::fn_addr_eq(lhs, rhs)
212 }
213 _ => false,
214 }
215 }
216}
217
218impl<T, R> Eq for CallbackWith<T, R> {}
219
220impl<T, R> CallbackWith<T, R>
221where
222 T: 'static,
223 R: Default + 'static,
224{
225 pub fn default_value() -> Self {
228 fn default_value_impl<T, R: Default>(_: T) -> R {
229 R::default()
230 }
231
232 Self::from_static(default_value_impl::<T, R>)
233 }
234}
235
236impl<T> CallbackWith<T, T>
237where
238 T: 'static,
239{
240 pub fn identity() -> Self {
242 fn identity_impl<T>(value: T) -> T {
243 value
244 }
245
246 Self::from_static(identity_impl::<T>)
247 }
248}
249
250#[derive(Clone, Copy)]
261pub struct RenderSlot {
262 repr: RenderSlotRepr,
263}
264
265#[derive(Clone, Copy, Eq, PartialEq)]
266enum RenderSlotRepr {
267 Empty,
268 Handle(FunctorHandle),
269}
270
271impl RenderSlot {
272 #[track_caller]
276 pub fn new<F>(render: F) -> Self
277 where
278 F: Fn() + Send + Sync + 'static,
279 {
280 Self {
281 repr: RenderSlotRepr::Handle(remember_render_slot_handle(render)),
282 }
283 }
284
285 pub const fn empty() -> Self {
287 Self {
288 repr: RenderSlotRepr::Empty,
289 }
290 }
291
292 pub fn render(&self) {
294 match self.repr {
295 RenderSlotRepr::Empty => {}
296 RenderSlotRepr::Handle(handle) => {
297 render_slot_boundary(handle);
298 }
299 }
300 }
301}
302
303#[tessera(crate)]
304fn render_slot_boundary(handle: FunctorHandle) {
305 track_render_slot_read_dependency(handle);
306 invoke_render_slot_handle(handle);
307}
308
309impl<F> From<F> for RenderSlot
310where
311 F: Fn() + Send + Sync + 'static,
312{
313 fn from(render: F) -> Self {
314 Self::new(render)
315 }
316}
317
318impl From<Callback> for RenderSlot {
319 fn from(callback: Callback) -> Self {
320 Self::new(move || callback.call())
321 }
322}
323
324impl Default for RenderSlot {
325 fn default() -> Self {
326 Self::empty()
327 }
328}
329
330impl PartialEq for RenderSlot {
331 fn eq(&self, other: &Self) -> bool {
332 match (&self.repr, &other.repr) {
333 (RenderSlotRepr::Empty, RenderSlotRepr::Empty) => true,
334 (RenderSlotRepr::Handle(lhs), RenderSlotRepr::Handle(rhs)) => lhs == rhs,
335 _ => false,
336 }
337 }
338}
339
340impl Eq for RenderSlot {}
341
342pub struct RenderSlotWith<T> {
347 handle: FunctorHandle,
348 marker: PhantomData<fn(T)>,
349}
350
351impl<T> RenderSlotWith<T> {
352 #[track_caller]
356 pub fn new<F>(render: F) -> Self
357 where
358 T: 'static,
359 F: Fn(T) + Send + Sync + 'static,
360 {
361 Self {
362 handle: remember_render_slot_with_handle(render),
363 marker: PhantomData,
364 }
365 }
366
367 pub fn render(&self, value: T)
369 where
370 T: Clone + PartialEq + Send + Sync + 'static,
371 {
372 render_slot_with_boundary(self.handle, value);
373 }
374}
375
376#[tessera(crate)]
377fn render_slot_with_boundary<T>(handle: FunctorHandle, value: T)
378where
379 T: Clone + PartialEq + Send + Sync + 'static,
380{
381 track_render_slot_read_dependency(handle);
382 invoke_render_slot_with_handle(handle, value)
383}
384
385impl<T, F> From<F> for RenderSlotWith<T>
386where
387 T: 'static,
388 F: Fn(T) + Send + Sync + 'static,
389{
390 fn from(render: F) -> Self {
391 Self::new(render)
392 }
393}
394
395impl<T> From<CallbackWith<T>> for RenderSlotWith<T>
396where
397 T: 'static,
398{
399 fn from(callback: CallbackWith<T>) -> Self {
400 Self::new(move |value| {
401 callback.call(value);
402 })
403 }
404}
405
406impl<T> Clone for RenderSlotWith<T> {
407 fn clone(&self) -> Self {
408 *self
409 }
410}
411
412impl<T> Copy for RenderSlotWith<T> {}
413
414impl<T> PartialEq for RenderSlotWith<T> {
415 fn eq(&self, other: &Self) -> bool {
416 self.handle == other.handle
417 }
418}
419
420impl<T> Eq for RenderSlotWith<T> {}
421
422pub trait Prop: Clone + Send + Sync + 'static {
424 fn prop_eq(&self, other: &Self) -> bool;
426}
427
428impl Prop for () {
429 fn prop_eq(&self, _other: &Self) -> bool {
430 true
431 }
432}
433
434pub trait ErasedProp: Send + Sync {
436 fn as_any(&self) -> &dyn Any;
438 fn clone_box(&self) -> Box<dyn ErasedProp>;
440 fn equals(&self, other: &dyn ErasedProp) -> bool;
442}
443
444impl<T> ErasedProp for T
445where
446 T: Prop,
447{
448 fn as_any(&self) -> &dyn Any {
449 self
450 }
451
452 fn clone_box(&self) -> Box<dyn ErasedProp> {
453 Box::new(self.clone())
454 }
455
456 fn equals(&self, other: &dyn ErasedProp) -> bool {
457 let Some(other) = other.as_any().downcast_ref::<T>() else {
458 return false;
459 };
460 self.prop_eq(other)
461 }
462}
463
464pub trait ErasedComponentRunner: Send + Sync {
466 fn run(&self, props: &dyn ErasedProp);
468}
469
470struct ComponentRunner<P: Prop> {
471 run_fn: fn(&P),
472}
473
474impl<P> ErasedComponentRunner for ComponentRunner<P>
475where
476 P: Prop,
477{
478 fn run(&self, props: &dyn ErasedProp) {
479 let Some(props) = props.as_any().downcast_ref::<P>() else {
480 panic!(
481 "component runner props type mismatch: expected {}",
482 std::any::type_name::<P>()
483 );
484 };
485 (self.run_fn)(props);
486 }
487}
488
489pub fn make_component_runner<P>(run_fn: fn(&P)) -> Arc<dyn ErasedComponentRunner>
491where
492 P: Prop,
493{
494 Arc::new(ComponentRunner { run_fn })
495}
496
497#[derive(Clone)]
499pub struct ComponentReplayData {
500 pub runner: Arc<dyn ErasedComponentRunner>,
502 pub props: Arc<dyn ErasedProp>,
504}
505
506impl ComponentReplayData {
507 pub fn new<P>(runner: Arc<dyn ErasedComponentRunner>, props: &P) -> Self
509 where
510 P: Prop,
511 {
512 Self {
513 runner,
514 props: Arc::new(props.clone()),
515 }
516 }
517}