Skip to main content

dioxus_native_dom/
write_once_attr.rs

1use std::{cell::RefCell, rc::Rc, sync::atomic::AtomicUsize};
2
3use blitz_dom::{Document, Widget};
4use dioxus_core::{AttributeValue, IntoAttributeValue};
5
6#[derive(Clone, PartialEq)]
7pub struct SubDocumentAttr(WriteOnceAttr<Box<dyn Document>>);
8
9impl SubDocumentAttr {
10    /// Accepts any [`Document`] implementation, e.g. a plain [`BaseDocument`](blitz_dom::BaseDocument)
11    /// or a `ScriptDocument` from `blitz-script`.
12    pub fn new(doc: impl Document) -> Self {
13        let id = doc.id();
14        Self(WriteOnceAttr::new(id, Box::new(doc) as Box<dyn Document>))
15    }
16}
17
18impl IntoAttributeValue for SubDocumentAttr {
19    fn into_value(self) -> AttributeValue {
20        AttributeValue::Any(Rc::new(self.0))
21    }
22}
23
24static ID_COUNTER: AtomicUsize = AtomicUsize::new(0);
25
26#[derive(Clone, PartialEq)]
27pub struct CustomWidgetAttr(WriteOnceAttr<Box<dyn Widget>>);
28
29impl CustomWidgetAttr {
30    pub fn new<T: Widget + 'static>(widget: T) -> Self {
31        let id = ID_COUNTER.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
32        let boxed = Box::new(widget) as Box<dyn Widget>;
33        Self(WriteOnceAttr::new(id, boxed))
34    }
35}
36
37impl IntoAttributeValue for CustomWidgetAttr {
38    fn into_value(self) -> AttributeValue {
39        AttributeValue::Any(Rc::new(self.0))
40    }
41}
42
43pub(crate) struct WriteOnceAttr<T> {
44    id: usize,
45    value: Rc<RefCell<Option<T>>>,
46}
47
48impl<T> WriteOnceAttr<T> {
49    pub(crate) fn new(id: usize, value: T) -> Self {
50        let value = Rc::new(RefCell::new(Some(value)));
51        Self { id, value }
52    }
53    pub(crate) fn take(&self) -> Option<T> {
54        self.value.borrow_mut().take()
55    }
56}
57
58impl<T> Clone for WriteOnceAttr<T> {
59    fn clone(&self) -> Self {
60        Self {
61            id: self.id,
62            value: Rc::clone(&self.value),
63        }
64    }
65}
66
67impl<T> PartialEq for WriteOnceAttr<T> {
68    fn eq(&self, other: &Self) -> bool {
69        self.id == other.id
70    }
71}