use crate::reactive::Binding;
use indexmap::IndexMap;
use serde::{Deserialize, Serialize};
use slotmap::new_key_type;
use std::sync::Arc;
new_key_type! {
pub struct NodeId;
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum Value {
Static(serde_json::Value),
Binding(Binding),
TemplateString {
template: String,
bindings: Vec<Binding>,
},
Action(String),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum IRNode {
Element(Element),
ForEach {
source: Binding,
item_name: String,
key_path: Option<String>,
template: Vec<IRNode>,
props: Props,
},
Conditional {
value: Value,
branches: Vec<ConditionalBranch>,
fallback: Option<Vec<IRNode>>,
},
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ConditionalBranch {
pub pattern: Value,
pub children: Vec<IRNode>,
}
impl IRNode {
pub fn element(element: Element) -> Self {
IRNode::Element(element)
}
pub fn for_each(
source: Binding,
item_name: impl Into<String>,
key_path: Option<String>,
template: Vec<IRNode>,
props: Props,
) -> Self {
IRNode::ForEach {
source,
item_name: item_name.into(),
key_path,
template,
props,
}
}
pub fn conditional(
value: Value,
branches: Vec<ConditionalBranch>,
fallback: Option<Vec<IRNode>>,
) -> Self {
IRNode::Conditional {
value,
branches,
fallback,
}
}
pub fn as_element(&self) -> Option<&Element> {
match self {
IRNode::Element(e) => Some(e),
_ => None,
}
}
pub fn is_for_each(&self) -> bool {
matches!(self, IRNode::ForEach { .. })
}
pub fn is_conditional(&self) -> bool {
matches!(self, IRNode::Conditional { .. })
}
}
impl ConditionalBranch {
pub fn new(pattern: Value, children: Vec<IRNode>) -> Self {
Self { pattern, children }
}
}
pub type PropsMap = IndexMap<String, Value>;
#[derive(Debug, Clone)]
pub struct Props(Arc<PropsMap>);
impl Props {
pub fn new() -> Self {
Props(Arc::new(IndexMap::new()))
}
pub fn from_map(map: PropsMap) -> Self {
Props(Arc::new(map))
}
pub fn make_mut(&mut self) -> &mut PropsMap {
Arc::make_mut(&mut self.0)
}
pub fn insert(&mut self, key: String, value: Value) -> Option<Value> {
self.make_mut().insert(key, value)
}
pub fn remove(&mut self, key: &str) -> Option<Value> {
self.make_mut().shift_remove(key)
}
pub fn inner(&self) -> &PropsMap {
&self.0
}
}
impl Default for Props {
fn default() -> Self {
Props::new()
}
}
impl std::ops::Deref for Props {
type Target = PropsMap;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<'a> IntoIterator for &'a Props {
type Item = (&'a String, &'a Value);
type IntoIter = indexmap::map::Iter<'a, String, Value>;
fn into_iter(self) -> Self::IntoIter {
self.0.iter()
}
}
impl FromIterator<(String, Value)> for Props {
fn from_iter<I: IntoIterator<Item = (String, Value)>>(iter: I) -> Self {
Props(Arc::new(iter.into_iter().collect()))
}
}
impl serde::Serialize for Props {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.0.serialize(serializer)
}
}
impl<'de> serde::Deserialize<'de> for Props {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let map = PropsMap::deserialize(deserializer)?;
Ok(Props(Arc::new(map)))
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Element {
pub element_type: String,
pub props: Props,
#[serde(with = "arc_element_vec")]
pub children: im::Vector<Arc<Element>>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub ir_children: Vec<IRNode>,
pub key: Option<String>,
}
mod arc_element_vec {
use super::*;
use serde::{Deserializer, Serializer};
pub fn serialize<S>(vec: &im::Vector<Arc<Element>>, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
use serde::ser::SerializeSeq;
let mut seq = serializer.serialize_seq(Some(vec.len()))?;
for elem in vec.iter() {
seq.serialize_element(elem.as_ref())?;
}
seq.end()
}
pub fn deserialize<'de, D>(deserializer: D) -> Result<im::Vector<Arc<Element>>, D::Error>
where
D: Deserializer<'de>,
{
let vec: Vec<Element> = Vec::deserialize(deserializer)?;
Ok(vec.into_iter().map(Arc::new).collect())
}
}
impl Element {
pub fn new(element_type: impl Into<String>) -> Self {
Self {
element_type: element_type.into(),
props: Props::new(),
children: im::Vector::new(),
ir_children: Vec::new(),
key: None,
}
}
pub fn with_prop(mut self, key: impl Into<String>, value: Value) -> Self {
self.props.insert(key.into(), value);
self
}
pub fn with_child(mut self, child: Element) -> Self {
self.children.push_back(Arc::new(child));
self
}
pub fn with_arc_child(mut self, child: Arc<Element>) -> Self {
self.children.push_back(child);
self
}
pub fn with_key(mut self, key: impl Into<String>) -> Self {
self.key = Some(key.into());
self
}
}