1use crate::{
2 Element, MountedVNode, RenderError, Runtime, VNode,
3 innerlude::{BoxedAnyProps, MountId},
4 reactive_context::ReactiveContext,
5 scope_context::Scope,
6};
7use std::{cell::Ref, rc::Rc};
8
9#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
15#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
16pub struct ScopeId(usize);
17
18impl std::fmt::Debug for ScopeId {
19 #[allow(unused_mut)]
20 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
21 let mut builder = f.debug_tuple("ScopeId");
22 let mut builder = builder.field(&self.0);
23 #[cfg(debug_assertions)]
24 {
25 if let Some(scope) = Runtime::try_current()
26 .as_ref()
27 .and_then(|r| r.try_get_state(*self))
28 {
29 builder = builder.field(&scope.name);
30 }
31 }
32 builder.finish()
33 }
34}
35
36impl ScopeId {
37 pub const APP: ScopeId = ScopeId(3);
53
54 pub const ROOT_ERROR_BOUNDARY: ScopeId = ScopeId(2);
56
57 pub const ROOT_SUSPENSE_BOUNDARY: ScopeId = ScopeId(1);
59
60 pub const ROOT: ScopeId = ScopeId(0);
64
65 pub(crate) const fn new(index: usize) -> Self {
66 Self(index)
67 }
68
69 pub(crate) const fn index(self) -> usize {
70 self.0
71 }
72}
73
74pub struct ScopeState {
78 pub(crate) runtime: Rc<Runtime>,
79 pub(crate) context_id: ScopeId,
80 pub(crate) props: BoxedAnyProps,
81 pub(crate) last_rendered_node: Option<MountedOutput>,
83 pub(crate) reactive_context: ReactiveContext,
84}
85
86impl ScopeState {
87 pub fn root_node(&self) -> &VNode {
93 self.try_root_node()
94 .expect("The tree has not been built yet. Make sure to call rebuild on the tree before accessing its nodes.")
95 }
96
97 pub fn try_root_node(&self) -> Option<&VNode> {
103 match &self.last_rendered_node {
104 Some(output) => Some(output.as_vnode()),
105 None => None,
106 }
107 }
108
109 pub fn try_mounted_root_node(&self) -> Option<MountedVNode<'_>> {
113 self.last_rendered_node
114 .as_ref()
115 .map(MountedOutput::mounted_vnode)
116 }
117
118 pub fn id(&self) -> ScopeId {
120 self.context_id
121 }
122
123 pub(crate) fn state(&self) -> Ref<'_, Scope> {
124 self.runtime.get_state(self.context_id)
125 }
126
127 pub fn height(&self) -> u32 {
129 self.state().height()
130 }
131}
132
133#[derive(Clone, PartialEq, Debug)]
134pub(crate) struct MountedOutput {
135 node: LastRenderedNode,
136 root_mount: MountId,
137}
138
139impl MountedOutput {
140 pub(crate) fn new(node: LastRenderedNode, root_mount: MountId) -> Self {
141 Self { node, root_mount }
142 }
143
144 pub(crate) fn node(&self) -> &LastRenderedNode {
145 &self.node
146 }
147
148 pub(crate) fn root_mount(&self) -> MountId {
149 self.root_mount
150 }
151
152 pub(crate) fn as_vnode(&self) -> &VNode {
153 self.node.as_vnode()
154 }
155
156 pub(crate) fn mounted_vnode(&self) -> MountedVNode<'_> {
157 MountedVNode::new(self.as_vnode(), self.root_mount)
158 }
159}
160
161impl std::ops::Deref for MountedOutput {
162 type Target = LastRenderedNode;
163
164 fn deref(&self) -> &Self::Target {
165 &self.node
166 }
167}
168
169#[derive(Clone, PartialEq, Debug)]
170pub(crate) enum LastRenderedNode {
171 Real(VNode),
172 Placeholder(VNode, RenderError),
173}
174
175impl std::ops::Deref for LastRenderedNode {
176 type Target = VNode;
177
178 fn deref(&self) -> &Self::Target {
179 match self {
180 LastRenderedNode::Real(vnode) => vnode,
181 LastRenderedNode::Placeholder(vnode, _err) => vnode,
182 }
183 }
184}
185
186impl LastRenderedNode {
187 pub(crate) fn new(node: Element) -> Self {
188 match node {
189 Ok(vnode) => LastRenderedNode::Real(vnode),
190 Err(err) => LastRenderedNode::Placeholder(VNode::placeholder(), err),
191 }
192 }
193
194 pub(crate) fn as_vnode(&self) -> &VNode {
195 match self {
196 LastRenderedNode::Real(vnode) => vnode,
197 LastRenderedNode::Placeholder(vnode, _err) => vnode,
198 }
199 }
200}
201
202impl Drop for ScopeState {
203 fn drop(&mut self) {
204 self.runtime.remove_scope(self.context_id);
205 }
206}