1use std::cell::RefCell;
2use std::collections::HashMap;
3use std::rc::{Rc, Weak};
4use std::{fmt, mem};
5
6use hirola_core::generic_node::GenericNode;
7use hirola_core::render::{Error, Render};
8
9#[derive(Debug)]
12enum SsrNodeType {
13 Element(RefCell<Element>),
14 Comment(RefCell<Comment>),
15 Text(RefCell<Text>),
16 Fragment(RefCell<Fragment>),
17}
18
19#[derive(Debug, Clone)]
20struct SsrNodeInner {
21 ty: Rc<SsrNodeType>,
22 parent: RefCell<Weak<SsrNodeInner>>,
24}
25
26#[derive(Debug, Clone)]
27pub struct SsrNode(Rc<SsrNodeInner>);
28
29impl PartialEq for SsrNode {
30 fn eq(&self, other: &Self) -> bool {
31 Rc::ptr_eq(&self.0.ty, &other.0.ty)
32 }
33}
34
35impl Eq for SsrNode {}
36
37impl SsrNode {
38 fn new(ty: SsrNodeType) -> Self {
39 Self(Rc::new(SsrNodeInner {
40 ty: Rc::new(ty),
41 parent: RefCell::new(Weak::new()), }))
43 }
44
45 fn set_parent(&self, parent: Weak<SsrNodeInner>) {
46 if let Some(old_parent) = self.parent_node() {
47 old_parent.try_remove_child(self);
48 }
49
50 *self.0.parent.borrow_mut() = parent;
51 }
52
53 #[track_caller]
54 fn unwrap_element(&self) -> &RefCell<Element> {
55 match self.0.ty.as_ref() {
56 SsrNodeType::Element(e) => e,
57 _ => panic!("node is not an element"),
58 }
59 }
60
61 #[track_caller]
62 fn unwrap_text(&self) -> &RefCell<Text> {
63 match &self.0.ty.as_ref() {
64 SsrNodeType::Text(e) => e,
65 _ => panic!("node is not a text node"),
66 }
67 }
68
69 fn try_remove_child(&self, child: &Self) {
71 let mut children = match self.0.ty.as_ref() {
72 SsrNodeType::Element(e) => mem::take(&mut e.borrow_mut().children.0),
73 SsrNodeType::Fragment(f) => mem::take(&mut f.borrow_mut().0),
74 _ => panic!("node type cannot have children"),
75 };
76
77 if let Some(index) = children
78 .iter()
79 .enumerate()
80 .find_map(|(i, c)| (c == child).then_some(i))
81 {
82 children.remove(index);
83 } else {
84 for c in &children {
86 if let SsrNodeType::Fragment(fragment) = c.0.ty.as_ref() {
87 for c in &fragment.borrow().0 {
88 c.try_remove_child(child);
89 }
90 }
91 }
92 }
93
94 match self.0.ty.as_ref() {
95 SsrNodeType::Element(e) => e.borrow_mut().children.0 = children,
96 SsrNodeType::Fragment(f) => f.borrow_mut().0 = children,
97 _ => panic!("node type cannot have children"),
98 };
99 }
100}
101
102impl GenericNode for SsrNode {
103 fn element(tag: &str) -> Self {
104 SsrNode::new(SsrNodeType::Element(RefCell::new(Element {
105 name: tag.to_string(),
106 attributes: HashMap::new(),
107 children: Default::default(),
108 })))
109 }
110
111 fn text_node(text: &str) -> Self {
112 SsrNode::new(SsrNodeType::Text(RefCell::new(Text(text.to_string()))))
113 }
114
115 fn fragment() -> Self {
116 SsrNode::new(SsrNodeType::Fragment(Default::default()))
117 }
118
119 fn marker() -> Self {
120 SsrNode::new(SsrNodeType::Comment(Default::default()))
121 }
122
123 fn set_attribute(&self, name: &str, value: &str) {
124 self.unwrap_element()
125 .borrow_mut()
126 .attributes
127 .insert(name.to_string(), value.to_string());
128 }
129
130 fn append_child(&self, child: &Self) {
131 child.set_parent(Rc::downgrade(&self.0));
132
133 match self.0.ty.as_ref() {
134 SsrNodeType::Element(element) => element.borrow_mut().children.0.push(child.clone()),
135 SsrNodeType::Fragment(fragment) => fragment.borrow_mut().0.push(child.clone()),
136 _ => panic!("node type cannot have children"),
137 }
138 }
139
140 fn insert_child_before(&self, new_node: &Self, reference_node: Option<&Self>) {
141 if let Some(reference_node) = reference_node {
142 debug_assert_eq!(
143 reference_node.parent_node().as_ref(),
144 Some(self),
145 "reference node is not a child of this node"
146 );
147 }
148
149 new_node.set_parent(Rc::downgrade(&self.0));
150
151 let mut children = match self.0.ty.as_ref() {
152 SsrNodeType::Element(e) => mem::take(&mut e.borrow_mut().children.0),
153 SsrNodeType::Fragment(f) => mem::take(&mut f.borrow_mut().0),
154 _ => panic!("node type cannot have children"),
155 };
156
157 match reference_node {
158 None => self.append_child(new_node),
159 Some(reference) => {
160 children.insert(
161 children
162 .iter()
163 .enumerate()
164 .find_map(|(i, child)| (child == reference).then_some(i))
165 .expect("couldn't find reference node"),
166 new_node.clone(),
167 );
168 }
169 }
170
171 match self.0.ty.as_ref() {
172 SsrNodeType::Element(e) => e.borrow_mut().children.0 = children,
173 SsrNodeType::Fragment(f) => f.borrow_mut().0 = children,
174 _ => panic!("node type cannot have children"),
175 };
176 }
177
178 fn remove_child(&self, child: &Self) {
179 let mut children = match self.0.ty.as_ref() {
180 SsrNodeType::Element(e) => mem::take(&mut e.borrow_mut().children.0),
181 SsrNodeType::Fragment(f) => mem::take(&mut f.borrow_mut().0),
182 _ => panic!("node type cannot have children"),
183 };
184
185 let index = children
186 .iter()
187 .enumerate()
188 .find_map(|(i, c)| (c == child).then_some(i))
189 .expect("couldn't find child");
190 children.remove(index);
191
192 match self.0.ty.as_ref() {
193 SsrNodeType::Element(e) => e.borrow_mut().children.0 = children,
194 SsrNodeType::Fragment(f) => f.borrow_mut().0 = children,
195 _ => panic!("node type cannot have children"),
196 };
197 }
198
199 fn replace_child(&self, old: &Self, new: &Self) {
200 new.set_parent(Rc::downgrade(&self.0));
201
202 let mut ele = self.unwrap_element().borrow_mut();
203 let children = &mut ele.children.0;
204 let index = children
205 .iter()
206 .enumerate()
207 .find_map(|(i, c)| (c == old).then_some(i))
208 .expect("Couldn't find child");
209 children[index] = new.clone();
210 }
211
212 fn insert_sibling_before(&self, child: &Self) {
213 child.set_parent(Rc::downgrade(
214 &self.parent_node().expect("no parent for this node").0,
215 ));
216
217 self.parent_node()
218 .unwrap()
219 .insert_child_before(child, Some(self));
220 }
221
222 fn parent_node(&self) -> Option<Self> {
223 self.0.parent.borrow().upgrade().map(SsrNode)
224 }
225
226 fn next_sibling(&self) -> Option<Self> {
227 unimplemented!()
228 }
229
230 fn remove_self(&self) {
231 unimplemented!()
232 }
233
234 fn children(&self) -> RefCell<Vec<SsrNode>> {
235 unimplemented!()
236 }
237
238 fn update_inner_text(&self, text: &str) {
239 self.unwrap_text().borrow_mut().0 = text.to_string();
240 }
241
242 fn replace_children_with(&self, _node: &Self) {
243 unimplemented!()
244 }
245 fn effect(&self, _future: impl std::future::Future<Output = ()> + 'static) {
246 }
248}
249
250impl fmt::Display for SsrNode {
251 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
252 match self.0.ty.as_ref() {
253 SsrNodeType::Element(x) => write!(f, "{}", x.borrow()),
254 SsrNodeType::Comment(x) => write!(f, "{}", x.borrow()),
255 SsrNodeType::Text(x) => write!(f, "{}", x.borrow()),
256 SsrNodeType::Fragment(x) => write!(f, "{}", x.borrow()),
257 }
258 }
259}
260
261impl Render<SsrNode> for SsrNode {
262 fn render_into(self: Box<Self>, parent: &SsrNode) -> Result<(), Error> {
263 parent.append_child(&self);
264 Ok(())
265 }
266}
267
268#[derive(Debug, Clone, Eq, PartialEq)]
269pub struct Element {
270 name: String,
271 attributes: HashMap<String, String>,
272 children: Fragment,
273}
274
275impl fmt::Display for Element {
276 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
277 write!(f, "<{}", self.name)?;
278 for (name, value) in &self.attributes {
279 write!(
280 f,
281 r#" {}="{}""#,
282 name,
283 html_escape::encode_double_quoted_attribute(value)
284 )?;
285 }
286 write!(f, ">{}</{}>", self.children, self.name)?;
287 Ok(())
288 }
289}
290
291#[derive(Debug, Clone, Eq, PartialEq, Default)]
292pub struct Comment(String);
293
294impl fmt::Display for Comment {
295 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
296 write!(f, "<!--{}-->", self.0.replace("-->", "-->"))
297 }
298}
299
300#[derive(Debug, Clone, Eq, PartialEq, Default)]
301pub struct Text(String);
302
303impl fmt::Display for Text {
304 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
305 write!(f, "{}", html_escape::encode_text_minimal(&self.0))
306 }
307}
308
309#[derive(Debug, Clone, Eq, PartialEq, Default)]
310pub struct Fragment(Vec<SsrNode>);
311
312impl fmt::Display for Fragment {
313 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
314 for child in &self.0 {
315 write!(f, "{}", child)?;
316 }
317 Ok(())
318 }
319}
320
321pub fn render_to_string(dom: SsrNode) -> Result<String, Error> {
323 let root = SsrNode::fragment();
324 Render::render_into(Box::new(dom), &root)?;
325 Ok(format!("{}", root))
326}
327
328#[cfg(test)]
329mod tests {
330 use super::*;
331 use hirola::prelude::*;
332
333 #[test]
334 fn hello_world() {
335 let node = html! { <p>"Hello World!"</p> };
336
337 assert_eq!(render_to_string(node).unwrap(), "<p>Hello World!</p>");
338 }
339
340 #[test]
341 fn reactive_text() {
342 let count = Mutable::new(0);
343
344 assert_eq!(
345 render_to_string(html! {
346 <p>{count.clone()}</p>
347 })
348 .unwrap(),
349 "<p>0</p>"
350 );
351
352 count.set(1);
353 assert_eq!(
354 render_to_string(html! {
355 <p>{count}</p>
356 })
357 .unwrap(),
358 "<p>1</p>"
359 );
360 }
361
362 #[test]
363 #[should_panic]
364 fn check_reject_effects() {
365 let count = MutableVec::new_with_values(vec![1, 2, 3]);
366
367 let node = html! {
368 <ul>
369 {count
370 .signal_vec()
371 .map_render(move |item| {
372 html! { <li>{item.to_string()}</li> }
373 })}
374 </ul>
375 };
376
377 let dom = render_to_string(node).unwrap();
378 assert_eq!("<ul><li>1</li><li>2</li><li>3</li><!----></ul>", dom);
379 }
380}