1use crate::{
2 any_props::BoxedAnyProps, reactive_context::ReactiveContext, scope_context::Scope, Element,
3 RenderError, Runtime, VNode,
4};
5use std::{cell::Ref, rc::Rc};
6
7#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
13#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
14pub struct ScopeId(pub usize);
15
16impl std::fmt::Debug for ScopeId {
17 #[allow(unused_mut)]
18 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
19 let mut builder = f.debug_tuple("ScopeId");
20 let mut builder = builder.field(&self.0);
21 #[cfg(debug_assertions)]
22 {
23 if let Some(scope) = Runtime::try_current()
24 .as_ref()
25 .and_then(|r| r.try_get_state(*self))
26 {
27 builder = builder.field(&scope.name);
28 }
29 }
30 builder.finish()
31 }
32}
33
34impl ScopeId {
35 pub const APP: ScopeId = ScopeId(3);
51
52 pub const ROOT_ERROR_BOUNDARY: ScopeId = ScopeId(2);
54
55 pub const ROOT_SUSPENSE_BOUNDARY: ScopeId = ScopeId(1);
57
58 pub const ROOT: ScopeId = ScopeId(0);
62
63 pub(crate) const PLACEHOLDER: ScopeId = ScopeId(usize::MAX);
64
65 pub(crate) fn is_placeholder(&self) -> bool {
66 *self == Self::PLACEHOLDER
67 }
68}
69
70pub struct ScopeState {
74 pub(crate) runtime: Rc<Runtime>,
75 pub(crate) context_id: ScopeId,
76 pub(crate) last_rendered_node: Option<LastRenderedNode>,
79 pub(crate) props: BoxedAnyProps,
80 pub(crate) reactive_context: ReactiveContext,
81}
82
83impl ScopeState {
84 pub fn root_node(&self) -> &VNode {
90 self.try_root_node()
91 .expect("The tree has not been built yet. Make sure to call rebuild on the tree before accessing its nodes.")
92 }
93
94 pub fn try_root_node(&self) -> Option<&VNode> {
100 match &self.last_rendered_node {
101 Some(LastRenderedNode::Real(vnode)) => Some(vnode),
102 Some(LastRenderedNode::Placeholder(vnode, _)) => Some(vnode),
103 None => None,
104 }
105 }
106
107 pub fn id(&self) -> ScopeId {
109 self.context_id
110 }
111
112 pub(crate) fn state(&self) -> Ref<'_, Scope> {
113 self.runtime.get_state(self.context_id)
114 }
115
116 pub fn height(&self) -> u32 {
118 self.state().height()
119 }
120}
121
122#[derive(Clone, PartialEq, Debug)]
123pub enum LastRenderedNode {
124 Real(VNode),
125 Placeholder(VNode, RenderError),
126}
127
128impl std::ops::Deref for LastRenderedNode {
129 type Target = VNode;
130
131 fn deref(&self) -> &Self::Target {
132 match self {
133 LastRenderedNode::Real(vnode) => vnode,
134 LastRenderedNode::Placeholder(vnode, _err) => vnode,
135 }
136 }
137}
138
139impl LastRenderedNode {
140 pub fn new(node: Element) -> Self {
141 match node {
142 Ok(vnode) => LastRenderedNode::Real(vnode),
143 Err(err) => LastRenderedNode::Placeholder(VNode::placeholder(), err),
144 }
145 }
146
147 pub fn as_vnode(&self) -> &VNode {
148 match self {
149 LastRenderedNode::Real(vnode) => vnode,
150 LastRenderedNode::Placeholder(vnode, _err) => vnode,
151 }
152 }
153}
154
155impl Drop for ScopeState {
156 fn drop(&mut self) {
157 self.runtime.remove_scope(self.context_id);
158 }
159}