Allows for cleaner representation of adding a single element: Some(T) instead of Vec<T> of length 1, but Vec<T> still works. This will probably end up being replaced by a more complex representation of how a particular element impacts the Rust AST, to represent things like inline style declarations (#show
blocks).
GKBSBSDY5XLAT7SDKAVFQI3PHFUHKHTJGGXZH5XWG2E45U7BSU5QC
ZRGSUUICJKNHKVH2JZHHOKSSIQXNWCNLJX2ICSX524AG2XJKD3VAC
BSJYWOYSJRERQ45AD7RN3364RYQ5P3IM76S67262VLFZPFO3B5JQC
YKL5NCLHVHFQMBIWC6HW4NFPPYK5DR6XTCKJ5VBHNLVP2RO3H24AC
HEIF2O2ELHA3M7K77CK7AHBZ4656AUS3QW5M4E2DUY7ECOLVWKIAC
2N3KOCP74PCK2ETO5PCWBDR5PA57DDNT2KR4JLBPZPQPA56SAR4QC
GYTRFADRDO4SYXV6V3PEPGGFIRDHQH5YBTKEJCWFAIZ5CX4P46NAC
HEUMSBESSTWA6G7ZG5OJP3ZW3FLXHYUCODGDHMZSLE4O777JSDJQC
BA5Y6VSEHJQBOYBS6R6FE6IZDRNAPNIN5ITJXWK7L46RJVHNI7JAC
MPTQGIIJUNQSRWF5G63WDZLYH6EYURPENFTJ7J46VKPAWC6QQUGAC
CQEA2ZDITRMPXKCO5T346QH7JJOOGOPRC66F3MG6VEMEQGLYYUZAC
Q3IYM4WFHTO2IQLR2ZJ52FIE7U4RYIHQHXTPCK2HENSPVI7CPUZAC
I3NG5A4WXPELEOY3KFQKYBZVKA56VPGLI5R7O7TDCZTQAA7EROTQC
})
}
fn path_segment(segment: &str) -> PathSegment {
PathSegment {
ident: Ident::new(segment, proc_macro2::Span::call_site()),
arguments: PathArguments::None,
}
}
fn expr_path(name: &str) -> syn::Expr {
let mut segments: Punctuated<PathSegment, token::PathSep> = Punctuated::new();
// The path should be elements::name
// e.g. elements::h2
segments.push(path_segment("elements"));
segments.push(path_segment(name));
let expr_path = ExprPath {
attrs: Vec::new(),
qself: None,
path: syn::Path {
leading_colon: None,
segments,
},
};
syn::Expr::Path(expr_path)
}
fn xilem_html_element(name: &str, expressions: Vec<syn::Expr>) -> syn::Expr {
syn::Expr::Call(ExprCall {
attrs: Vec::new(),
func: Box::new(expr_path(name)),
paren_token: token::Paren::default(),
args: Punctuated::from_iter(expressions.into_iter()),
SupportedContent::Space(_space) => vec![syn::Expr::Lit(literal_string(" "))],
SupportedContent::Table(table) => vec![xilem_html_element(
"table",
vec![syn::Expr::Tuple(syn::ExprTuple {
attrs: Vec::new(),
paren_token: syn::token::Paren::default(),
elems: syn::punctuated::Punctuated::from_iter(
table
.children()
.into_iter()
.map(|content| SupportedContent::downcast(content))
.map(|supported| supported.to_xilem())
.flatten()
.collect::<Vec<_>>()
.chunks(2) // TODO: a slightly more sophisticated layout algorithm
.map(|chunk| {
xilem_html_element(
"tr",
vec![syn::Expr::Tuple(syn::ExprTuple {
attrs: Vec::new(),
paren_token: syn::token::Paren::default(),
elems: syn::punctuated::Punctuated::from_iter(
chunk.into_iter().map(|item| item.to_owned()),
),
})],
)
}),
),
})],
)],
SupportedContent::UnorderedList(list) => {
vec![xilem_html_element(
SupportedContent::Space(_space) => {
Box::new(Some(syn::Expr::Lit(literal_string(" "))).into_iter())
}
SupportedContent::Table(table) => Box::new(
Some(xilem_html_element(
"table",
Some(syn::Expr::Tuple(syn::ExprTuple {
attrs: Vec::new(),
paren_token: token::Paren::default(),
elems: Punctuated::from_iter(
table
.children()
.into_iter()
.map(|content| SupportedContent::downcast(content))
.map(|supported| supported.to_xilem().collect::<Vec<_>>())
.flatten()
.collect::<Vec<_>>()
.chunks(2) // TODO: a slightly more sophisticated layout algorithm
.map(|chunk| {
xilem_html_element(
"tr",
vec![syn::Expr::Tuple(syn::ExprTuple {
attrs: Vec::new(),
paren_token: token::Paren::default(),
elems: Punctuated::from_iter(
chunk.into_iter().map(|item| item.to_owned()),
),
})],
)
}),
),
})),
))
.into_iter(),
),
SupportedContent::UnorderedList(list) => Box::new(
Some(xilem_html_element(
fn expr_path(name: &str) -> syn::Expr {
let mut segments: Punctuated<PathSegment, token::PathSep> = Punctuated::new();
// The path should be elements::name
// e.g. elements::h2
segments.push(path_segment("elements"));
segments.push(path_segment(name));
let expr_path = ExprPath {
attrs: Vec::new(),
qself: None,
path: syn::Path {
leading_colon: None,
segments,
},
};
syn::Expr::Path(expr_path)
}
fn xilem_html_element(name: &str, expressions: impl IntoIterator<Item = syn::Expr>) -> syn::Expr {
syn::Expr::Call(syn::ExprCall {
attrs: Vec::new(),
func: Box::new(expr_path(name)),
paren_token: token::Paren::default(),
args: Punctuated::from_iter(expressions.into_iter()),
})
}