use crate::innerlude::*;
use dioxus_core::internal::{FmtSegment, FmtedSegments, HotReloadLiteral};
use std::cell::Cell;
#[derive(Debug, PartialEq, Clone)]
pub(crate) struct BakedPool<T> {
pub inner: Vec<BakedItem<T>>,
}
impl<T> BakedPool<T> {
fn new(inner: impl IntoIterator<Item = T>) -> Self {
Self {
inner: inner.into_iter().map(BakedItem::new).collect(),
}
}
pub fn position(&self, condition: impl Fn(&T) -> bool) -> Option<usize> {
for (idx, baked_item) in self.inner.iter().enumerate() {
if condition(&baked_item.inner) {
baked_item.used.set(true);
return Some(idx);
}
}
None
}
fn unused_dynamic_items(&self) -> usize {
self.inner
.iter()
.filter(|baked_item| !baked_item.used.get())
.count()
}
}
#[derive(Debug, PartialEq, Clone)]
pub(crate) struct BakedItem<T> {
pub inner: T,
pub used: Cell<bool>,
}
impl<T> BakedItem<T> {
fn new(inner: T) -> Self {
Self {
inner,
used: Cell::new(false),
}
}
}
#[derive(Debug, PartialEq, Clone)]
pub(crate) struct LastBuildState {
pub dynamic_text_segments: BakedPool<FormattedSegment>,
pub dynamic_nodes: BakedPool<BodyNode>,
pub dynamic_attributes: BakedPool<Attribute>,
pub component_properties: Vec<HotLiteral>,
pub root_index: DynIdx,
pub name: String,
}
impl LastBuildState {
pub fn new(body: &TemplateBody, name: String) -> Self {
let dynamic_text_segments = body.dynamic_text_segments.iter().cloned();
let dynamic_nodes = body.dynamic_nodes().cloned();
let dynamic_attributes = body.dynamic_attributes().cloned();
let component_properties = body.literal_component_properties().cloned().collect();
Self {
dynamic_text_segments: BakedPool::new(dynamic_text_segments),
dynamic_nodes: BakedPool::new(dynamic_nodes),
dynamic_attributes: BakedPool::new(dynamic_attributes),
component_properties,
root_index: body.template_idx.clone(),
name,
}
}
pub fn unused_dynamic_items(&self) -> usize {
self.dynamic_text_segments.unused_dynamic_items()
+ self.dynamic_nodes.unused_dynamic_items()
+ self.dynamic_attributes.unused_dynamic_items()
}
pub fn hotreload_hot_literal(&self, hot_literal: &HotLiteral) -> Option<HotReloadLiteral> {
match hot_literal {
HotLiteral::Fmted(segments) => {
let new_segments = self.hot_reload_formatted_segments(segments)?;
Some(HotReloadLiteral::Fmted(new_segments))
}
HotLiteral::Bool(b) => Some(HotReloadLiteral::Bool(b.value())),
HotLiteral::Float(f) => Some(HotReloadLiteral::Float(f.base10_parse().ok()?)),
HotLiteral::Int(i) => Some(HotReloadLiteral::Int(i.base10_parse().ok()?)),
}
}
pub fn hot_reload_formatted_segments(
&self,
new: &HotReloadFormattedSegment,
) -> Option<FmtedSegments> {
let mut segments = Vec::new();
for segment in &new.segments {
match segment {
Segment::Literal(value) => {
segments.push(FmtSegment::Literal {
value: Box::leak(value.clone().into_boxed_str()),
});
} Segment::Formatted(formatted) => {
let index = self.dynamic_text_segments.position(|s| s == formatted)?;
segments.push(FmtSegment::Dynamic { id: index });
}
}
}
Some(FmtedSegments::new(segments))
}
}