cache.rs 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. use dioxus_core::prelude::*;
  2. use std::fmt::Write;
  3. pub struct StringCache {
  4. pub segments: Vec<Segment>,
  5. pub template: Template<'static>,
  6. }
  7. #[derive(Default)]
  8. pub struct StringChain {
  9. pub segments: Vec<Segment>,
  10. }
  11. #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
  12. pub enum Segment {
  13. Attr(usize),
  14. Node(usize),
  15. PreRendered(String),
  16. }
  17. impl std::fmt::Write for StringChain {
  18. fn write_str(&mut self, s: &str) -> std::fmt::Result {
  19. match self.segments.last_mut() {
  20. Some(Segment::PreRendered(s2)) => s2.push_str(s),
  21. _ => self.segments.push(Segment::PreRendered(s.to_string())),
  22. }
  23. Ok(())
  24. }
  25. }
  26. impl StringCache {
  27. pub fn from_template(template: &VNode) -> Result<Self, std::fmt::Error> {
  28. let mut chain = StringChain::default();
  29. let mut cur_path = vec![];
  30. for (root_idx, root) in template.template.roots.iter().enumerate() {
  31. Self::recurse(root, &mut cur_path, root_idx, &mut chain)?;
  32. }
  33. Ok(Self {
  34. segments: chain.segments,
  35. template: template.template,
  36. })
  37. }
  38. fn recurse(
  39. root: &TemplateNode,
  40. cur_path: &mut Vec<usize>,
  41. root_idx: usize,
  42. chain: &mut StringChain,
  43. ) -> Result<(), std::fmt::Error> {
  44. match root {
  45. TemplateNode::Element {
  46. tag,
  47. attrs,
  48. children,
  49. ..
  50. } => {
  51. cur_path.push(root_idx);
  52. write!(chain, "<{}", tag)?;
  53. for attr in *attrs {
  54. match attr {
  55. TemplateAttribute::Static { name, value, .. } => {
  56. write!(chain, " {}=\"{}\"", name, value)?;
  57. }
  58. TemplateAttribute::Dynamic { id: index } => {
  59. chain.segments.push(Segment::Attr(*index))
  60. }
  61. }
  62. }
  63. if children.is_empty() && tag_is_self_closing(tag) {
  64. write!(chain, "/>")?;
  65. } else {
  66. write!(chain, ">")?;
  67. for child in *children {
  68. Self::recurse(child, cur_path, root_idx, chain)?;
  69. }
  70. write!(chain, "</{}>", tag)?;
  71. }
  72. cur_path.pop();
  73. }
  74. TemplateNode::Text { text } => write!(chain, "{}", text)?,
  75. TemplateNode::Dynamic { id: idx } | TemplateNode::DynamicText { id: idx } => {
  76. chain.segments.push(Segment::Node(*idx))
  77. }
  78. }
  79. Ok(())
  80. }
  81. }
  82. fn tag_is_self_closing(tag: &str) -> bool {
  83. matches!(
  84. tag,
  85. "area"
  86. | "base"
  87. | "br"
  88. | "col"
  89. | "embed"
  90. | "hr"
  91. | "img"
  92. | "input"
  93. | "link"
  94. | "meta"
  95. | "param"
  96. | "source"
  97. | "track"
  98. | "wbr"
  99. )
  100. }