Jonathan Kelley 3 lat temu
rodzic
commit
36d89be

+ 4 - 8
examples/borrowed.rs

@@ -20,7 +20,7 @@ fn main() {
     dioxus::desktop::launch(App, |c| c);
 }
 
-fn App((cx, props): Scope<()>) -> Element {
+fn App(cx: Context, props: &()) -> Element {
     let text: &mut Vec<String> = cx.use_hook(|_| vec![String::from("abc=def")], |f| f);
 
     let first = text.get_mut(0).unwrap();
@@ -39,11 +39,7 @@ struct C1Props<'a> {
     text: &'a mut String,
 }
 
-impl<'a> Drop for C1Props<'a> {
-    fn drop(&mut self) {}
-}
-
-fn Child1<'a>((cx, props): Scope<'a, C1Props>) -> Element<'a> {
+fn Child1(cx: Context, props: &C1Props) -> Element {
     let (left, right) = props.text.split_once("=").unwrap();
 
     cx.render(rsx! {
@@ -59,7 +55,7 @@ struct C2Props<'a> {
     text: &'a str,
 }
 
-fn Child2<'a>((cx, props): Scope<'a, C2Props>) -> Element<'a> {
+fn Child2(cx: Context, props: &C2Props) -> Element {
     cx.render(rsx! {
         Child3 {
             text: props.text
@@ -72,7 +68,7 @@ struct C3Props<'a> {
     text: &'a str,
 }
 
-fn Child3<'a>((cx, props): Scope<'a, C3Props>) -> Element<'a> {
+fn Child3(cx: Context, props: &C3Props) -> Element {
     cx.render(rsx! {
         div { "{props.text}"}
     })

+ 0 - 36
packages/core-macro/src/router.rs

@@ -189,39 +189,9 @@ pub fn routable_derive_impl(input: Routable) -> TokenStream {
     let from_path = input.build_from_path();
     let to_path = input.build_to_path();
 
-    let not_found_route = match not_found_route {
-        Some(route) => quote! { ::std::option::Option::Some(Self::#route) },
-        None => quote! { ::std::option::Option::None },
-    };
-
-    let cache_thread_local_ident = Ident::new(
-        &format!("__{}_ROUTER_CURRENT_ROUTE_CACHE", ident),
-        ident.span(),
-    );
-
     quote! {
-        // ::std::thread_local! {
-        //     #[doc(hidden)]
-        //     #[allow(non_upper_case_globals)]
-        //     static #cache_thread_local_ident: ::std::cell::RefCell<::std::option::Option<#ident>> = ::std::cell::RefCell::new(::std::option::Option::None);
-        // }
-
         // #[automatically_derived]
         // impl ::dioxus::router::Routable for #ident {
-        //     #from_path
-        //     #to_path
-
-        //     // fn routes() -> ::std::vec::Vec<&'static str> {
-        //     //     ::std::vec![#(#ats),*]
-        //     // }
-
-        //     fn not_found_route() -> ::std::option::Option<Self> {
-        //         #not_found_route
-        //     }
-
-        //     // fn current_route() -> ::std::option::Option<Self> {
-        //     //     #cache_thread_local_ident.with(|val| ::std::clone::Clone::clone(&*val.borrow()))
-        //     // }
 
         //     fn recognize(pathname: &str) -> ::std::option::Option<Self> {
         //         todo!()
@@ -237,12 +207,6 @@ pub fn routable_derive_impl(input: Routable) -> TokenStream {
         //         // }
         //         // route
         //     }
-
-        //     // fn cleanup() {
-        //     //     #cache_thread_local_ident.with(move |val| {
-        //     //         *val.borrow_mut() = ::std::option::Option::None;
-        //     //     });
-        //     // }
         // }
     }
 }

+ 0 - 264
packages/core-macro/styles/calc.rs

@@ -1,264 +0,0 @@
-//! The `calc` functionality.
-use crate::LengthPercentage;
-use ::{
-    proc_macro2::TokenStream,
-    quote::{quote, ToTokens},
-    std::fmt,
-    syn::{
-        custom_keyword, parenthesized,
-        parse::{Parse, ParseStream},
-        Token,
-    },
-};
-
-/// Values that can be a calculaion (currently restricted to length & percentages)
-#[derive(Debug, Clone, PartialEq)]
-pub enum Calc {
-    Calculated(CalcSum),
-    Normal(LengthPercentage),
-}
-
-impl fmt::Display for Calc {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            Calc::Calculated(inner) => write!(f, "calc({})", inner),
-            Calc::Normal(inner) => write!(f, "{}", inner),
-        }
-    }
-}
-
-impl Parse for Calc {
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        custom_keyword!(calc);
-        if s.peek(calc) {
-            s.parse::<calc>()?;
-            let content;
-            parenthesized!(content in s);
-            Ok(Calc::Calculated(content.parse()?))
-        } else {
-            Ok(Calc::Normal(s.parse()?))
-        }
-    }
-}
-
-impl ToTokens for Calc {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        tokens.extend(match self {
-            Calc::Calculated(inner) => quote!(style::Calc::Calculated(#inner)),
-            Calc::Normal(inner) => quote!(style::Calc::Normal(#inner)),
-        });
-    }
-}
-
-#[test]
-fn test_calc() {
-    for (input, output) in vec![
-        ("calc(10% - 20\"em\")", "calc(10% - 20em)"),
-        ("calc(100% + 5px)", "calc(100% + 5px)"),
-        ("calc(100% - 60px)", "calc(100% - 60px)"),
-    ] {
-        assert_eq!(&syn::parse_str::<Calc>(input).unwrap().to_string(), output);
-    }
-}
-
-#[derive(Debug, Clone, PartialEq)]
-pub struct CalcSum {
-    pub first: CalcProduct,
-    pub rest: Vec<SumOp>,
-}
-
-impl fmt::Display for CalcSum {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{}", self.first)?;
-        for op in self.rest.iter() {
-            write!(f, "{}", op)?;
-        }
-        Ok(())
-    }
-}
-
-impl Parse for CalcSum {
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        let first: CalcProduct = s.parse()?;
-        let mut rest: Vec<SumOp> = vec![];
-        while SumOp::peek(s) {
-            rest.push(s.parse()?);
-        }
-        Ok(CalcSum { first, rest })
-    }
-}
-
-impl ToTokens for CalcSum {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        let first = &self.first;
-        let rest = self.rest.iter();
-        tokens.extend(quote! {
-            style::calc::CalcSum {
-                first: #first,
-                rest: vec![#(#rest,)*]
-            }
-        });
-    }
-}
-
-#[derive(Debug, Clone, PartialEq)]
-pub enum SumOp {
-    Add(CalcProduct),
-    Sub(CalcProduct),
-}
-
-impl SumOp {
-    fn peek(s: ParseStream) -> bool {
-        s.peek(Token![+]) || s.peek(Token![-])
-    }
-}
-
-impl fmt::Display for SumOp {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            SumOp::Add(inner) => write!(f, " + {}", inner),
-            SumOp::Sub(inner) => write!(f, " - {}", inner),
-        }
-    }
-}
-
-impl Parse for SumOp {
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        let lookahead = s.lookahead1();
-        if lookahead.peek(Token![+]) {
-            s.parse::<Token![+]>()?;
-            Ok(SumOp::Add(s.parse()?))
-        } else if lookahead.peek(Token![-]) {
-            s.parse::<Token![-]>()?;
-            Ok(SumOp::Sub(s.parse()?))
-        } else {
-            Err(lookahead.error())
-        }
-    }
-}
-
-impl ToTokens for SumOp {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        tokens.extend(match self {
-            SumOp::Add(inner) => quote!(style::SumOp::Add(#inner)),
-            SumOp::Sub(inner) => quote!(style::SumOp::Sub(#inner)),
-        });
-    }
-}
-
-#[derive(Debug, Clone, PartialEq)]
-pub struct CalcProduct {
-    pub first: CalcValue,
-    pub rest: Vec<ProductOp>,
-}
-
-impl fmt::Display for CalcProduct {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{}", self.first)?;
-        for op in self.rest.iter() {
-            write!(f, "{}", op)?;
-        }
-        Ok(())
-    }
-}
-
-impl Parse for CalcProduct {
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        let first: CalcValue = s.parse()?;
-        let mut rest: Vec<ProductOp> = vec![];
-        while ProductOp::peek(s) {
-            rest.push(s.parse()?);
-        }
-        Ok(CalcProduct { first, rest })
-    }
-}
-
-impl ToTokens for CalcProduct {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        let first = &self.first;
-        let rest = self.rest.iter();
-        tokens.extend(quote! {
-            style::calc::CalcProduct {
-                first: #first,
-                rest: vec![#(#rest,)*]
-            }
-        });
-    }
-}
-
-#[derive(Debug, Clone, PartialEq)]
-pub enum ProductOp {
-    Mul(CalcValue),
-    // todo Div(Number),
-}
-
-impl ProductOp {
-    pub fn peek(s: ParseStream) -> bool {
-        s.peek(Token![*]) // || s.peek(Token[/])
-    }
-}
-
-impl fmt::Display for ProductOp {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            ProductOp::Mul(inner) => write!(f, "*{}", inner),
-            //ProductOp::Div(inner) => write!(f, "/{}", inner),
-        }
-    }
-}
-
-impl Parse for ProductOp {
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        let lookahead = s.lookahead1();
-        if lookahead.peek(Token![*]) {
-            s.parse::<Token![*]>()?;
-            Ok(ProductOp::Mul(s.parse()?))
-        /*
-        } else if lookahead.peek(Token![/]) {
-            s.parse::<Token![/]>()?;
-            Ok(ProductOp::Div(s.parse()?))
-        */
-        } else {
-            Err(lookahead.error())
-        }
-    }
-}
-
-impl ToTokens for ProductOp {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        tokens.extend(match self {
-            ProductOp::Mul(inner) => quote!(style::ProductOp::Mul(#inner)),
-            //ProductOp::Div(inner) => quote!(style::ProductOp::Div(#inner)),
-        });
-    }
-}
-
-#[derive(Debug, Clone, PartialEq)]
-pub enum CalcValue {
-    LengthPercentage(LengthPercentage),
-    // todo more variants
-}
-
-impl Parse for CalcValue {
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        Ok(CalcValue::LengthPercentage(s.parse()?))
-    }
-}
-
-impl fmt::Display for CalcValue {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            CalcValue::LengthPercentage(inner) => write!(f, "{}", inner),
-        }
-    }
-}
-
-impl ToTokens for CalcValue {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        tokens.extend(match self {
-            CalcValue::LengthPercentage(inner) => {
-                quote!(style::CalcValue::LengthPercentage(#inner))
-            }
-        });
-    }
-}

+ 0 - 1150
packages/core-macro/styles/codegen.rs

@@ -1,1150 +0,0 @@
-use crate::*;
-use proc_macro2::TokenStream;
-use quote::{quote, ToTokens};
-
-macro_rules! path {
-    ($($t:tt)+) => {
-        ::quote::quote!(::style:: $($t)+)
-    };
-}
-
-impl ToTokens for DynamicStyles {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        let parts = self
-            .rules
-            .iter()
-            .filter(|style| !style.is_dummy())
-            .map(|style| style.to_token_stream());
-        tokens.extend(quote! {
-            {
-                let mut styles = style::Styles::new();
-                #(styles.push(#parts);)*
-                styles
-            }
-        })
-    }
-}
-
-impl ToTokens for DynamicStyle {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        tokens.extend(match self {
-            DynamicStyle::Dynamic(block) => quote!(#block),
-            DynamicStyle::Literal(lit) => quote!(#lit),
-        })
-    }
-}
-
-impl ToTokens for Style {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        let path = quote!(::style::Style::);
-        tokens.extend(match self {
-            Style::Dummy => quote!(#path Dummy),
-            Style::Unchecked(v) => quote!(#path Unchecked(String::from(#v))),
-
-            Style::AlignContent(v) => quote!(#path AlignContent(#v)),
-            Style::AlignItems(v) => quote!(#path AlignItems(#v)),
-            Style::AlignSelf(v) => quote!(#path AlignSelf(#v)),
-            // all
-            // background
-            Style::BackgroundAttachment(v) => quote!(#path BackgroundAttachment(#v)),
-            Style::BackgroundBlendMode(v) => quote!(#path BackgroundBlendMode(#v)),
-            Style::BackgroundClip(v) => quote!(#path BackgroundClip(#v)),
-            Style::BackgroundColor(v) => quote!(#path BackgroundColor(#v)),
-            Style::BackgroundImage(v) => quote!(#path BackgroundImage(#v)),
-            Style::BackgroundOrigin(v) => quote!(#path BackgroundOrigin(#v)),
-            Style::BackgroundPosition(v) => quote!(#path BackgroundPosition(#v)),
-            Style::BackgroundRepeat(v) => quote!(#path BackgroundRepeat(#v)),
-            Style::BackgroundSize(v) => quote!(#path BackgroundSize(#v)),
-            Style::Border(v) => quote!(#path Border(#v)),
-            Style::BorderBottom(v) => quote!(#path BorderBottom(#v)),
-            Style::BorderBottomColor(v) => quote!(#path BorderBottomColor(#v)),
-            Style::BorderBottomLeftRadius(v) => quote!(#path BorderBottomLeftRadius(#v)),
-            Style::BorderBottomRightRadius(v) => quote!(#path BorderBottomRightRadius(#v)),
-            Style::BorderBottomStyle(v) => quote!(#path BorderBottomStyle(#v)),
-            Style::BorderBottomWidth(v) => quote!(#path BorderBottomWidth(#v)),
-            Style::BorderCollapse(v) => quote!(#path BorderCollapse(#v)),
-            Style::BorderColor(v) => quote!(#path BorderColor(#v)),
-            // border-image
-            // border-image-outset
-            // border-image-repeat
-            // border-image-slice
-            // border-image-source
-            // border-image-width
-            Style::BorderLeft(v) => quote!(#path BorderLeft(#v)),
-            Style::BorderLeftColor(v) => quote!(#path BorderLeftColor(#v)),
-            Style::BorderLeftStyle(v) => quote!(#path BorderLeftStyle(#v)),
-            Style::BorderLeftWidth(v) => quote!(#path BorderLeftWidth(#v)),
-            Style::BorderRadius(v) => quote!(#path BorderRadius(#v)),
-            Style::BorderRight(v) => quote!(#path BorderRight(#v)),
-            Style::BorderRightColor(v) => quote!(#path BorderRightColor(#v)),
-            Style::BorderRightStyle(v) => quote!(#path BorderRightStyle(#v)),
-            Style::BorderRightWidth(v) => quote!(#path BorderRightWidth(#v)),
-            // border-spacing
-            Style::BorderStyle(v) => quote!(#path BorderStyle(#v)),
-            Style::BorderTop(v) => quote!(#path BorderTop(#v)),
-            Style::BorderTopColor(v) => quote!(#path BorderTopColor(#v)),
-            Style::BorderTopLeftRadius(v) => quote!(#path BorderTopLeftRadius(#v)),
-            Style::BorderTopRightRadius(v) => quote!(#path BorderTopRightRadius(#v)),
-            Style::BorderTopStyle(v) => quote!(#path BorderTopStyle(#v)),
-            Style::BorderTopWidth(v) => quote!(#path BorderTopWidth(#v)),
-            Style::BorderWidth(v) => quote!(#path BorderWidth(#v)),
-            Style::Bottom(v) => quote!(#path Bottom(#v)),
-            // box-decoration-break
-            Style::BoxShadow(v) => quote!(#path BoxShadow(#v)),
-            Style::BoxSizing(v) => quote!(#path BoxSizing(#v)),
-            // break-after
-            // break-before
-            // break-inside
-            // caption-side
-            // caret-color
-            Style::Clear(v) => quote!(#path Clear(#v)),
-            // clip
-            // clip-path
-            // clip-rule
-            Style::ColumnCount(v) => quote!(#path ColumnCount(#v)),
-            Style::Color(v) => quote!(#path Color(#v)),
-            // contain
-            // content
-            // counter-increment
-            // counter-reset
-            // cue
-            // cue-after
-            // cue-before
-            Style::Cursor(v) => quote!(#path Cursor(#v)),
-            // direction
-            Style::Display(v) => quote!(#path Display(#v)),
-            // elevation
-            // empty-cells
-            // flex
-            Style::FlexBasis(v) => quote!(#path FlexBasis(#v)),
-            Style::FlexDirection(v) => quote!(#path FlexDirection(#v)),
-            // flex-flow
-            Style::FlexGrow(v) => quote!(#path FlexGrow(#v)),
-            Style::FlexShrink(v) => quote!(#path FlexShrink(#v)),
-            Style::FlexWrap(v) => quote!(#path FlexWrap(#v)),
-            Style::Float(v) => quote!(#path Float(#v)),
-            // font
-            Style::FontFamily(v) => quote!(#path FontFamily(#v)),
-            // font-feature-settings
-            // font-kerning
-            Style::FontSize(v) => quote!(#path FontSize(#v)),
-            // font-size-adjust
-            // font-stretch
-            Style::FontStyle(v) => quote!(#path FontStyle(#v)),
-            // font-synthesis
-            // font-variant
-            // font-variant-caps
-            // font-variant-east-asian
-            // font-variant-ligatures
-            // font-variant-numeric
-            // font-variant-position
-            Style::FontWeight(v) => quote!(#path FontWeight(#v)),
-            // glyph-orientation-vertical
-            // grid
-            // grid-area
-            // grid-auto-columns
-            // grid-auto-flow
-            // grid-auto-rows
-            // grid-column
-            // grid-column-end
-            // grid-column-start
-            // grid-row
-            // grid-row-end
-            // grid-row-start
-            // grid-template
-            // grid-template-areas
-            // grid-template-columns
-            // grid-template-rows
-            Style::Height(v) => quote!(#path Height(#v)),
-            // image-orientation
-            // image-rendering
-            // isolation
-            Style::JustifyContent(v) => quote!(#path JustifyContent(#v)),
-            Style::Left(v) => quote!(#path Left(#v)),
-            // letter-spacing
-            Style::LineHeight(v) => quote!(#path LineHeight(#v)),
-            // list-style
-            // list-style-image
-            // list-style-position
-            Style::ListStyleType(v) => quote!(#path ListStyleType(#v)),
-            Style::Margin(v) => quote!(#path Margin(#v)),
-            Style::MarginBottom(v) => quote!(#path MarginBottom(#v)),
-            Style::MarginLeft(v) => quote!(#path MarginLeft(#v)),
-            Style::MarginRight(v) => quote!(#path MarginRight(#v)),
-            Style::MarginTop(v) => quote!(#path MarginTop(#v)),
-            // mask
-            // mask-border
-            // mask-border-mode
-            // mask-border-outset
-            // mask-border-repeat
-            // mask-border-slice
-            // mask-border-source
-            // mask-border-width
-            // mask-clip
-            // mask-composite
-            // mask-image
-            // mask-mode
-            // mask-origin
-            // mask-position
-            // mask-repeat
-            // mask-size
-            // mask-type
-            Style::MaxHeight(v) => quote!(#path MaxHeight(#v)),
-            Style::MaxWidth(v) => quote!(#path MaxWidth(#v)),
-            Style::MinHeight(v) => quote!(#path MinHeight(#v)),
-            Style::MinWidth(v) => quote!(#path MinWidth(#v)),
-            // mix-blend-mode
-            Style::ObjectFit(v) => quote!(#path ObjectFit(#v)),
-            // object-position
-            // opacity
-            // order
-            // orphans
-            // outline
-            // outline-color
-            // outline-offset
-            // outline-style
-            // outline-width
-            Style::Overflow(v) => quote!(#path Overflow(#v)),
-            Style::OverflowX(v) => quote!(#path OverflowX(#v)),
-            Style::OverflowY(v) => quote!(#path OverflowY(#v)),
-            Style::Padding(v) => quote!(#path Padding(#v)),
-            Style::PaddingBottom(v) => quote!(#path PaddingBottom(#v)),
-            Style::PaddingLeft(v) => quote!(#path PaddingLeft(#v)),
-            Style::PaddingRight(v) => quote!(#path PaddingRight(#v)),
-            Style::PaddingTop(v) => quote!(#path PaddingTop(#v)),
-            // page-break-after
-            // page-break-before
-            // page-break-inside
-            // pause
-            // pause-after
-            // pause-before
-            // pitch
-            // pitch-range
-            // play-during
-            Style::Position(v) => quote!(#path Position(#v)),
-            // quotes
-            Style::Resize(v) => quote!(#path Resize(#v)),
-            // richness
-            Style::Right(v) => quote!(#path Right(#v)),
-            // scroll-margin
-            // scroll-margin-block
-            // scroll-margin-block-end
-            // scroll-margin-block-start
-            // scroll-margin-bottom
-            // scroll-margin-inline
-            // scroll-margin-inline-end
-            // scroll-margin-inline-start
-            // scroll-margin-left
-            // scroll-margin-right
-            // scroll-margin-top
-            // scroll-padding
-            // scroll-padding-block
-            // scroll-padding-block-end
-            // scroll-padding-block-start
-            // scroll-padding-bottom
-            // scroll-padding-inline
-            // scroll-padding-inline-end
-            // scroll-padding-inline-start
-            // scroll-padding-left
-            // scroll-padding-right
-            // scroll-padding-top
-            // scroll-snap-align
-            // scroll-snap-stop
-            // scroll-snap-type
-            // shape-image-threshold
-            // shape-margin
-            // shape-outside
-            // speak
-            // speak-header
-            // speak-numeral
-            // speak-punctuation
-            // speech-rate
-            // stress
-            // table-layout
-            Style::TextAlign(v) => quote!(#path TextAlign(#v)),
-            // text-combine-upright
-            // text-decoration
-            // text-decoration-color
-            // text-decoration-line
-            // text-decoration-style
-            // text-emphasis
-            // text-emphasis-color
-            // text-emphasis-position
-            // text-emphasis-style
-            // text-indent
-            // text-orientation
-            // text-overflow
-            // text-shadow
-            // text-transform
-            // text-underline-position
-            Style::Top(v) => quote!(#path Top(#v)),
-            // transform
-            // transform-box
-            // transform-origin
-            // unicode-bidi
-            // vertical-align
-            // visibility
-            // voice-family
-            // volume
-            // white-space
-            Style::WhiteSpace(v) => quote!(#path WhiteSpace(#v)),
-            Style::Widows(v) => quote!(#path Widows(#v)),
-            Style::Width(v) => quote!(#path Width(#v)),
-            // will-change
-            // word-spacing
-            // writing-mode
-            // z-index
-        });
-    }
-}
-
-impl ToTokens for AlignContent {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        tokens.extend(match self {
-            AlignContent::FlexStart => path!(AlignContent::FlexStart),
-            AlignContent::Center => path!(AlignContent::Center),
-            AlignContent::FlexEnd => path!(style::AlignContent::FlexEnd),
-            AlignContent::SpaceAround => path!(AlignContent::SpaceAround),
-            AlignContent::SpaceBetween => path!(AlignContent::SpaceBetween),
-            AlignContent::Stretch => path!(AlignContent::Stretch),
-        });
-    }
-}
-
-impl ToTokens for Cursor {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        tokens.extend(match self {
-            Cursor::Auto => path!(Cursor::Auto),
-            Cursor::Default => path!(Cursor::Default),
-            Cursor::None => path!(Cursor::None),
-            Cursor::ContextMenu => path!(Cursor::ContextMenu),
-            Cursor::Help => path!(Cursor::Help),
-            Cursor::Pointer => path!(Cursor::Pointer),
-            Cursor::Progress => path!(Cursor::Progress),
-            Cursor::Wait => path!(Cursor::Wait),
-            Cursor::Cell => path!(Cursor::Cell),
-            Cursor::Crosshair => path!(Cursor::Crosshair),
-            Cursor::Text => path!(Cursor::Text),
-            Cursor::VerticalText => path!(Cursor::VerticalText),
-            Cursor::Alias => path!(Cursor::Alias),
-            Cursor::Copy => path!(Cursor::Copy),
-            Cursor::Move => path!(Cursor::Move),
-            Cursor::NoDrop => path!(Cursor::NoDrop),
-            Cursor::NotAllowed => path!(Cursor::NotAllowed),
-            Cursor::Grab => path!(Cursor::Grab),
-            Cursor::Grabbing => path!(Cursor::Grabbing),
-            Cursor::EResize => path!(Cursor::EResize),
-            Cursor::NResize => path!(Cursor::NResize),
-            Cursor::NEResize => path!(Cursor::NEResize),
-            Cursor::NWResize => path!(Cursor::NWResize),
-            Cursor::SResize => path!(Cursor::SResize),
-            Cursor::SEResize => path!(Cursor::SEResize),
-            Cursor::SWResize => path!(Cursor::SWResize),
-            Cursor::WResize => path!(Cursor::WResize),
-            Cursor::EWResize => path!(Cursor::EWResize),
-            Cursor::NSResize => path!(Cursor::NSResize),
-            Cursor::NESWResize => path!(Cursor::NESWResize),
-            Cursor::NWSEResize => path!(Cursor::NWSEResize),
-            Cursor::ColResize => path!(Cursor::ColResize),
-            Cursor::RowResize => path!(Cursor::RowResize),
-            Cursor::AllScroll => path!(Cursor::AllScroll),
-            Cursor::ZoomIn => path!(Cursor::ZoomIn),
-            Cursor::ZoomOut => path!(Cursor::ZoomOut),
-        })
-    }
-}
-
-impl ToTokens for Display {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        tokens.extend(match self {
-            Display::Block => path!(Display::Block),
-            Display::Flex => path!(Display::Flex),
-            Display::Inline => path!(Display::Inline),
-        });
-    }
-}
-
-impl ToTokens for FlexBasis {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        tokens.extend(match self {
-            FlexBasis::Width(v) => path!(FlexBasis::Width(#v)),
-            FlexBasis::Content => path!(FlexBasis::Content),
-        });
-    }
-}
-
-impl ToTokens for FlexDirection {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        tokens.extend(match self {
-            FlexDirection::Row => path!(FlexDirection::Row),
-            FlexDirection::Column => path!(FlexDirection::Column),
-        });
-    }
-}
-
-impl ToTokens for FlexWrap {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        tokens.extend(match self {
-            FlexWrap::Wrap => path!(FlexWrap::Wrap),
-            FlexWrap::Nowrap => path!(FlexWrap::Nowrap),
-        });
-    }
-}
-
-impl ToTokens for AlignItems {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        tokens.extend(match self {
-            AlignItems::Normal => path!(AlignItems::Normal),
-            AlignItems::Stretch => path!(AlignItems::Stretch),
-            AlignItems::Center => path!(AlignItems::Center),
-            AlignItems::Start => path!(AlignItems::Start),
-            AlignItems::End => path!(AlignItems::End),
-            AlignItems::FlexStart => path!(AlignItems::FlexStart),
-            AlignItems::FlexEnd => path!(AlignItems::FlexEnd),
-            AlignItems::Baseline => path!(AlignItems::Baseline),
-            AlignItems::FirstBaseline => path!(AlignItems::FirstBaseline),
-            AlignItems::LastBaseline => path!(AlignItems::LastBaseline),
-            AlignItems::SafeCenter => path!(AlignItems::SafeCenter),
-            AlignItems::UnsafeCenter => path!(AlignItems::UnsafeCenter),
-        });
-    }
-}
-
-impl ToTokens for AlignSelf {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        tokens.extend(match self {
-            AlignSelf::Auto => path!(AlignSelf::Auto),
-            AlignSelf::Normal => path!(AlignSelf::Normal),
-            AlignSelf::Center => path!(AlignSelf::Center),
-            AlignSelf::Start => path!(AlignSelf::Start),
-            AlignSelf::End => path!(AlignSelf::End),
-            AlignSelf::SelfStart => path!(AlignSelf::SelfStart),
-            AlignSelf::SelfEnd => path!(AlignSelf::SelfEnd),
-            AlignSelf::FlexStart => path!(AlignSelf::FlexStart),
-            AlignSelf::FlexEnd => path!(AlignSelf::FlexEnd),
-            AlignSelf::Baseline => path!(AlignSelf::Baseline),
-            AlignSelf::FirstBaseline => path!(AlignSelf::FirstBaseline),
-            AlignSelf::LastBaseline => path!(AlignSelf::LastBaseline),
-            AlignSelf::Stretch => path!(AlignSelf::Stretch),
-            AlignSelf::SafeCenter => path!(AlignSelf::SafeCenter),
-            AlignSelf::UnsafeCenter => path!(AlignSelf::UnsafeCenter),
-        });
-    }
-}
-
-impl ToTokens for BackgroundAttachment {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        tokens.extend(match self {
-            BackgroundAttachment::Scroll => path!(BackgroundAttachment::Scroll),
-            BackgroundAttachment::Fixed => path!(BackgroundAttachment::Fixed),
-            BackgroundAttachment::Local => path!(BackgroundAttachment::Local),
-        })
-    }
-}
-
-impl ToTokens for BlendMode {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        tokens.extend(match self {
-            BlendMode::Normal => path!(BlendMode::Normal),
-            BlendMode::Multiply => path!(BlendMode::Multiply),
-            BlendMode::Screen => path!(BlendMode::Screen),
-            BlendMode::Overlay => path!(BlendMode::Overlay),
-            BlendMode::Darken => path!(BlendMode::Darken),
-            BlendMode::Lighten => path!(BlendMode::Lighten),
-            BlendMode::ColorDodge => path!(BlendMode::ColorDodge),
-            BlendMode::ColorBurn => path!(BlendMode::ColorBurn),
-            BlendMode::HardLight => path!(BlendMode::HardLight),
-            BlendMode::SoftLight => path!(BlendMode::SoftLight),
-            BlendMode::Difference => path!(BlendMode::Difference),
-            BlendMode::Exclusion => path!(BlendMode::Exclusion),
-            BlendMode::Hue => path!(BlendMode::Hue),
-            BlendMode::Saturation => path!(BlendMode::Saturation),
-            BlendMode::Color => path!(BlendMode::Color),
-            BlendMode::Luminosity => path!(BlendMode::Luminosity),
-        })
-    }
-}
-
-impl ToTokens for BackgroundBox {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        tokens.extend(match self {
-            BackgroundBox::BorderBox => path!(BackgroundBox::BorderBox),
-            BackgroundBox::PaddingBox => path!(BackgroundBox::PaddingBox),
-            BackgroundBox::ContentBox => path!(BackgroundBox::ContentBox),
-        })
-    }
-}
-
-impl ToTokens for BackgroundImage {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        tokens.extend(match self {
-            BackgroundImage::None => path!(BackgroundImage::None),
-            BackgroundImage::Url(url) => path!(BackgroundImage::Url(#url)),
-        })
-    }
-}
-
-impl ToTokens for BackgroundPosition {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        tokens.extend(match self {
-            BackgroundPosition::Top => path!(BackgroundPosition::Top),
-            BackgroundPosition::Bottom => path!(BackgroundPosition::Bottom),
-            BackgroundPosition::Left => path!(BackgroundPosition::Left),
-            BackgroundPosition::Right => path!(BackgroundPosition::Right),
-            BackgroundPosition::Center => path!(BackgroundPosition::Center),
-        })
-    }
-}
-
-impl ToTokens for BackgroundRepeat {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        tokens.extend(match self {
-            BackgroundRepeat::RepeatX => path!(BackgroundRepeat::RepeatX),
-            BackgroundRepeat::RepeatY => path!(BackgroundRepeat::RepeatY),
-            BackgroundRepeat::SingleOrDouble(v) => path!(BackgroundRepeat::SingleOrDouble(#v)),
-        })
-    }
-}
-
-impl ToTokens for BgRepeatPart {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        tokens.extend(match self {
-            BgRepeatPart::Repeat => path!(BgRepeatPart::Repeat),
-            BgRepeatPart::Space => path!(BgRepeatPart::Space),
-            BgRepeatPart::Round => path!(BgRepeatPart::Round),
-            BgRepeatPart::NoRepeat => path!(BgRepeatPart::NoRepeat),
-        })
-    }
-}
-
-impl ToTokens for BackgroundSize {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        tokens.extend(match self {
-            BackgroundSize::Cover => path!(BackgroundSize::Cover),
-            BackgroundSize::Contain => path!(BackgroundSize::Contain),
-            BackgroundSize::SingleOrDouble(v) => path!(BackgroundSize::SingleOrDouble(#v)),
-        })
-    }
-}
-
-impl ToTokens for BorderCollapse {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        tokens.extend(match self {
-            BorderCollapse::Collapse => path!(BorderCollapse::Collapse),
-            BorderCollapse::Separate => path!(BorderCollapse::Separate),
-        })
-    }
-}
-
-impl ToTokens for JustifyContent {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        tokens.extend(match self {
-            JustifyContent::FlexStart => path!(JustifyContent::FlexStart),
-            JustifyContent::Center => path!(JustifyContent::Center),
-            JustifyContent::FlexEnd => path!(JustifyContent::FlexEnd),
-            JustifyContent::SpaceAround => path!(JustifyContent::SpaceAround),
-            JustifyContent::SpaceBetween => path!(JustifyContent::SpaceBetween),
-        });
-    }
-}
-
-impl ToTokens for Float {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        tokens.extend(match self {
-            Float::None => path!(Float::None),
-            Float::Left => path!(Float::Left),
-            Float::Right => path!(Float::Right),
-            Float::InlineStart => path!(Float::InlineStart),
-            Float::InlineEnd => path!(Float::InlineEnd),
-        })
-    }
-}
-
-impl ToTokens for FontWeight {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        tokens.extend(match self {
-            FontWeight::Normal => path!(FontWeight::Normal),
-            FontWeight::Bold => path!(FontWeight::Bold),
-            FontWeight::Lighter => path!(FontWeight::Lighter),
-            FontWeight::Bolder => path!(FontWeight::Bolder),
-            FontWeight::Number(v) => path!(FontWeight::Number(#v)),
-        });
-    }
-}
-
-impl ToTokens for Font {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        tokens.extend(match self {
-            Font::Named(inner) => path!(Font::Named(String::from(#inner))),
-            Font::Serif => path!(Font::Serif),
-            Font::SansSerif => path!(Font::SansSerif),
-            Font::Cursive => path!(Font::Cursive),
-            Font::Fantasy => path!(Font::Fantasy),
-            Font::Monospace => path!(Font::Monospace),
-        })
-    }
-}
-
-impl ToTokens for FontSize {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        tokens.extend(match self {
-            FontSize::XXSmall => path!(FontSize::XXSmall),
-            FontSize::XSmall => path!(FontSize::XSmall),
-            FontSize::Small => path!(FontSize::Small),
-            FontSize::Medium => path!(FontSize::Medium),
-            FontSize::Large => path!(FontSize::Large),
-            FontSize::XLarge => path!(FontSize::XLarge),
-            FontSize::XXLarge => path!(FontSize::XXLarge),
-            FontSize::XXXLarge => path!(FontSize::XXXLarge),
-            FontSize::Larger => path!(FontSize::Larger),
-            FontSize::Smaller => path!(FontSize::Smaller),
-            FontSize::LengthPercentage(v) => path!(FontSize::LengthPercentage(#v)),
-        });
-    }
-}
-
-impl ToTokens for FontStyle {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        tokens.extend(match self {
-            FontStyle::Normal => path!(FontStyle::Normal),
-            FontStyle::Italic => path!(FontStyle::Italic),
-            FontStyle::Oblique => path!(FontStyle::Oblique),
-        });
-    }
-}
-
-impl ToTokens for Border {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        let line_width = match self.line_width {
-            Some(line_width) => quote!(Some(#line_width)),
-            None => quote!(None),
-        };
-        let line_style = match self.line_style {
-            Some(line_style) => quote!(Some(#line_style)),
-            None => quote!(None),
-        };
-        let color = match self.color {
-            Some(color) => quote!(Some(#color)),
-            None => quote!(None),
-        };
-        tokens.extend(quote!(
-            style::Border {
-                line_width: #line_width,
-                line_style: #line_style,
-                color: #color,
-            }
-        ))
-    }
-}
-
-impl ToTokens for BoxShadow {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        tokens.extend(match self {
-            BoxShadow::None => path!(BoxShadow::None),
-            BoxShadow::Shadows(list) => path!(BoxShadow::Shadows(#list)),
-        });
-    }
-}
-
-impl ToTokens for BoxSizing {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        tokens.extend(match self {
-            BoxSizing::BorderBox => path!(BoxSizing::BorderBox),
-            BoxSizing::ContentBox => path!(BoxSizing::ContentBox),
-        });
-    }
-}
-
-impl ToTokens for Clear {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        tokens.extend(match self {
-            Clear::None => path!(Clear::None),
-            Clear::Left => path!(Clear::Left),
-            Clear::Right => path!(Clear::Right),
-            Clear::Both => path!(Clear::Both),
-            Clear::InlineStart => path!(Clear::InlineStart),
-            Clear::InlineEnd => path!(Clear::InlineEnd),
-        })
-    }
-}
-
-impl ToTokens for ColumnCount {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        tokens.extend(match self {
-            ColumnCount::Auto => path!(ColumnCount::Auto),
-            ColumnCount::Fixed(v) => path!(ColumnCount::Fixed(#v)),
-        })
-    }
-}
-
-impl ToTokens for Overflow {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        tokens.extend(match self {
-            Overflow::Both(v) => path!(Overflow::Both(#v)),
-            Overflow::XY(x, y) => path!(Overflow::XY(#x, #y)),
-        })
-    }
-}
-
-impl ToTokens for OverflowXY {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        tokens.extend(match self {
-            OverflowXY::Visible => path!(OverflowXY::Visible),
-            OverflowXY::Hidden => path!(OverflowXY::Hidden),
-            OverflowXY::Clip => path!(OverflowXY::Clip),
-            OverflowXY::Scroll => path!(OverflowXY::Scroll),
-            OverflowXY::Auto => path!(OverflowXY::Auto),
-        })
-    }
-}
-
-impl ToTokens for ObjectFit {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        tokens.extend(match self {
-            ObjectFit::Fill => path!(ObjectFit::Fill),
-            ObjectFit::None => path!(ObjectFit::None),
-            ObjectFit::Contain { scale_down } => {
-                path!(ObjectFit::Contain { scale_down: #scale_down })
-            }
-            ObjectFit::Cover { scale_down } => path!(ObjectFit::Cover { scale_down: #scale_down }),
-        })
-    }
-}
-
-impl<T> ToTokens for Rect<T>
-where
-    T: ToTokens,
-{
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        tokens.extend(match self {
-            Rect::All(v) => path!(Rect::All(#v)),
-            Rect::VerticalHorizontal(v, h) => path!(Rect::VerticalHorizontal(#v, #h)),
-            Rect::TopHorizontalBottom(t, h, b) => path!(Rect::TopHorizontalBottom(#t, #h, #b)),
-            Rect::TopRightBottomLeft(t, r, b, l) => path!(Rect::TopRightBottomLeft(#t, #r, #b, #l)),
-        });
-    }
-}
-
-impl ToTokens for LengthPercentage {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        tokens.extend(match self {
-            LengthPercentage::Length(v) => path!(LengthPercentage::Length(#v)),
-            LengthPercentage::Percentage(v) => path!(LengthPercentage::Percentage(#v)),
-        });
-    }
-}
-
-impl ToTokens for AutoLengthPercentage {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        tokens.extend(match self {
-            AutoLengthPercentage::LengthPercentage(v) => {
-                path!(AutoLengthPercentage::LengthPercentage(#v))
-            }
-            AutoLengthPercentage::Auto => path!(AutoLengthPercentage::Auto),
-        });
-    }
-}
-
-impl ToTokens for LineStyle {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        tokens.extend(match self {
-            LineStyle::None => path!(LineStyle::None),
-            LineStyle::Hidden => path!(LineStyle::Hidden),
-            LineStyle::Dotted => path!(LineStyle::Dotted),
-            LineStyle::Dashed => path!(LineStyle::Dashed),
-            LineStyle::Solid => path!(LineStyle::Solid),
-            LineStyle::Double => path!(LineStyle::Double),
-            LineStyle::Groove => path!(LineStyle::Groove),
-            LineStyle::Ridge => path!(LineStyle::Ridge),
-            LineStyle::Inset => path!(LineStyle::Inset),
-            LineStyle::Outset => path!(LineStyle::Outset),
-        })
-    }
-}
-
-impl ToTokens for LineWidth {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        tokens.extend(match self {
-            LineWidth::Length(length) => path!(LineWidth::Length(#length)),
-            LineWidth::Thin => path!(LineWidth::Thin),
-            LineWidth::Medium => path!(LineWidth::Medium),
-            LineWidth::Thick => path!(LineWidth::Thick),
-        })
-    }
-}
-
-impl ToTokens for LineHeight {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        self.0.to_tokens(tokens)
-    }
-}
-
-impl ToTokens for ListStyleType {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        tokens.extend(match self {
-            ListStyleType::Disc => path!(ListStyleType::Disc),
-            ListStyleType::Circle => path!(ListStyleType::Circle),
-            ListStyleType::Square => path!(ListStyleType::Square),
-            ListStyleType::Decimal => path!(ListStyleType::Decimal),
-            ListStyleType::DecimalLeadingZero => path!(ListStyleType::DecimalLeadingZero),
-            ListStyleType::LowerRoman => path!(ListStyleType::LowerRoman),
-            ListStyleType::UpperRoman => path!(ListStyleType::UpperRoman),
-            ListStyleType::LowerGreek => path!(ListStyleType::LowerGreek),
-            ListStyleType::UpperGreek => path!(ListStyleType::UpperGreek),
-            ListStyleType::LowerLatin => path!(ListStyleType::LowerLatin),
-            ListStyleType::UpperLatin => path!(ListStyleType::UpperLatin),
-            ListStyleType::Armenian => path!(ListStyleType::Armenian),
-            ListStyleType::Georgian => path!(ListStyleType::Georgian),
-            ListStyleType::LowerAlpha => path!(ListStyleType::LowerAlpha),
-            ListStyleType::UpperAlpha => path!(ListStyleType::UpperAlpha),
-            ListStyleType::None => path!(ListStyleType::None),
-        })
-    }
-}
-
-impl ToTokens for Position {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        tokens.extend(match self {
-            Position::Static => path!(Position::Static),
-            Position::Relative => path!(Position::Relative),
-            Position::Absolute => path!(Position::Absolute),
-            Position::Fixed => path!(Position::Fixed),
-        })
-    }
-}
-
-impl ToTokens for Resize {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        tokens.extend(match self {
-            Resize::None => path!(Resize::None),
-            Resize::Both => path!(Resize::Both),
-            Resize::Horizontal => path!(Resize::Horizontal),
-            Resize::Vertical => path!(Resize::Vertical),
-        })
-    }
-}
-
-impl ToTokens for WhiteSpace {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        tokens.extend(match self {
-            WhiteSpace::Normal => path!(WhiteSpace::Normal),
-            WhiteSpace::Pre => path!(WhiteSpace::Pre),
-            WhiteSpace::Nowrap => path!(WhiteSpace::Nowrap),
-            WhiteSpace::PreWrap => path!(WhiteSpace::PreWrap),
-            WhiteSpace::PreLine => path!(WhiteSpace::PreLine),
-        })
-    }
-}
-
-impl ToTokens for WidthHeight {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        tokens.extend(match self {
-            WidthHeight::Auto => path!(WidthHeight::Auto),
-            WidthHeight::LengthPercentage(v) => path!(WidthHeight::LengthPercentage(#v)),
-            WidthHeight::MinContent => path!(WidthHeight::MinContent),
-            WidthHeight::MaxContent => path!(WidthHeight::MaxContent),
-            WidthHeight::FitContent(v) => path!(WidthHeight::FitContent(#v)),
-        })
-    }
-}
-
-impl ToTokens for MaxWidthHeight {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        tokens.extend(match self {
-            MaxWidthHeight::None => path!(MaxWidthHeight::None),
-            MaxWidthHeight::LengthPercentage(v) => path!(MaxWidthHeight::LengthPercentage(#v)),
-            MaxWidthHeight::MinContent => path!(MaxWidthHeight::MinContent),
-            MaxWidthHeight::MaxContent => path!(MaxWidthHeight::MaxContent),
-            MaxWidthHeight::FitContent(v) => path!(MaxWidthHeight::FitContent(#v)),
-        })
-    }
-}
-
-impl ToTokens for Width21 {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        tokens.extend(match self {
-            Width21::Auto => path!(Width21::Auto),
-            Width21::LengthPercentage(v) => path!(Width21::LengthPercentage(#v)),
-        })
-    }
-}
-
-impl ToTokens for Shadow {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        let color = match self.color.as_ref() {
-            Some(color) => quote!(Some(#color)),
-            None => quote!(None),
-        };
-        let length = &self.length;
-        let inset = &self.inset;
-        tokens.extend(quote! {
-            style::Shadow {
-                color: #color,
-                length: #length,
-                inset: #inset,
-            }
-        })
-    }
-}
-
-impl ToTokens for ShadowLength {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        tokens.extend(match self {
-            ShadowLength::Offsets {
-                vertical,
-                horizontal,
-            } => path!(ShadowLength::Offsets {
-                vertical: #vertical,
-                horizontal: #horizontal,
-            }),
-            ShadowLength::OffsetsBlur {
-                vertical,
-                horizontal,
-                blur,
-            } => path!(ShadowLength::OffsetsBlur {
-                vertical: #vertical,
-                horizontal: #horizontal,
-                blur: #blur,
-            }),
-            ShadowLength::OffsetsBlurSpread {
-                vertical,
-                horizontal,
-                blur,
-                spread,
-            } => path!(ShadowLength::Offsets {
-                vertical: #vertical,
-                horizontal: #horizontal,
-                blur: #blur,
-                spread: #spread,
-            }),
-        })
-    }
-}
-
-impl ToTokens for TextAlign {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        tokens.extend(match self {
-            TextAlign::Left => path!(TextAlign::Left),
-            TextAlign::Right => path!(TextAlign::Right),
-            TextAlign::Center => path!(TextAlign::Center),
-            TextAlign::Justify => path!(TextAlign::Justify),
-        });
-    }
-}
-
-impl ToTokens for Length {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        tokens.extend(match self {
-            Length::Em(v) => path!(Length::Em(#v)),
-            Length::Ex(v) => path!(Length::Ex(#v)),
-            Length::In(v) => path!(Length::In(#v)),
-            Length::Cm(v) => path!(Length::Cm(#v)),
-            Length::Mm(v) => path!(Length::Mm(#v)),
-            Length::Pt(v) => path!(Length::Pt(#v)),
-            Length::Pc(v) => path!(Length::Pc(#v)),
-            Length::Px(v) => path!(Length::Px(#v)),
-            Length::Zero => path!(Length::Zero),
-        })
-    }
-}
-
-impl ToTokens for Percentage {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        let val = self.0;
-        tokens.extend(path!(Percentage(#val)));
-    }
-}
-
-impl ToTokens for DynamicColor {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        tokens.extend(match self {
-            DynamicColor::Dynamic(block) => path!(DynamicColor::Literal(#block)),
-            DynamicColor::Literal(color) => path!(DynamicColor::Literal(#color)),
-        })
-    }
-}
-
-impl ToTokens for Color {
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        tokens.extend(match self {
-            Color::HexRGB(r, g, b) => path!(Color::HexRGB(#r, #g, #b)),
-            Color::HexRGBA(r, g, b, a) => path!(Color::HexRGB(#r, #g, #b, #a)),
-            Color::HSL(h, s, l) => path!(Color::HSL(#h, #s, #l)),
-            Color::HSLA(h, s, l, a) => path!(Color::HSLA(#h, #s, #l, #a)),
-            Color::IndianRed => path!(Color::IndianRed),
-            Color::LightCoral => path!(Color::LightCoral),
-            Color::Salmon => path!(Color::Salmon),
-            Color::DarkSalmon => path!(Color::DarkSalmon),
-            Color::LightSalmon => path!(Color::LightSalmon),
-            Color::Crimson => path!(Color::Crimson),
-            Color::Red => path!(Color::Red),
-            Color::FireBrick => path!(Color::FireBrick),
-            Color::DarkRed => path!(Color::DarkRed),
-            Color::Pink => path!(Color::Pink),
-            Color::LightPink => path!(Color::LightPink),
-            Color::HotPink => path!(Color::HotPink),
-            Color::DeepPink => path!(Color::DeepPink),
-            Color::MediumVioletRed => path!(Color::MediumVioletRed),
-            Color::PaleVioletRed => path!(Color::PaleVioletRed),
-            Color::Coral => path!(Color::Coral),
-            Color::Tomato => path!(Color::Tomato),
-            Color::OrangeRed => path!(Color::OrangeRed),
-            Color::DarkOrange => path!(Color::DarkOrange),
-            Color::Orange => path!(Color::Orange),
-            Color::Gold => path!(Color::Gold),
-            Color::Yellow => path!(Color::Yellow),
-            Color::LightYellow => path!(Color::LightYellow),
-            Color::LemonChiffon => path!(Color::LemonChiffon),
-            Color::LightGoldenrodYellow => path!(Color::LightGoldenrodYellow),
-            Color::PapayaWhip => path!(Color::PapayaWhip),
-            Color::Moccasin => path!(Color::Moccasin),
-            Color::PeachPuff => path!(Color::PeachPuff),
-            Color::PaleGoldenrod => path!(Color::PaleGoldenrod),
-            Color::Khaki => path!(Color::Khaki),
-            Color::DarkKhaki => path!(Color::DarkKhaki),
-            Color::Lavender => path!(Color::Lavender),
-            Color::Thistle => path!(Color::Thistle),
-            Color::Plum => path!(Color::Plum),
-            Color::Violet => path!(Color::Violet),
-            Color::Orchid => path!(Color::Orchid),
-            Color::Fuchsia => path!(Color::Fuchsia),
-            Color::Magenta => path!(Color::Magenta),
-            Color::MediumOrchid => path!(Color::MediumOrchid),
-            Color::MediumPurple => path!(Color::MediumPurple),
-            Color::RebeccaPurple => path!(Color::RebeccaPurple),
-            Color::BlueViolet => path!(Color::BlueViolet),
-            Color::DarkViolet => path!(Color::DarkViolet),
-            Color::DarkOrchid => path!(Color::DarkOrchid),
-            Color::DarkMagenta => path!(Color::DarkMagenta),
-            Color::Purple => path!(Color::Purple),
-            Color::Indigo => path!(Color::Indigo),
-            Color::SlateBlue => path!(Color::SlateBlue),
-            Color::DarkSlateBlue => path!(Color::DarkSlateBlue),
-            Color::MediumSlateBlue => path!(Color::MediumSlateBlue),
-            Color::GreenYellow => path!(Color::GreenYellow),
-            Color::Chartreuse => path!(Color::Chartreuse),
-            Color::LawnGreen => path!(Color::LawnGreen),
-            Color::Lime => path!(Color::Lime),
-            Color::LimeGreen => path!(Color::LimeGreen),
-            Color::PaleGreen => path!(Color::PaleGreen),
-            Color::LightGreen => path!(Color::LightGreen),
-            Color::MediumSpringGreen => path!(Color::MediumSpringGreen),
-            Color::SpringGreen => path!(Color::SpringGreen),
-            Color::MediumSeaGreen => path!(Color::MediumSeaGreen),
-            Color::SeaGreen => path!(Color::SeaGreen),
-            Color::ForestGreen => path!(Color::ForestGreen),
-            Color::Green => path!(Color::Green),
-            Color::DarkGreen => path!(Color::DarkGreen),
-            Color::YellowGreen => path!(Color::YellowGreen),
-            Color::OliveDrab => path!(Color::OliveDrab),
-            Color::Olive => path!(Color::Olive),
-            Color::DarkOliveGreen => path!(Color::DarkOliveGreen),
-            Color::MediumAquamarine => path!(Color::MediumAquamarine),
-            Color::DarkSeaGreen => path!(Color::DarkSeaGreen),
-            Color::LightSeaGreen => path!(Color::LightSeaGreen),
-            Color::DarkCyan => path!(Color::DarkCyan),
-            Color::Teal => path!(Color::Teal),
-            Color::Aqua => path!(Color::Aqua),
-            Color::Cyan => path!(Color::Cyan),
-            Color::LightCyan => path!(Color::LightCyan),
-            Color::PaleTurquoise => path!(Color::PaleTurquoise),
-            Color::Aquamarine => path!(Color::Aquamarine),
-            Color::Turquoise => path!(Color::Turquoise),
-            Color::MediumTurquoise => path!(Color::MediumTurquoise),
-            Color::DarkTurquoise => path!(Color::DarkTurquoise),
-            Color::CadetBlue => path!(Color::CadetBlue),
-            Color::SteelBlue => path!(Color::SteelBlue),
-            Color::LightSteelBlue => path!(Color::LightSteelBlue),
-            Color::PowderBlue => path!(Color::PowderBlue),
-            Color::LightBlue => path!(Color::LightBlue),
-            Color::SkyBlue => path!(Color::SkyBlue),
-            Color::LightSkyBlue => path!(Color::LightSkyBlue),
-            Color::DeepSkyBlue => path!(Color::DeepSkyBlue),
-            Color::DodgerBlue => path!(Color::DodgerBlue),
-            Color::CornflowerBlue => path!(Color::CornflowerBlue),
-            Color::RoyalBlue => path!(Color::RoyalBlue),
-            Color::Blue => path!(Color::Blue),
-            Color::MediumBlue => path!(Color::MediumBlue),
-            Color::DarkBlue => path!(Color::DarkBlue),
-            Color::Navy => path!(Color::Navy),
-            Color::MidnightBlue => path!(Color::MidnightBlue),
-            Color::Cornsilk => path!(Color::Cornsilk),
-            Color::BlanchedAlmond => path!(Color::BlanchedAlmond),
-            Color::Bisque => path!(Color::Bisque),
-            Color::NavajoWhite => path!(Color::NavajoWhite),
-            Color::Wheat => path!(Color::Wheat),
-            Color::BurlyWood => path!(Color::BurlyWood),
-            Color::Tan => path!(Color::Tan),
-            Color::RosyBrown => path!(Color::RosyBrown),
-            Color::SandyBrown => path!(Color::SandyBrown),
-            Color::Goldenrod => path!(Color::Goldenrod),
-            Color::DarkGoldenrod => path!(Color::DarkGoldenrod),
-            Color::Peru => path!(Color::Peru),
-            Color::Chocolate => path!(Color::Chocolate),
-            Color::SaddleBrown => path!(Color::SaddleBrown),
-            Color::Sienna => path!(Color::Sienna),
-            Color::Brown => path!(Color::Brown),
-            Color::Maroon => path!(Color::Maroon),
-            Color::White => path!(Color::White),
-            Color::Snow => path!(Color::Snow),
-            Color::HoneyDew => path!(Color::HoneyDew),
-            Color::MintCream => path!(Color::MintCream),
-            Color::Azure => path!(Color::Azure),
-            Color::AliceBlue => path!(Color::AliceBlue),
-            Color::GhostWhite => path!(Color::GhostWhite),
-            Color::WhiteSmoke => path!(Color::WhiteSmoke),
-            Color::SeaShell => path!(Color::SeaShell),
-            Color::Beige => path!(Color::Beige),
-            Color::OldLace => path!(Color::OldLace),
-            Color::FloralWhite => path!(Color::FloralWhite),
-            Color::Ivory => path!(Color::Ivory),
-            Color::AntiqueWhite => path!(Color::AntiqueWhite),
-            Color::Linen => path!(Color::Linen),
-            Color::LavenderBlush => path!(Color::LavenderBlush),
-            Color::MistyRose => path!(Color::MistyRose),
-            Color::Gainsboro => path!(Color::Gainsboro),
-            Color::LightGray => path!(Color::LightGray),
-            Color::Silver => path!(Color::Silver),
-            Color::DarkGray => path!(Color::DarkGray),
-            Color::Gray => path!(Color::Gray),
-            Color::DimGray => path!(Color::DimGray),
-            Color::LightSlateGray => path!(Color::LightSlateGray),
-            Color::SlateGray => path!(Color::SlateGray),
-            Color::DarkSlateGray => path!(Color::DarkSlateGray),
-            Color::Black => path!(Color::Black),
-        })
-    }
-}
-
-// Generic containers
-
-impl<T> ToTokens for NonemptyCommaList<T>
-where
-    T: ToTokens,
-{
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        let first = &self.first;
-        let rest = &self.rest;
-        tokens.extend(path! {
-            NonemptyCommaList {
-                first: #first,
-                rest: vec![#(#rest),*],
-            }
-        })
-    }
-}
-
-impl<T> ToTokens for SingleOrDouble<T>
-where
-    T: ToTokens,
-{
-    fn to_tokens(&self, tokens: &mut TokenStream) {
-        tokens.extend(match self {
-            SingleOrDouble::Single(t) => path!(SingleOrDouble::Single(#t)),
-            SingleOrDouble::Double { vert, horiz } => path!(SingleOrDouble::Double {
-                vert: #vert,
-                horiz: #horiz,
-            }),
-        })
-    }
-}

+ 0 - 854
packages/core-macro/styles/color.rs

@@ -1,854 +0,0 @@
-use std::fmt;
-
-/// A color that possibly is possibly code, rather than a literal
-#[derive(Debug, Clone, PartialEq)]
-pub enum DynamicColor {
-    Literal(Color),
-    /// The type of the block is not checked here (it is checked by typeck).
-    Dynamic(syn::Block),
-}
-
-impl DynamicColor {
-    pub fn is_dynamic(&self) -> bool {
-        match self {
-            DynamicColor::Dynamic(_) => true,
-            DynamicColor::Literal(_) => false,
-        }
-    }
-}
-
-impl fmt::Display for DynamicColor {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            DynamicColor::Dynamic(_) => Ok(()),
-            DynamicColor::Literal(color) => color.fmt(f),
-        }
-    }
-}
-
-// TODO other color variants.
-#[derive(Debug, Clone, Copy, PartialEq)]
-#[non_exhaustive]
-pub enum Color {
-    HexRGB(u8, u8, u8),
-    HexRGBA(u8, u8, u8, u8),
-    // Invariants: `0 <= .0 < 360`, `0 <= .1 < 100`, `0 <= .2 < 100`.
-    HSL(f64, f64, f64),
-    // Invariants: `0 <= .0 < 360`, `0 <= .1 < 100`, `0 <= .2 < 100`, `0 <= .3 < 1`.
-    HSLA(f64, f64, f64, f64),
-
-    // Red HTML Color Names
-    /// rgb(205, 92, 92)
-    IndianRed,
-    /// rgb(240, 128, 128)
-    LightCoral,
-    /// rgb(250, 128, 114)
-    Salmon,
-    /// rgb(233, 150, 122)
-    DarkSalmon,
-    /// rgb(255, 160, 122)
-    LightSalmon,
-    /// rgb(220, 20, 60)
-    Crimson,
-    /// rgb(255, 0, 0)
-    Red,
-    /// rgb(178, 34, 34)
-    FireBrick,
-    /// rgb(139, 0, 0)
-    DarkRed,
-    // Pink HTML Color Names
-    /// rgb(255, 192, 203)
-    Pink,
-    /// rgb(255, 182, 193)
-    LightPink,
-    /// rgb(255, 105, 180)
-    HotPink,
-    /// rgb(255, 20, 147)
-    DeepPink,
-    /// rgb(199, 21, 133)
-    MediumVioletRed,
-    /// rgb(219, 112, 147)
-    PaleVioletRed,
-    //Orange HTML Color Names
-    // /// rgb(255, 160, 122) redefined
-    // LightSalmon,
-    /// rgb(255, 127, 80)
-    Coral,
-    /// rgb(255, 99, 71)
-    Tomato,
-    /// rgb(255, 69, 0)
-    OrangeRed,
-    /// rgb(255, 140, 0)
-    DarkOrange,
-    /// rgb(255, 165, 0)
-    Orange,
-    // Yellow HTML Color Names
-    /// rgb(255, 215, 0)
-    Gold,
-    /// rgb(255, 255, 0)
-    Yellow,
-    /// rgb(255, 255, 224)
-    LightYellow,
-    /// rgb(255, 250, 205)
-    LemonChiffon,
-    /// rgb(250, 250, 210)
-    LightGoldenrodYellow,
-    /// rgb(255, 239, 213)
-    PapayaWhip,
-    /// rgb(255, 228, 181)
-    Moccasin,
-    /// rgb(255, 218, 185)
-    PeachPuff,
-    /// rgb(238, 232, 170)
-    PaleGoldenrod,
-    /// rgb(240, 230, 140)
-    Khaki,
-    /// rgb(189, 183, 107)
-    DarkKhaki,
-    // Purple HTML Color Names
-    /// rgb(230, 230, 250)
-    Lavender,
-    /// rgb(216, 191, 216)
-    Thistle,
-    /// rgb(221, 160, 221)
-    Plum,
-    /// rgb(238, 130, 238)
-    Violet,
-    /// rgb(218, 112, 214)
-    Orchid,
-    /// rgb(255, 0, 255)
-    Fuchsia,
-    /// rgb(255, 0, 255)
-    Magenta,
-    /// rgb(186, 85, 211)
-    MediumOrchid,
-    /// rgb(147, 112, 219)
-    MediumPurple,
-    /// rgb(102, 51, 153)
-    RebeccaPurple,
-    /// rgb(138, 43, 226)
-    BlueViolet,
-    /// rgb(148, 0, 211)
-    DarkViolet,
-    /// rgb(153, 50, 204)
-    DarkOrchid,
-    /// rgb(139, 0, 139)
-    DarkMagenta,
-    /// rgb(128, 0, 128)
-    Purple,
-    /// rgb(75, 0, 130)
-    Indigo,
-    /// rgb(106, 90, 205)
-    SlateBlue,
-    /// rgb(72, 61, 139)
-    DarkSlateBlue,
-    /// rgb(123, 104, 238)
-    MediumSlateBlue,
-    // Green HTML Color Names
-    /// rgb(173, 255, 47)
-    GreenYellow,
-    /// rgb(127, 255, 0)
-    Chartreuse,
-    /// rgb(124, 252, 0)
-    LawnGreen,
-    /// rgb(0, 255, 0)
-    Lime,
-    /// rgb(50, 205, 50)
-    LimeGreen,
-    /// rgb(152, 251, 152)
-    PaleGreen,
-    /// rgb(144, 238, 144)
-    LightGreen,
-    /// rgb(0, 250, 154)
-    MediumSpringGreen,
-    /// rgb(0, 255, 127)
-    SpringGreen,
-    /// rgb(60, 179, 113)
-    MediumSeaGreen,
-    /// rgb(46, 139, 87)
-    SeaGreen,
-    /// rgb(34, 139, 34)
-    ForestGreen,
-    /// rgb(0, 128, 0)
-    Green,
-    /// rgb(0, 100, 0)
-    DarkGreen,
-    /// rgb(154, 205, 50)
-    YellowGreen,
-    /// rgb(107, 142, 35)
-    OliveDrab,
-    /// rgb(128, 128, 0)
-    Olive,
-    /// rgb(85, 107, 47)
-    DarkOliveGreen,
-    /// rgb(102, 205, 170)
-    MediumAquamarine,
-    /// rgb(143, 188, 139)
-    DarkSeaGreen,
-    /// rgb(32, 178, 170)
-    LightSeaGreen,
-    /// rgb(0, 139, 139)
-    DarkCyan,
-    /// rgb(0, 128, 128)
-    Teal,
-    // Blue HTML Color Names
-    /// rgb(0, 255, 255)
-    Aqua,
-    /// rgb(0, 255, 255)
-    Cyan,
-    /// rgb(224, 255, 255)
-    LightCyan,
-    /// rgb(175, 238, 238)
-    PaleTurquoise,
-    /// rgb(127, 255, 212)
-    Aquamarine,
-    /// rgb(64, 224, 208)
-    Turquoise,
-    /// rgb(72, 209, 204)
-    MediumTurquoise,
-    /// rgb(0, 206, 209)
-    DarkTurquoise,
-    /// rgb(95, 158, 160)
-    CadetBlue,
-    /// rgb(70, 130, 180)
-    SteelBlue,
-    /// rgb(176, 196, 222)
-    LightSteelBlue,
-    /// rgb(176, 224, 230)
-    PowderBlue,
-    /// rgb(173, 216, 230)
-    LightBlue,
-    /// rgb(135, 206, 235)
-    SkyBlue,
-    /// rgb(135, 206, 250)
-    LightSkyBlue,
-    /// rgb(0, 191, 255)
-    DeepSkyBlue,
-    /// rgb(30, 144, 255)
-    DodgerBlue,
-    /// rgb(100, 149, 237)
-    CornflowerBlue,
-    // /// rgb(123, 104, 238) duplicate
-    //MediumSlateBlue,
-    /// rgb(65, 105, 225)
-    RoyalBlue,
-    /// rgb(0, 0, 255)
-    Blue,
-    /// rgb(0, 0, 205)
-    MediumBlue,
-    /// rgb(0, 0, 139)
-    DarkBlue,
-    /// rgb(0, 0, 128)
-    Navy,
-    /// rgb(25, 25, 112)
-    MidnightBlue,
-    // Brown HTML Color Names
-    /// rgb(255, 248, 220)
-    Cornsilk,
-    /// rgb(255, 235, 205)
-    BlanchedAlmond,
-    /// rgb(255, 228, 196)
-    Bisque,
-    /// rgb(255, 222, 173)
-    NavajoWhite,
-    /// rgb(245, 222, 179)
-    Wheat,
-    /// rgb(222, 184, 135)
-    BurlyWood,
-    /// rgb(210, 180, 140)
-    Tan,
-    /// rgb(188, 143, 143)
-    RosyBrown,
-    /// rgb(244, 164, 96)
-    SandyBrown,
-    /// rgb(218, 165, 32)
-    Goldenrod,
-    /// rgb(184, 134, 11)
-    DarkGoldenrod,
-    /// rgb(205, 133, 63)
-    Peru,
-    /// rgb(210, 105, 30)
-    Chocolate,
-    /// rgb(139, 69, 19)
-    SaddleBrown,
-    /// rgb(160, 82, 45)
-    Sienna,
-    /// rgb(165, 42, 42)
-    Brown,
-    /// rgb(128, 0, 0)
-    Maroon,
-    // White HTML Color Names
-    /// rgb(255, 255, 255)
-    White,
-    /// rgb(255, 250, 250)
-    Snow,
-    /// rgb(240, 255, 240)
-    HoneyDew,
-    /// rgb(245, 255, 250)
-    MintCream,
-    /// rgb(240, 255, 255)
-    Azure,
-    /// rgb(240, 248, 255)
-    AliceBlue,
-    /// rgb(248, 248, 255)
-    GhostWhite,
-    /// rgb(245, 245, 245)
-    WhiteSmoke,
-    /// rgb(255, 245, 238)
-    SeaShell,
-    /// rgb(245, 245, 220)
-    Beige,
-    /// rgb(253, 245, 230)
-    OldLace,
-    /// rgb(255, 250, 240)
-    FloralWhite,
-    /// rgb(255, 255, 240)
-    Ivory,
-    /// rgb(250, 235, 215)
-    AntiqueWhite,
-    /// rgb(250, 240, 230)
-    Linen,
-    /// rgb(255, 240, 245)
-    LavenderBlush,
-    /// rgb(255, 228, 225)
-    MistyRose,
-    // Gray HTML Color Names
-    /// rgb(220, 220, 220)
-    Gainsboro,
-    /// rgb(211, 211, 211)
-    LightGray,
-    /// rgb(192, 192, 192)
-    Silver,
-    /// rgb(169, 169, 169)
-    DarkGray,
-    /// rgb(128, 128, 128)
-    Gray,
-    /// rgb(105, 105, 105)
-    DimGray,
-    /// rgb(119, 136, 153)
-    LightSlateGray,
-    /// rgb(112, 128, 144)
-    SlateGray,
-    /// rgb(47, 79, 79)
-    DarkSlateGray,
-    /// rgb(0, 0, 0)
-    Black,
-}
-
-impl Color {
-    // todo similar for others
-    pub fn to_rgb(self) -> Color {
-        use Color::*;
-        match self {
-            HexRGB(r, g, b) => HexRGB(r, g, b),
-            HexRGBA(r, g, b, _) => HexRGB(r, g, b),
-            HSL(h, s, l) => {
-                let s = s * 0.01; // percent conversion
-                let l = l * 0.01; // percent conversion
-                let (r, g, b) = hsl_to_rgb(h, s, l);
-                HexRGB((r * 255.0) as u8, (g * 255.0) as u8, (b * 255.0) as u8)
-            }
-            HSLA(h, s, l, _) => Color::to_rgb(HSL(h, s, l)),
-            IndianRed => HexRGB(205, 92, 92),
-            LightCoral => HexRGB(240, 128, 128),
-            Salmon => HexRGB(250, 128, 114),
-            DarkSalmon => HexRGB(233, 150, 122),
-            LightSalmon => HexRGB(255, 160, 122),
-            Crimson => HexRGB(220, 20, 60),
-            Red => HexRGB(255, 0, 0),
-            FireBrick => HexRGB(178, 34, 34),
-            DarkRed => HexRGB(139, 0, 0),
-            Pink => HexRGB(255, 192, 203),
-            LightPink => HexRGB(255, 182, 193),
-            HotPink => HexRGB(255, 105, 180),
-            DeepPink => HexRGB(255, 20, 147),
-            MediumVioletRed => HexRGB(199, 21, 133),
-            PaleVioletRed => HexRGB(219, 112, 147),
-            Coral => HexRGB(255, 127, 80),
-            Tomato => HexRGB(255, 99, 71),
-            OrangeRed => HexRGB(255, 69, 0),
-            DarkOrange => HexRGB(255, 140, 0),
-            Orange => HexRGB(255, 165, 0),
-            Gold => HexRGB(255, 215, 0),
-            Yellow => HexRGB(255, 255, 0),
-            LightYellow => HexRGB(255, 255, 224),
-            LemonChiffon => HexRGB(255, 250, 205),
-            LightGoldenrodYellow => HexRGB(250, 250, 210),
-            PapayaWhip => HexRGB(255, 239, 213),
-            Moccasin => HexRGB(255, 228, 181),
-            PeachPuff => HexRGB(255, 218, 185),
-            PaleGoldenrod => HexRGB(238, 232, 170),
-            Khaki => HexRGB(240, 230, 140),
-            DarkKhaki => HexRGB(189, 183, 107),
-            Lavender => HexRGB(230, 230, 250),
-            Thistle => HexRGB(216, 191, 216),
-            Plum => HexRGB(221, 160, 221),
-            Violet => HexRGB(238, 130, 238),
-            Orchid => HexRGB(218, 112, 214),
-            Fuchsia => HexRGB(255, 0, 255),
-            Magenta => HexRGB(255, 0, 255),
-            MediumOrchid => HexRGB(186, 85, 211),
-            MediumPurple => HexRGB(147, 112, 219),
-            RebeccaPurple => HexRGB(102, 51, 153),
-            BlueViolet => HexRGB(138, 43, 226),
-            DarkViolet => HexRGB(148, 0, 211),
-            DarkOrchid => HexRGB(153, 50, 204),
-            DarkMagenta => HexRGB(139, 0, 139),
-            Purple => HexRGB(128, 0, 128),
-            Indigo => HexRGB(75, 0, 130),
-            SlateBlue => HexRGB(106, 90, 205),
-            DarkSlateBlue => HexRGB(72, 61, 139),
-            MediumSlateBlue => HexRGB(123, 104, 238),
-            GreenYellow => HexRGB(173, 255, 47),
-            Chartreuse => HexRGB(127, 255, 0),
-            LawnGreen => HexRGB(124, 252, 0),
-            Lime => HexRGB(0, 255, 0),
-            LimeGreen => HexRGB(50, 205, 50),
-            PaleGreen => HexRGB(152, 251, 152),
-            LightGreen => HexRGB(144, 238, 144),
-            MediumSpringGreen => HexRGB(0, 250, 154),
-            SpringGreen => HexRGB(0, 255, 127),
-            MediumSeaGreen => HexRGB(60, 179, 113),
-            SeaGreen => HexRGB(46, 139, 87),
-            ForestGreen => HexRGB(34, 139, 34),
-            Green => HexRGB(0, 128, 0),
-            DarkGreen => HexRGB(0, 100, 0),
-            YellowGreen => HexRGB(154, 205, 50),
-            OliveDrab => HexRGB(107, 142, 35),
-            Olive => HexRGB(128, 128, 0),
-            DarkOliveGreen => HexRGB(85, 107, 47),
-            MediumAquamarine => HexRGB(102, 205, 170),
-            DarkSeaGreen => HexRGB(143, 188, 139),
-            LightSeaGreen => HexRGB(32, 178, 170),
-            DarkCyan => HexRGB(0, 139, 139),
-            Teal => HexRGB(0, 128, 128),
-            Aqua => HexRGB(0, 255, 255),
-            Cyan => HexRGB(0, 255, 255),
-            LightCyan => HexRGB(224, 255, 255),
-            PaleTurquoise => HexRGB(175, 238, 238),
-            Aquamarine => HexRGB(127, 255, 212),
-            Turquoise => HexRGB(64, 224, 208),
-            MediumTurquoise => HexRGB(72, 209, 204),
-            DarkTurquoise => HexRGB(0, 206, 209),
-            CadetBlue => HexRGB(95, 158, 160),
-            SteelBlue => HexRGB(70, 130, 180),
-            LightSteelBlue => HexRGB(176, 196, 222),
-            PowderBlue => HexRGB(176, 224, 230),
-            LightBlue => HexRGB(173, 216, 230),
-            SkyBlue => HexRGB(135, 206, 235),
-            LightSkyBlue => HexRGB(135, 206, 250),
-            DeepSkyBlue => HexRGB(0, 191, 255),
-            DodgerBlue => HexRGB(30, 144, 255),
-            CornflowerBlue => HexRGB(100, 149, 237),
-            RoyalBlue => HexRGB(65, 105, 225),
-            Blue => HexRGB(0, 0, 255),
-            MediumBlue => HexRGB(0, 0, 205),
-            DarkBlue => HexRGB(0, 0, 139),
-            Navy => HexRGB(0, 0, 128),
-            MidnightBlue => HexRGB(25, 25, 112),
-            Cornsilk => HexRGB(255, 248, 220),
-            BlanchedAlmond => HexRGB(255, 235, 205),
-            Bisque => HexRGB(255, 228, 196),
-            NavajoWhite => HexRGB(255, 222, 173),
-            Wheat => HexRGB(245, 222, 179),
-            BurlyWood => HexRGB(222, 184, 135),
-            Tan => HexRGB(210, 180, 140),
-            RosyBrown => HexRGB(188, 143, 143),
-            SandyBrown => HexRGB(244, 164, 96),
-            Goldenrod => HexRGB(218, 165, 32),
-            DarkGoldenrod => HexRGB(184, 134, 11),
-            Peru => HexRGB(205, 133, 63),
-            Chocolate => HexRGB(210, 105, 30),
-            SaddleBrown => HexRGB(139, 69, 19),
-            Sienna => HexRGB(160, 82, 45),
-            Brown => HexRGB(165, 42, 42),
-            Maroon => HexRGB(128, 0, 0),
-            White => HexRGB(255, 255, 255),
-            Snow => HexRGB(255, 250, 250),
-            HoneyDew => HexRGB(240, 255, 240),
-            MintCream => HexRGB(245, 255, 250),
-            Azure => HexRGB(240, 255, 255),
-            AliceBlue => HexRGB(240, 248, 255),
-            GhostWhite => HexRGB(248, 248, 255),
-            WhiteSmoke => HexRGB(245, 245, 245),
-            SeaShell => HexRGB(255, 245, 238),
-            Beige => HexRGB(245, 245, 220),
-            OldLace => HexRGB(253, 245, 230),
-            FloralWhite => HexRGB(255, 250, 240),
-            Ivory => HexRGB(255, 255, 240),
-            AntiqueWhite => HexRGB(250, 235, 215),
-            Linen => HexRGB(250, 240, 230),
-            LavenderBlush => HexRGB(255, 240, 245),
-            MistyRose => HexRGB(255, 228, 225),
-            Gainsboro => HexRGB(220, 220, 220),
-            LightGray => HexRGB(211, 211, 211),
-            Silver => HexRGB(192, 192, 192),
-            DarkGray => HexRGB(169, 169, 169),
-            Gray => HexRGB(128, 128, 128),
-            DimGray => HexRGB(105, 105, 105),
-            LightSlateGray => HexRGB(119, 136, 153),
-            SlateGray => HexRGB(112, 128, 144),
-            DarkSlateGray => HexRGB(47, 79, 79),
-            Black => HexRGB(0, 0, 0),
-        }
-    }
-
-    pub fn from_named(name: &str) -> Option<Self> {
-        // todo use a faster search (e.g. hashmap, aho-corasick)
-        use Color::*;
-        Some(match name {
-            "indianred" => IndianRed,
-            "lightcoral" => LightCoral,
-            "salmon" => Salmon,
-            "darksalmon" => DarkSalmon,
-            "lightsalmon" => LightSalmon,
-            "crimson" => Crimson,
-            "red" => Red,
-            "firebrick" => FireBrick,
-            "darkred" => DarkRed,
-            "pink" => Pink,
-            "lightpink" => LightPink,
-            "hotpink" => HotPink,
-            "deeppink" => DeepPink,
-            "mediumvioletred" => MediumVioletRed,
-            "palevioletred" => PaleVioletRed,
-            "coral" => Coral,
-            "tomato" => Tomato,
-            "orangered" => OrangeRed,
-            "darkorange" => DarkOrange,
-            "orange" => Orange,
-            "gold" => Gold,
-            "yellow" => Yellow,
-            "lightyellow" => LightYellow,
-            "lemonchiffon" => LemonChiffon,
-            "lightgoldenrodyellow" => LightGoldenrodYellow,
-            "papayawhip" => PapayaWhip,
-            "Moccasin" => Moccasin,
-            "Peachpuff" => PeachPuff,
-            "palegoldenrod" => PaleGoldenrod,
-            "khaki" => Khaki,
-            "darkkhaki" => DarkKhaki,
-            "lavender" => Lavender,
-            "thistle" => Thistle,
-            "plum" => Plum,
-            "violet" => Violet,
-            "orchid" => Orchid,
-            "fuchsia" => Fuchsia,
-            "magenta" => Magenta,
-            "mediumorchid" => MediumOrchid,
-            "mediumpurple" => MediumPurple,
-            "rebeccapurple" => RebeccaPurple,
-            "blueviolet" => BlueViolet,
-            "darkviolet" => DarkViolet,
-            "darkorchid" => DarkOrchid,
-            "darkmagenta" => DarkMagenta,
-            "purple" => Purple,
-            "indigo" => Indigo,
-            "slateblue" => SlateBlue,
-            "darkslateblue" => DarkSlateBlue,
-            "mediumslateblue" => MediumSlateBlue,
-            "greenyellow" => GreenYellow,
-            "chartreuse" => Chartreuse,
-            "lawngreen" => LawnGreen,
-            "lime" => Lime,
-            "limegreen" => LimeGreen,
-            "palegreen" => PaleGreen,
-            "lightgreen" => LightGreen,
-            "mediumspringgreen" => MediumSpringGreen,
-            "springgreen" => SpringGreen,
-            "mediumseagreen" => MediumSeaGreen,
-            "seagreen" => SeaGreen,
-            "forestgreen" => ForestGreen,
-            "green" => Green,
-            "darkgreen" => DarkGreen,
-            "yellowgreen" => YellowGreen,
-            "olivedrab" => OliveDrab,
-            "olive" => Olive,
-            "darkolivegreen" => DarkOliveGreen,
-            "mediumaquamarine" => MediumAquamarine,
-            "darkseagreen" => DarkSeaGreen,
-            "lightseagreen" => LightSeaGreen,
-            "darkcyan" => DarkCyan,
-            "teal" => Teal,
-            "aqua" => Aqua,
-            "cyan" => Cyan,
-            "lightcyan" => LightCyan,
-            "paleturquoise" => PaleTurquoise,
-            "aquamarine" => Aquamarine,
-            "turquoise" => Turquoise,
-            "mediumturquoise" => MediumTurquoise,
-            "darkturquoise" => DarkTurquoise,
-            "cadetblue" => CadetBlue,
-            "steelblue" => SteelBlue,
-            "lightsteelblue" => LightSteelBlue,
-            "powderblue" => PowderBlue,
-            "lightblue" => LightBlue,
-            "skyblue" => SkyBlue,
-            "lightskyblue" => LightSkyBlue,
-            "deepskyblue" => DeepSkyBlue,
-            "dodgerblue" => DodgerBlue,
-            "cornflowerblue" => CornflowerBlue,
-            "royalblue" => RoyalBlue,
-            "blue" => Blue,
-            "mediumblue" => MediumBlue,
-            "darkblue" => DarkBlue,
-            "navy" => Navy,
-            "midnightblue" => MidnightBlue,
-            "cornsilk" => Cornsilk,
-            "blanchedalmond" => BlanchedAlmond,
-            "bisque" => Bisque,
-            "navajowhite" => NavajoWhite,
-            "wheat" => Wheat,
-            "burlywood" => BurlyWood,
-            "tan" => Tan,
-            "rosybrown" => RosyBrown,
-            "sandybrown" => SandyBrown,
-            "goldenrod" => Goldenrod,
-            "darkgoldenrod" => DarkGoldenrod,
-            "peru" => Peru,
-            "chocolate" => Chocolate,
-            "saddlebrown" => SaddleBrown,
-            "sienna" => Sienna,
-            "brown" => Brown,
-            "maroon" => Maroon,
-            "white" => White,
-            "snow" => Snow,
-            "honeydew" => HoneyDew,
-            "mintcream" => MintCream,
-            "azure" => Azure,
-            "aliceblue" => AliceBlue,
-            "ghostwhite" => GhostWhite,
-            "whitesmoke" => WhiteSmoke,
-            "seashell" => SeaShell,
-            "beige" => Beige,
-            "oldlace" => OldLace,
-            "floralwhite" => FloralWhite,
-            "ivory" => Ivory,
-            "antiquewhite" => AntiqueWhite,
-            "linen" => Linen,
-            "lavenderblush" => LavenderBlush,
-            "mistyrose" => MistyRose,
-            "gainsboro" => Gainsboro,
-            "lightgray" => LightGray,
-            "silver" => Silver,
-            "darkgray" => DarkGray,
-            "gray" => Gray,
-            "dimgray" => DimGray,
-            "lightslategray" => LightSlateGray,
-            "slategray" => SlateGray,
-            "darkslategray" => DarkSlateGray,
-            "black" => Black,
-            _ => return None,
-        })
-    }
-}
-
-impl fmt::Display for Color {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        use Color::*;
-        match self {
-            HexRGB(r, g, b) => write!(f, "#{:02x}{:02x}{:02x}", r, g, b),
-            HexRGBA(r, g, b, a) => write!(f, "#{:02x}{:02x}{:02x}{:02x}", r, g, b, a),
-            HSL(h, s, l) => write!(f, "hsl({}, {}%, {}%)", h, s, l),
-            HSLA(h, s, l, a) => write!(f, "hsla({}, {}%, {}%, {})", h, s, l, a),
-            IndianRed => write!(f, "indianred"),
-            LightCoral => write!(f, "lightcoral"),
-            Salmon => write!(f, "salmon"),
-            DarkSalmon => write!(f, "darksalmon"),
-            LightSalmon => write!(f, "lightsalmon"),
-            Crimson => write!(f, "crimson"),
-            Red => write!(f, "red"),
-            FireBrick => write!(f, "firebrick"),
-            DarkRed => write!(f, "darkred"),
-            Pink => write!(f, "pink"),
-            LightPink => write!(f, "lightpink"),
-            HotPink => write!(f, "hotpink"),
-            DeepPink => write!(f, "deeppink"),
-            MediumVioletRed => write!(f, "mediumvioletred"),
-            PaleVioletRed => write!(f, "palevioletred"),
-            Coral => write!(f, "coral"),
-            Tomato => write!(f, "tomato"),
-            OrangeRed => write!(f, "orangered"),
-            DarkOrange => write!(f, "darkorange"),
-            Orange => write!(f, "orange"),
-            Gold => write!(f, "gold"),
-            Yellow => write!(f, "yellow"),
-            LightYellow => write!(f, "lightyellow"),
-            LemonChiffon => write!(f, "lemonchiffon"),
-            LightGoldenrodYellow => write!(f, "lightgoldenrodyellow"),
-            PapayaWhip => write!(f, "papayawhip"),
-            Moccasin => write!(f, "Moccasin"),
-            PeachPuff => write!(f, "Peachpuff"),
-            PaleGoldenrod => write!(f, "palegoldenrod"),
-            Khaki => write!(f, "khaki"),
-            DarkKhaki => write!(f, "darkkhaki"),
-            Lavender => write!(f, "lavender"),
-            Thistle => write!(f, "thistle"),
-            Plum => write!(f, "plum"),
-            Violet => write!(f, "violet"),
-            Orchid => write!(f, "orchid"),
-            Fuchsia => write!(f, "fuchsia"),
-            Magenta => write!(f, "magenta"),
-            MediumOrchid => write!(f, "mediumorchid"),
-            MediumPurple => write!(f, "mediumpurple"),
-            RebeccaPurple => write!(f, "rebeccapurple"),
-            BlueViolet => write!(f, "blueviolet"),
-            DarkViolet => write!(f, "darkviolet"),
-            DarkOrchid => write!(f, "darkorchid"),
-            DarkMagenta => write!(f, "darkmagenta"),
-            Purple => write!(f, "purple"),
-            Indigo => write!(f, "indigo"),
-            SlateBlue => write!(f, "slateblue"),
-            DarkSlateBlue => write!(f, "darkslateblue"),
-            MediumSlateBlue => write!(f, "mediumslateblue"),
-            GreenYellow => write!(f, "greenyellow"),
-            Chartreuse => write!(f, "chartreuse"),
-            LawnGreen => write!(f, "lawngreen"),
-            Lime => write!(f, "lime"),
-            LimeGreen => write!(f, "limegreen"),
-            PaleGreen => write!(f, "palegreen"),
-            LightGreen => write!(f, "lightgreen"),
-            MediumSpringGreen => write!(f, "mediumspringgreen"),
-            SpringGreen => write!(f, "springgreen"),
-            MediumSeaGreen => write!(f, "mediumseagreen"),
-            SeaGreen => write!(f, "seagreen"),
-            ForestGreen => write!(f, "forestgreen"),
-            Green => write!(f, "green"),
-            DarkGreen => write!(f, "darkgreen"),
-            YellowGreen => write!(f, "yellowgreen"),
-            OliveDrab => write!(f, "olivedrab"),
-            Olive => write!(f, "olive"),
-            DarkOliveGreen => write!(f, "darkolivegreen"),
-            MediumAquamarine => write!(f, "mediumaquamarine"),
-            DarkSeaGreen => write!(f, "darkseagreen"),
-            LightSeaGreen => write!(f, "lightseagreen"),
-            DarkCyan => write!(f, "darkcyan"),
-            Teal => write!(f, "teal"),
-            Aqua => write!(f, "aqua"),
-            Cyan => write!(f, "cyan"),
-            LightCyan => write!(f, "lightcyan"),
-            PaleTurquoise => write!(f, "paleturquoise"),
-            Aquamarine => write!(f, "aquamarine"),
-            Turquoise => write!(f, "turquoise"),
-            MediumTurquoise => write!(f, "mediumturquoise"),
-            DarkTurquoise => write!(f, "darkturquoise"),
-            CadetBlue => write!(f, "cadetblue"),
-            SteelBlue => write!(f, "steelblue"),
-            LightSteelBlue => write!(f, "lightsteelblue"),
-            PowderBlue => write!(f, "powderblue"),
-            LightBlue => write!(f, "lightblue"),
-            SkyBlue => write!(f, "skyblue"),
-            LightSkyBlue => write!(f, "lightskyblue"),
-            DeepSkyBlue => write!(f, "deepskyblue"),
-            DodgerBlue => write!(f, "dodgerblue"),
-            CornflowerBlue => write!(f, "cornflowerblue"),
-            RoyalBlue => write!(f, "royalblue"),
-            Blue => write!(f, "blue"),
-            MediumBlue => write!(f, "mediumblue"),
-            DarkBlue => write!(f, "darkblue"),
-            Navy => write!(f, "navy"),
-            MidnightBlue => write!(f, "midnightblue"),
-            Cornsilk => write!(f, "cornsilk"),
-            BlanchedAlmond => write!(f, "blanchedalmond"),
-            Bisque => write!(f, "bisque"),
-            NavajoWhite => write!(f, "navajowhite"),
-            Wheat => write!(f, "wheat"),
-            BurlyWood => write!(f, "burlywood"),
-            Tan => write!(f, "tan"),
-            RosyBrown => write!(f, "rosybrown"),
-            SandyBrown => write!(f, "sandybrown"),
-            Goldenrod => write!(f, "goldenrod"),
-            DarkGoldenrod => write!(f, "darkgoldenrod"),
-            Peru => write!(f, "peru"),
-            Chocolate => write!(f, "chocolate"),
-            SaddleBrown => write!(f, "saddlebrown"),
-            Sienna => write!(f, "sienna"),
-            Brown => write!(f, "brown"),
-            Maroon => write!(f, "maroon"),
-            White => write!(f, "white"),
-            Snow => write!(f, "snow"),
-            HoneyDew => write!(f, "honeydew"),
-            MintCream => write!(f, "mintcream"),
-            Azure => write!(f, "azure"),
-            AliceBlue => write!(f, "aliceblue"),
-            GhostWhite => write!(f, "ghostwhite"),
-            WhiteSmoke => write!(f, "whitesmoke"),
-            SeaShell => write!(f, "seashell"),
-            Beige => write!(f, "beige"),
-            OldLace => write!(f, "oldlace"),
-            FloralWhite => write!(f, "floralwhite"),
-            Ivory => write!(f, "ivory"),
-            AntiqueWhite => write!(f, "antiquewhite"),
-            Linen => write!(f, "linen"),
-            LavenderBlush => write!(f, "lavenderblush"),
-            MistyRose => write!(f, "mistyrose"),
-            Gainsboro => write!(f, "gainsboro"),
-            LightGray => write!(f, "lightgray"),
-            Silver => write!(f, "silver"),
-            DarkGray => write!(f, "darkgray"),
-            Gray => write!(f, "gray"),
-            DimGray => write!(f, "dimgray"),
-            LightSlateGray => write!(f, "lightslategray"),
-            SlateGray => write!(f, "slategray"),
-            DarkSlateGray => write!(f, "darkslategray"),
-            Black => write!(f, "black"),
-        }
-    }
-}
-
-fn hsl_to_rgb(h: f64, s: f64, l: f64) -> (f64, f64, f64) {
-    debug_assert!(h >= 0.0 && h < 360.0);
-    debug_assert!(s >= 0.0 && s <= 1.0);
-    debug_assert!(l >= 0.0 && l <= 1.0);
-    let c = (1.0 - (2.0 * l - 1.0).abs()) * s;
-    let x = c * (1.0 - ((h / 60.0) % 2.0 - 1.0).abs());
-    let m = l - c * 0.5;
-    let (rp, gp, bp) = if h < 60.0 {
-        (c, x, 0.0)
-    } else if h < 120.0 {
-        (x, c, 0.0)
-    } else if h < 180.0 {
-        (0.0, c, x)
-    } else if h < 240.0 {
-        (0.0, x, c)
-    } else if h < 300.0 {
-        (x, 0.0, c)
-    } else {
-        (c, 0.0, x)
-    };
-    (rp + m, gp + m, bp + m)
-}
-
-pub fn parse_hex(hex: &str) -> Option<Color> {
-    match hex.len() {
-        3 => {
-            let r = u8::from_str_radix(hex.get(0..1)?, 16).ok()?;
-            let g = u8::from_str_radix(hex.get(1..2)?, 16).ok()?;
-            let b = u8::from_str_radix(hex.get(2..3)?, 16).ok()?;
-            // #fff is equivalent to #ffffff
-            Some(Color::HexRGB(r << 4 | r, g << 4 | g, b << 4 | b))
-        }
-        6 => {
-            let r = u8::from_str_radix(hex.get(0..2)?, 16).ok()?;
-            let g = u8::from_str_radix(hex.get(2..4)?, 16).ok()?;
-            let b = u8::from_str_radix(hex.get(4..6)?, 16).ok()?;
-            Some(Color::HexRGB(r, g, b))
-        }
-        8 => {
-            let r = u8::from_str_radix(hex.get(0..2)?, 16).ok()?;
-            let g = u8::from_str_radix(hex.get(2..4)?, 16).ok()?;
-            let b = u8::from_str_radix(hex.get(4..6)?, 16).ok()?;
-            let a = u8::from_str_radix(hex.get(6..8)?, 16).ok()?;
-            Some(Color::HexRGBA(r, g, b, a))
-        }
-        _ => None,
-    }
-}
-
-#[test]
-fn test_color_convert() {
-    let color = Color::HSL(60.0, 0.0, 100.0);
-    assert_eq!(color.to_rgb(), Color::HexRGB(255, 255, 255));
-    let color = Color::HSL(0.0, 100.0, 50.0);
-    assert_eq!(color.to_rgb(), Color::HexRGB(255, 0, 0));
-}

+ 0 - 2044
packages/core-macro/styles/mod.rs

@@ -1,2044 +0,0 @@
-//! A module to type styles.
-// TODO most stuff here is on the stack, but there are a few heap-allocs here and there. It would
-// be good if we could just to allocate them in the bump arena when using bumpalo.
-mod calc;
-mod codegen;
-mod color;
-pub mod string;
-mod syn_parse;
-
-use std::{
-    fmt,
-    ops::{Deref, DerefMut},
-};
-
-pub use calc::*;
-pub use color::{Color, DynamicColor};
-// pub use crate::{
-//     calc::*,
-//     color::{Color, DynamicColor},
-// };
-
-pub struct DynamicStyles {
-    pub rules: Vec<DynamicStyle>,
-}
-
-impl From<Vec<DynamicStyle>> for DynamicStyles {
-    fn from(v: Vec<DynamicStyle>) -> Self {
-        Self { rules: v }
-    }
-}
-
-impl fmt::Display for DynamicStyles {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        for style in self
-            .rules
-            .iter()
-            .filter(|style| !(style.is_dynamic() || style.is_dummy()))
-        {
-            write!(f, "{};", style)?;
-        }
-        Ok(())
-    }
-}
-
-// TODO make container generic over heap (e.g. support bumpalo)
-#[derive(Debug, Clone, PartialEq)]
-pub struct Styles {
-    pub rules: Vec<Style>,
-}
-
-impl Styles {
-    pub fn new() -> Self {
-        Styles { rules: Vec::new() }
-    }
-
-    pub fn add(&mut self, style: Style) {
-        self.rules.push(style);
-    }
-
-    pub fn merge(&mut self, other: Styles) {
-        self.rules.extend(other.rules.into_iter())
-    }
-}
-
-impl From<DynamicStyles> for Styles {
-    fn from(dy: DynamicStyles) -> Self {
-        Styles {
-            rules: dy
-                .rules
-                .into_iter()
-                .filter_map(|dy_sty| match dy_sty {
-                    DynamicStyle::Dynamic(_) => None,
-                    DynamicStyle::Literal(l) => Some(l),
-                })
-                .collect(),
-        }
-    }
-}
-
-impl Deref for Styles {
-    type Target = Vec<Style>;
-    fn deref(&self) -> &Self::Target {
-        &self.rules
-    }
-}
-impl DerefMut for Styles {
-    fn deref_mut(&mut self) -> &mut Self::Target {
-        &mut self.rules
-    }
-}
-
-impl From<Vec<Style>> for Styles {
-    fn from(v: Vec<Style>) -> Self {
-        Self { rules: v }
-    }
-}
-
-impl From<Styles> for Vec<Style> {
-    fn from(v: Styles) -> Self {
-        v.rules
-    }
-}
-
-impl fmt::Display for Styles {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        for style in self.rules.iter().filter(|style| !style.is_dummy()) {
-            write!(f, "{};", style)?;
-        }
-        Ok(())
-    }
-}
-
-#[derive(Debug, Clone, PartialEq)]
-pub enum DynamicStyle {
-    /// A literal style.
-    Literal(Style),
-    /// Tokens to pass through directly to codegen.
-    Dynamic(syn::Block),
-}
-
-impl DynamicStyle {
-    pub fn is_dynamic(&self) -> bool {
-        match self {
-            DynamicStyle::Literal(style) => style.is_dynamic(),
-            DynamicStyle::Dynamic(_) => true,
-        }
-    }
-    pub fn is_dummy(&self) -> bool {
-        match self {
-            DynamicStyle::Literal(style) => style.is_dummy(),
-            DynamicStyle::Dynamic(_) => false,
-        }
-    }
-}
-
-impl From<Style> for DynamicStyle {
-    fn from(style: Style) -> Self {
-        DynamicStyle::Literal(style)
-    }
-}
-
-impl fmt::Display for DynamicStyle {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            DynamicStyle::Literal(style) => style.fmt(f),
-            DynamicStyle::Dynamic(_) => Ok(()),
-        }
-    }
-}
-
-/// a `Style` is one of the css key/value pairs, also sometimes known as rules.
-#[derive(Debug, Clone, PartialEq)]
-#[non_exhaustive]
-pub enum Style {
-    /// For when you don't want to include any style at all (useful in expressions like `if`)
-    Dummy,
-    /// For when you want to use some unimplemented css. This is not type checked!
-    Unchecked(String),
-
-    // *From w3 spec:*
-    /// align-content
-    AlignContent(AlignContent),
-    /// align-items
-    AlignItems(AlignItems),
-    /// align-self
-    AlignSelf(AlignSelf),
-    // all - todo when doing global values
-    // background
-    /// background-attachment
-    BackgroundAttachment(BackgroundAttachment),
-    /// background-blend-mode
-    BackgroundBlendMode(NonemptyCommaList<BlendMode>),
-    /// background-clip
-    BackgroundClip(BackgroundBox),
-    /// background-color
-    BackgroundColor(DynamicColor),
-    /// background-image
-    BackgroundImage(NonemptyCommaList<BackgroundImage>),
-    /// background-origin
-    BackgroundOrigin(BackgroundBox),
-    /// background-position
-    BackgroundPosition(BackgroundPosition),
-    /// background-repeat
-    BackgroundRepeat(NonemptyCommaList<BackgroundRepeat>),
-    /// background-size
-    BackgroundSize(BackgroundSize),
-    /// border
-    Border(Border),
-    /// border-bottom
-    BorderBottom(Border),
-    /// border-bottom-color
-    BorderBottomColor(Color),
-    /// border-bottom-left-radius
-    BorderBottomLeftRadius(SingleOrDouble<LengthPercentage>),
-    /// border-bottom-right-radius
-    BorderBottomRightRadius(SingleOrDouble<LengthPercentage>),
-    /// border-bottom-style
-    BorderBottomStyle(LineStyle),
-    /// border-bottom-width
-    BorderBottomWidth(LineWidth),
-    /// border-collapse
-    BorderCollapse(BorderCollapse),
-    /// border-color
-    BorderColor(Rect<Color>),
-    // border-image
-    // border-image-outset
-    // border-image-repeat
-    // border-image-slice
-    // border-image-source
-    // border-image-width
-    /// border-left
-    BorderLeft(Border),
-    /// border-left-color
-    BorderLeftColor(Color),
-    /// border-left-style
-    BorderLeftStyle(LineStyle),
-    /// border-left-width
-    BorderLeftWidth(LineWidth),
-    /// border-radius
-    BorderRadius(BorderRadius),
-    /// border-right
-    BorderRight(Border),
-    /// border-right-color
-    BorderRightColor(Color),
-    /// border-right-style
-    BorderRightStyle(LineStyle),
-    /// border-right-width
-    BorderRightWidth(LineWidth),
-    // border-spacing
-    /// border-style
-    BorderStyle(BorderStyle),
-    /// border-top
-    BorderTop(Border),
-    /// border-top-color
-    BorderTopColor(Color),
-    /// border-top-left-radius
-    BorderTopLeftRadius(SingleOrDouble<LengthPercentage>),
-    /// border-top-right-radius
-    BorderTopRightRadius(SingleOrDouble<LengthPercentage>),
-    /// border-top-style
-    BorderTopStyle(LineStyle),
-    /// border-top-width
-    BorderTopWidth(LineWidth),
-    /// border-width
-    BorderWidth(BorderWidth),
-    /// bottom
-    Bottom(AutoLengthPercentage),
-    // box-decoration-break
-    /// box-shadow
-    BoxShadow(BoxShadow),
-    /// box-sizing
-    BoxSizing(BoxSizing),
-    // break-after
-    // break-before
-    // break-inside
-    // caption-side
-    // caret-color
-    /// clear
-    Clear(Clear),
-    // clip
-    // clip-path
-    // clip-rule
-    /// color
-    Color(DynamicColor),
-    /// column-count (manually added)
-    ColumnCount(ColumnCount),
-    // contain
-    // content
-    // counter-increment
-    // counter-reset
-    // cue
-    // cue-after
-    // cue-before
-    /// cursor
-    Cursor(Cursor),
-    // direction
-    /// display https://www.w3.org/TR/css-display-3/#typedef-display-outside
-    Display(Display),
-    // elevation
-    // empty-cells
-    // flex
-    /// flex-basis
-    FlexBasis(FlexBasis),
-    /// flex-direction
-    FlexDirection(FlexDirection),
-    // flex-flow
-    /// flex-grow
-    FlexGrow(f64),
-    /// flex-shrink
-    FlexShrink(f64),
-    /// flex-wrap
-    FlexWrap(FlexWrap),
-    /// float
-    Float(Float),
-    // font
-    /// font-family
-    FontFamily(FontFamily),
-    // font-feature-settings
-    // font-kerning
-    /// font-size
-    FontSize(FontSize),
-    // font-size-adjust
-    // font-stretch
-    /// font-style
-    FontStyle(FontStyle),
-    // font-synthesis
-    // font-variant
-    // font-variant-caps
-    // font-variant-east-asian
-    // font-variant-ligatures
-    // font-variant-numeric
-    // font-variant-position
-    /// font-weight
-    FontWeight(FontWeight),
-    // glyph-orientation-vertical
-    // grid
-    // grid-area
-    // grid-auto-columns
-    // grid-auto-flow
-    // grid-auto-rows
-    // grid-column
-    // grid-column-end
-    // grid-column-start
-    // grid-row
-    // grid-row-end
-    // grid-row-start
-    // grid-template
-    // grid-template-areas
-    // grid-template-columns
-    // grid-template-rows
-    /// height
-    Height(WidthHeight),
-    // image-orientation
-    // image-rendering
-    // isolation
-    /// justify-content
-    JustifyContent(JustifyContent),
-    /// left
-    Left(AutoLengthPercentage),
-    // letter-spacing
-    /// line-height
-    LineHeight(LineHeight),
-    // list-style
-    // list-style-image
-    // list-style-position
-    /// list-style-type
-    ListStyleType(ListStyleType),
-    /// margin
-    Margin(Margin),
-    /// margin-bottom
-    MarginBottom(MarginWidth),
-    /// margin-left
-    MarginLeft(MarginWidth),
-    /// margin-right
-    MarginRight(MarginWidth),
-    /// margin-top
-    MarginTop(MarginWidth),
-    // mask
-    // mask-border
-    // mask-border-mode
-    // mask-border-outset
-    // mask-border-repeat
-    // mask-border-slice
-    // mask-border-source
-    // mask-border-width
-    // mask-clip
-    // mask-composite
-    // mask-image
-    // mask-mode
-    // mask-origin
-    // mask-position
-    // mask-repeat
-    // mask-size
-    // mask-type
-    /// max-height
-    MaxHeight(MaxWidthHeight),
-    /// max-width
-    MaxWidth(MaxWidthHeight),
-    /// min-height - current implementing CSS2 spec
-    MinHeight(Calc),
-    /// min-width - current implementing CSS2 spec
-    MinWidth(Calc),
-    // mix-blend-mode
-    /// object-fit - https://drafts.csswg.org/css-images-4/#the-object-fit
-    ObjectFit(ObjectFit),
-    // object-position
-    // opacity
-    // order
-    // orphans
-    // outline
-    // outline-color
-    // outline-offset
-    // outline-style
-    // outline-width
-    /// overflow - https://drafts.csswg.org/css-overflow-3/#propdef-overflow
-    Overflow(Overflow),
-    /// overflow-x manually added
-    OverflowX(OverflowXY),
-    /// overflow-y manually added
-    OverflowY(OverflowXY),
-    /// padding
-    Padding(Padding),
-    /// padding-bottom
-    PaddingBottom(PaddingWidth),
-    /// padding-left
-    PaddingLeft(PaddingWidth),
-    /// padding-right
-    PaddingRight(PaddingWidth),
-    /// padding-top
-    PaddingTop(PaddingWidth),
-    // page-break-after
-    // page-break-before
-    // page-break-inside
-    // pause
-    // pause-after
-    // pause-before
-    // pitch
-    // pitch-range
-    // play-during
-    /// position
-    Position(Position),
-    // quotes
-    /// resize
-    Resize(Resize),
-    // richness
-    /// right
-    Right(AutoLengthPercentage),
-    // scroll-margin
-    // scroll-margin-block
-    // scroll-margin-block-end
-    // scroll-margin-block-start
-    // scroll-margin-bottom
-    // scroll-margin-inline
-    // scroll-margin-inline-end
-    // scroll-margin-inline-start
-    // scroll-margin-left
-    // scroll-margin-right
-    // scroll-margin-top
-    // scroll-padding
-    // scroll-padding-block
-    // scroll-padding-block-end
-    // scroll-padding-block-start
-    // scroll-padding-bottom
-    // scroll-padding-inline
-    // scroll-padding-inline-end
-    // scroll-padding-inline-start
-    // scroll-padding-left
-    // scroll-padding-right
-    // scroll-padding-top
-    // scroll-snap-align
-    // scroll-snap-stop
-    // scroll-snap-type
-    // shape-image-threshold
-    // shape-margin
-    // shape-outside
-    // speak
-    // speak-header
-    // speak-numeral
-    // speak-punctuation
-    // speech-rate
-    // stress
-    // table-layout
-    /// text-align
-    TextAlign(TextAlign),
-    // text-combine-upright
-    // text-decoration
-    // text-decoration-color
-    // text-decoration-line
-    // text-decoration-style
-    // text-emphasis
-    // text-emphasis-color
-    // text-emphasis-position
-    // text-emphasis-style
-    // text-indent
-    // text-orientation
-    // text-overflow
-    // text-shadow
-    // text-transform
-    // text-underline-position
-    /// top
-    Top(AutoLengthPercentage),
-    // transform
-    // transform-box
-    // transform-origin
-    // unicode-bidi
-    // vertical-align
-    // visibility
-    // voice-family
-    // volume
-    /// white-space
-    WhiteSpace(WhiteSpace),
-    /// widows
-    Widows(u32),
-    /// width
-    Width(WidthHeight),
-    // will-change
-    // word-spacing
-    // writing-mode
-    // z-index
-}
-
-impl Style {
-    fn is_dummy(&self) -> bool {
-        match self {
-            Style::Dummy => true,
-            _ => false,
-        }
-    }
-
-    fn is_dynamic(&self) -> bool {
-        match self {
-            Style::BackgroundColor(value) => value.is_dynamic(),
-            Style::Color(value) => value.is_dynamic(),
-            _ => false,
-        }
-    }
-}
-
-impl fmt::Display for Style {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            Style::Dummy => Ok(()),
-            Style::Unchecked(v) => write!(f, "{}", v),
-
-            Style::AlignContent(v) => write!(f, "align-content:{}", v),
-            Style::AlignItems(v) => write!(f, "align-items:{}", v),
-            Style::AlignSelf(v) => write!(f, "align-self:{}", v),
-            // all - deferred
-            // background
-            Style::BackgroundAttachment(v) => write!(f, "background-attachment:{}", v),
-            Style::BackgroundBlendMode(v) => write!(f, "background-blend-mode:{}", v),
-            Style::BackgroundClip(v) => write!(f, "background-clip:{}", v),
-            Style::BackgroundColor(v) => write!(f, "background-color:{}", v),
-            Style::BackgroundImage(v) => write!(f, "background-image:{}", v),
-            Style::BackgroundOrigin(v) => write!(f, "background-origin:{}", v),
-            Style::BackgroundPosition(v) => write!(f, "background-position:{}", v),
-            Style::BackgroundRepeat(v) => write!(f, "background-repeat:{}", v),
-            Style::BackgroundSize(v) => write!(f, "background-size:{}", v),
-            Style::Border(v) => write!(f, "border:{}", v),
-            Style::BorderBottom(v) => write!(f, "border-bottom:{}", v),
-            Style::BorderBottomColor(v) => write!(f, "border-bottom-color:{}", v),
-            Style::BorderBottomLeftRadius(v) => write!(f, "border-bottom-left-radius:{}", v),
-            Style::BorderBottomRightRadius(v) => write!(f, "border-bottom-right-radius:{}", v),
-            Style::BorderBottomStyle(v) => write!(f, "border-bottom-style:{}", v),
-            Style::BorderBottomWidth(v) => write!(f, "border-bottom-width:{}", v),
-            Style::BorderCollapse(v) => write!(f, "border-collapse:{}", v),
-            Style::BorderColor(v) => write!(f, "border-color:{}", v),
-            // border-image
-            // border-image-outset
-            // border-image-repeat
-            // border-image-slice
-            // border-image-source
-            // border-image-width
-            Style::BorderLeft(v) => write!(f, "border-left:{}", v),
-            Style::BorderLeftColor(v) => write!(f, "border-left-color:{}", v),
-            Style::BorderLeftStyle(v) => write!(f, "border-left-style:{}", v),
-            Style::BorderLeftWidth(v) => write!(f, "border-left-width:{}", v),
-            Style::BorderRadius(v) => write!(f, "border-radius:{}", v),
-            Style::BorderRight(v) => write!(f, "border-right:{}", v),
-            Style::BorderRightColor(v) => write!(f, "border-right-color:{}", v),
-            Style::BorderRightStyle(v) => write!(f, "border-right-style:{}", v),
-            Style::BorderRightWidth(v) => write!(f, "border-right-width:{}", v),
-            // border-spacing
-            Style::BorderStyle(v) => write!(f, "border-style:{}", v),
-            Style::BorderTop(v) => write!(f, "border-top:{}", v),
-            Style::BorderTopColor(v) => write!(f, "border-top-color:{}", v),
-            Style::BorderTopLeftRadius(v) => write!(f, "border-top-left-radius:{}", v),
-            Style::BorderTopRightRadius(v) => write!(f, "border-top-right-radius:{}", v),
-            Style::BorderTopStyle(v) => write!(f, "border-top-style:{}", v),
-            Style::BorderTopWidth(v) => write!(f, "border-top-width:{}", v),
-            Style::BorderWidth(v) => write!(f, "border-width:{}", v),
-            Style::Bottom(v) => write!(f, "bottom:{}", v),
-            // box-decoration-break
-            Style::BoxShadow(v) => write!(f, "box-shadow:{}", v),
-            Style::BoxSizing(v) => write!(f, "box-sizing:{}", v),
-            // break-after
-            // break-before
-            // break-inside
-            // caption-side
-            // caret-color
-            Style::Clear(v) => write!(f, "clear:{}", v),
-            // clip
-            // clip-path
-            // clip-rule
-            Style::Color(v) => write!(f, "color:{}", v),
-            Style::ColumnCount(v) => write!(f, "column-count:{}", v),
-            // contain
-            // content
-            // counter-increment
-            // counter-reset
-            // cue
-            // cue-after
-            // cue-before
-            Style::Cursor(v) => write!(f, "cursor:{}", v),
-            // direction
-            Style::Display(v) => write!(f, "display:{}", v),
-            // elevation
-            // empty-cells
-            // flex
-            Style::FlexBasis(v) => write!(f, "flex-basis:{}", v),
-            Style::FlexDirection(v) => write!(f, "flex-direction:{}", v),
-            // flex-flow
-            Style::FlexGrow(v) => write!(f, "flex-grow:{}", v),
-            Style::FlexShrink(v) => write!(f, "flex-shrink:{}", v),
-            Style::FlexWrap(v) => write!(f, "flex-wrap:{}", v),
-            Style::Float(v) => write!(f, "float:{}", v),
-            // font
-            Style::FontFamily(v) => write!(f, "font-family:{}", v),
-            // font-feature-settings
-            // font-kerning
-            Style::FontSize(v) => write!(f, "font-size:{}", v),
-            // font-size-adjust
-            // font-stretch
-            Style::FontStyle(v) => write!(f, "font-style:{}", v),
-            // font-synthesis
-            // font-variant
-            // font-variant-caps
-            // font-variant-east-asian
-            // font-variant-ligatures
-            // font-variant-numeric
-            // font-variant-position
-            Style::FontWeight(v) => write!(f, "font-weight:{}", v),
-            // glyph-orientation-vertical
-            // grid
-            // grid-area
-            // grid-auto-columns
-            // grid-auto-flow
-            // grid-auto-rows
-            // grid-column
-            // grid-column-end
-            // grid-column-start
-            // grid-row
-            // grid-row-end
-            // grid-row-start
-            // grid-template
-            // grid-template-areas
-            // grid-template-columns
-            // grid-template-rows
-            Style::Height(v) => write!(f, "height:{}", v),
-            // image-orientation
-            // image-rendering
-            // isolation
-            Style::JustifyContent(v) => write!(f, "justify-content:{}", v),
-            // left
-            Style::Left(v) => write!(f, "left:{}", v),
-            // letter-spacing
-            // line-height
-            Style::LineHeight(v) => write!(f, "line-height:{}", v),
-            // list-style
-            // list-style-image
-            // list-style-position
-            Style::ListStyleType(v) => write!(f, "list-style-type:{}", v),
-            Style::Margin(v) => write!(f, "margin:{}", v),
-            Style::MarginBottom(v) => write!(f, "margin-bottom:{}", v),
-            Style::MarginLeft(v) => write!(f, "margin-left:{}", v),
-            Style::MarginRight(v) => write!(f, "margin-right:{}", v),
-            Style::MarginTop(v) => write!(f, "margin-top:{}", v),
-            // mask
-            // mask-border
-            // mask-border-mode
-            // mask-border-outset
-            // mask-border-repeat
-            // mask-border-slice
-            // mask-border-source
-            // mask-border-width
-            // mask-clip
-            // mask-composite
-            // mask-image
-            // mask-mode
-            // mask-origin
-            // mask-position
-            // mask-repeat
-            // mask-size
-            // mask-type
-            Style::MaxHeight(v) => write!(f, "max-height:{}", v),
-            Style::MaxWidth(v) => write!(f, "max-width:{}", v),
-            Style::MinHeight(v) => write!(f, "min-height:{}", v),
-            Style::MinWidth(v) => write!(f, "min-width:{}", v),
-            // mix-blend-mode
-            Style::ObjectFit(v) => write!(f, "object-fit:{}", v),
-            // object-position
-            // opacity
-            // order
-            // orphans
-            // outline
-            // outline-color
-            // outline-offset
-            // outline-style
-            // outline-width
-            Style::Overflow(v) => write!(f, "overflow:{}", v),
-            Style::OverflowX(v) => write!(f, "overflow-x:{}", v),
-            Style::OverflowY(v) => write!(f, "overflow-y:{}", v),
-            Style::Padding(v) => write!(f, "padding:{}", v),
-            Style::PaddingBottom(v) => write!(f, "padding-bottom:{}", v),
-            Style::PaddingLeft(v) => write!(f, "padding-left:{}", v),
-            Style::PaddingRight(v) => write!(f, "padding-right:{}", v),
-            Style::PaddingTop(v) => write!(f, "padding-top:{}", v),
-            // padding-bottom
-            // padding-left
-            // padding-right
-            // padding-top
-            // page-break-after
-            // page-break-before
-            // page-break-inside
-            // pause
-            // pause-after
-            // pause-before
-            // pitch
-            // pitch-range
-            // play-during
-            Style::Position(v) => write!(f, "position:{}", v),
-            // uotes
-            Style::Resize(v) => write!(f, "resize:{}", v),
-            // richness
-            Style::Right(v) => write!(f, "right:{}", v),
-            // scroll-margin
-            // scroll-margin-block
-            // scroll-margin-block-end
-            // scroll-margin-block-start
-            // scroll-margin-bottom
-            // scroll-margin-inline
-            // scroll-margin-inline-end
-            // scroll-margin-inline-start
-            // scroll-margin-left
-            // scroll-margin-right
-            // scroll-margin-top
-            // scroll-padding
-            // scroll-padding-block
-            // scroll-padding-block-end
-            // scroll-padding-block-start
-            // scroll-padding-bottom
-            // scroll-padding-inline
-            // scroll-padding-inline-end
-            // scroll-padding-inline-start
-            // scroll-padding-left
-            // scroll-padding-right
-            // scroll-padding-top
-            // scroll-snap-align
-            // scroll-snap-stop
-            // scroll-snap-type
-            // shape-image-threshold
-            // shape-margin
-            // shape-outside
-            // speak
-            // speak-header
-            // speak-numeral
-            // speak-punctuation
-            // speech-rate
-            // stress
-            // table-layout
-            Style::TextAlign(v) => write!(f, "text-align:{}", v),
-            // text-combine-upright
-            // text-decoration
-            // text-decoration-color
-            // text-decoration-line
-            // text-decoration-style
-            // text-emphasis
-            // text-emphasis-color
-            // text-emphasis-position
-            // text-emphasis-style
-            // text-indent
-            // text-orientation
-            // text-overflow
-            // text-shadow
-            // text-transform
-            // text-underline-position
-            // top
-            Style::Top(v) => write!(f, "top:{}", v),
-            // transform
-            // transform-box
-            // transform-origin
-            // unicode-bidi
-            // vertical-align
-            // visibility
-            // voice-family
-            // volume
-            Style::WhiteSpace(v) => write!(f, "white-space:{}", v),
-            Style::Widows(v) => write!(f, "widows:{}", v),
-            Style::Width(v) => write!(f, "width:{}", v),
-            // will-change
-            // word-spacing
-            // writing-mode
-            // z-index
-        }
-    }
-}
-
-/// https://www.w3.org/TR/css-flexbox-1/#propdef-justify-content
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub enum AlignContent {
-    FlexStart,
-    Center,
-    FlexEnd,
-    SpaceBetween,
-    SpaceAround,
-    Stretch,
-}
-
-impl Default for AlignContent {
-    fn default() -> Self {
-        AlignContent::Stretch
-    }
-}
-
-impl fmt::Display for AlignContent {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            AlignContent::FlexStart => write!(f, "flex-start"),
-            AlignContent::Center => write!(f, "center"),
-            AlignContent::FlexEnd => write!(f, "flex-end"),
-            AlignContent::SpaceAround => write!(f, "space-around"),
-            AlignContent::SpaceBetween => write!(f, "space-between"),
-            AlignContent::Stretch => write!(f, "stretch"),
-        }
-    }
-}
-
-/// https://developer.mozilla.org/en-US/docs/Web/CSS/align-items
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub enum AlignItems {
-    Normal,
-    Stretch,
-    Center,
-    Start,
-    End,
-    FlexStart,
-    FlexEnd,
-    Baseline,
-    FirstBaseline,
-    LastBaseline,
-    SafeCenter,
-    UnsafeCenter,
-}
-
-impl fmt::Display for AlignItems {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            AlignItems::Normal => write!(f, "normal"),
-            AlignItems::Stretch => write!(f, "stretch"),
-            AlignItems::Center => write!(f, "center"),
-            AlignItems::Start => write!(f, "start"),
-            AlignItems::End => write!(f, "end"),
-            AlignItems::FlexStart => write!(f, "flex-start"),
-            AlignItems::FlexEnd => write!(f, "flex-end"),
-            AlignItems::Baseline => write!(f, "baseline"),
-            AlignItems::FirstBaseline => write!(f, "first baseline"),
-            AlignItems::LastBaseline => write!(f, "last baseline"),
-            AlignItems::SafeCenter => write!(f, "safe center"),
-            AlignItems::UnsafeCenter => write!(f, "unsafe center"),
-        }
-    }
-}
-
-/// https://developer.mozilla.org/en-US/docs/Web/CSS/align-self
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub enum AlignSelf {
-    Auto,
-    Normal,
-    Center,
-    Start,
-    End,
-    SelfStart,
-    SelfEnd,
-    FlexStart,
-    FlexEnd,
-    Baseline,
-    FirstBaseline,
-    LastBaseline,
-    Stretch,
-    SafeCenter,
-    UnsafeCenter,
-}
-
-impl fmt::Display for AlignSelf {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            AlignSelf::Auto => write!(f, "auto"),
-            AlignSelf::Normal => write!(f, "normal"),
-            AlignSelf::Center => write!(f, "center"),
-            AlignSelf::Start => write!(f, "start"),
-            AlignSelf::End => write!(f, "end"),
-            AlignSelf::SelfStart => write!(f, "self-start"),
-            AlignSelf::SelfEnd => write!(f, "self-end"),
-            AlignSelf::FlexStart => write!(f, "flex-start"),
-            AlignSelf::FlexEnd => write!(f, "flex-end"),
-            AlignSelf::Baseline => write!(f, "baseline"),
-            AlignSelf::FirstBaseline => write!(f, "first baseline"),
-            AlignSelf::LastBaseline => write!(f, "last baseline"),
-            AlignSelf::Stretch => write!(f, "stretch"),
-            AlignSelf::SafeCenter => write!(f, "safe center"),
-            AlignSelf::UnsafeCenter => write!(f, "unsafe center"),
-        }
-    }
-}
-
-/// https://developer.mozilla.org/en-US/docs/Web/CSS/background-attachment
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub enum BackgroundAttachment {
-    Scroll,
-    Fixed,
-    Local,
-}
-
-impl fmt::Display for BackgroundAttachment {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            BackgroundAttachment::Scroll => write!(f, "scroll"),
-            BackgroundAttachment::Fixed => write!(f, "fixed"),
-            BackgroundAttachment::Local => write!(f, "local"),
-        }
-    }
-}
-
-/// https://developer.mozilla.org/en-US/docs/Web/CSS/background-blend-mode
-#[derive(Debug, Clone, PartialEq)]
-pub enum BlendMode {
-    Normal,
-    Multiply,
-    Screen,
-    Overlay,
-    Darken,
-    Lighten,
-    ColorDodge,
-    ColorBurn,
-    HardLight,
-    SoftLight,
-    Difference,
-    Exclusion,
-    Hue,
-    Saturation,
-    Color,
-    Luminosity,
-}
-
-impl fmt::Display for BlendMode {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            BlendMode::Normal => write!(f, "normal"),
-            BlendMode::Multiply => write!(f, "multiply"),
-            BlendMode::Screen => write!(f, "screen"),
-            BlendMode::Overlay => write!(f, "overlay"),
-            BlendMode::Darken => write!(f, "darken"),
-            BlendMode::Lighten => write!(f, "lighten"),
-            BlendMode::ColorDodge => write!(f, "color-dodge"),
-            BlendMode::ColorBurn => write!(f, "color-burn"),
-            BlendMode::HardLight => write!(f, "hard-light"),
-            BlendMode::SoftLight => write!(f, "soft-light"),
-            BlendMode::Difference => write!(f, "difference"),
-            BlendMode::Exclusion => write!(f, "exclusion"),
-            BlendMode::Hue => write!(f, "hue"),
-            BlendMode::Saturation => write!(f, "saturation"),
-            BlendMode::Color => write!(f, "color"),
-            BlendMode::Luminosity => write!(f, "luminosity"),
-        }
-    }
-}
-
-#[derive(Debug, Clone, PartialEq)]
-pub enum BackgroundBox {
-    BorderBox,
-    PaddingBox,
-    ContentBox,
-}
-
-impl fmt::Display for BackgroundBox {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            BackgroundBox::BorderBox => write!(f, "border-box"),
-            BackgroundBox::PaddingBox => write!(f, "padding-box"),
-            BackgroundBox::ContentBox => write!(f, "content-box"),
-        }
-    }
-}
-
-#[derive(Debug, Clone, PartialEq)]
-pub enum BackgroundImage {
-    None,
-    Url(String),
-    // TODO other variants
-}
-
-impl fmt::Display for BackgroundImage {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            BackgroundImage::None => write!(f, "none"),
-            BackgroundImage::Url(url) => write!(f, "url({})", url),
-        }
-    }
-}
-
-#[derive(Debug, Clone, PartialEq)]
-pub enum BackgroundPosition {
-    Top,
-    Bottom,
-    Left,
-    Right,
-    Center,
-    // TODO other variants
-}
-
-impl fmt::Display for BackgroundPosition {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            BackgroundPosition::Top => write!(f, "top"),
-            BackgroundPosition::Left => write!(f, "left"),
-            BackgroundPosition::Bottom => write!(f, "bottom"),
-            BackgroundPosition::Right => write!(f, "right"),
-            BackgroundPosition::Center => write!(f, "center"),
-        }
-    }
-}
-
-#[derive(Debug, Clone, PartialEq)]
-pub enum BackgroundRepeat {
-    RepeatX,
-    RepeatY,
-    SingleOrDouble(SingleOrDouble<BgRepeatPart>),
-}
-
-impl fmt::Display for BackgroundRepeat {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            BackgroundRepeat::RepeatX => write!(f, "repeat-x"),
-            BackgroundRepeat::RepeatY => write!(f, "repeat-y"),
-            BackgroundRepeat::SingleOrDouble(v) => v.fmt(f),
-        }
-    }
-}
-
-#[derive(Debug, Clone, PartialEq)]
-pub enum BgRepeatPart {
-    Repeat,
-    Space,
-    Round,
-    NoRepeat,
-}
-
-impl fmt::Display for BgRepeatPart {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            BgRepeatPart::Repeat => write!(f, "repeat"),
-            BgRepeatPart::Space => write!(f, "space"),
-            BgRepeatPart::Round => write!(f, "round"),
-            BgRepeatPart::NoRepeat => write!(f, "no-repeat"),
-        }
-    }
-}
-
-#[derive(Debug, Clone, PartialEq)]
-pub enum BackgroundSize {
-    Cover,
-    Contain,
-    SingleOrDouble(SingleOrDouble<AutoLengthPercentage>),
-}
-
-impl fmt::Display for BackgroundSize {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            BackgroundSize::Cover => write!(f, "cover"),
-            BackgroundSize::Contain => write!(f, "contain"),
-            BackgroundSize::SingleOrDouble(v) => v.fmt(f),
-        }
-    }
-}
-
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub struct Border {
-    pub line_width: Option<LineWidth>,
-    pub line_style: Option<LineStyle>,
-    pub color: Option<Color>,
-}
-
-impl Border {
-    fn new() -> Self {
-        Border {
-            line_width: None,
-            line_style: None,
-            color: None,
-        }
-    }
-
-    fn is_full(&self) -> bool {
-        match (&self.line_width, &self.line_style, &self.color) {
-            (Some(_), Some(_), Some(_)) => true,
-            _ => false,
-        }
-    }
-
-    fn has_line_width(&self) -> bool {
-        self.line_width.is_some()
-    }
-    fn has_line_style(&self) -> bool {
-        self.line_style.is_some()
-    }
-    fn has_color(&self) -> bool {
-        self.color.is_some()
-    }
-}
-
-impl fmt::Display for Border {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        fn space(yes: bool) -> &'static str {
-            if yes {
-                " "
-            } else {
-                ""
-            }
-        }
-        let mut cont = false;
-        if let Some(line_width) = self.line_width {
-            write!(f, "{}", line_width)?;
-            cont = true;
-        }
-        if let Some(line_style) = self.line_style {
-            write!(f, "{}{}", space(cont), line_style)?;
-            cont = true;
-        }
-        if let Some(color) = self.color {
-            write!(f, "{}{}", space(cont), color)?;
-        }
-        Ok(())
-    }
-}
-
-#[derive(Debug, Clone, PartialEq)]
-pub enum BorderCollapse {
-    Collapse,
-    Separate,
-}
-
-impl fmt::Display for BorderCollapse {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            BorderCollapse::Collapse => write!(f, "collapse"),
-            BorderCollapse::Separate => write!(f, "separate"),
-        }
-    }
-}
-
-pub type BorderRadius = Calc;
-
-pub type BorderStyle = Rect<LineStyle>;
-
-pub type BorderWidth = Rect<LineWidth>;
-
-#[derive(Debug, Clone, PartialEq)]
-pub enum BoxShadow {
-    None,
-    Shadows(NonemptyCommaList<Shadow>),
-}
-
-impl fmt::Display for BoxShadow {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            BoxShadow::None => f.write_str("none"),
-            BoxShadow::Shadows(list) => write!(f, "{}", list),
-        }
-    }
-}
-
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub enum BoxSizing {
-    BorderBox,
-    ContentBox,
-}
-
-impl fmt::Display for BoxSizing {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            BoxSizing::BorderBox => f.write_str("border-box"),
-            BoxSizing::ContentBox => f.write_str("content-box"),
-        }
-    }
-}
-
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub enum Clear {
-    None,
-    Left,
-    Right,
-    Both,
-    InlineStart,
-    InlineEnd,
-}
-
-impl fmt::Display for Clear {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            Clear::None => f.write_str("none"),
-            Clear::Left => f.write_str("left"),
-            Clear::Right => f.write_str("right"),
-            Clear::Both => f.write_str("both"),
-            Clear::InlineStart => f.write_str("inline-start"),
-            Clear::InlineEnd => f.write_str("inline-end"),
-        }
-    }
-}
-
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub enum ColumnCount {
-    Auto,
-    Fixed(u32),
-}
-
-impl fmt::Display for ColumnCount {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            ColumnCount::Auto => f.write_str("auto"),
-            ColumnCount::Fixed(inner) => write!(f, "{}", inner),
-        }
-    }
-}
-
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub enum Cursor {
-    // todo url
-    Auto,
-    Default,
-    None,
-    ContextMenu,
-    Help,
-    Pointer,
-    Progress,
-    Wait,
-    Cell,
-    Crosshair,
-    Text,
-    VerticalText,
-    Alias,
-    Copy,
-    Move,
-    NoDrop,
-    NotAllowed,
-    Grab,
-    Grabbing,
-    EResize,
-    NResize,
-    NEResize,
-    NWResize,
-    SResize,
-    SEResize,
-    SWResize,
-    WResize,
-    EWResize,
-    NSResize,
-    NESWResize,
-    NWSEResize,
-    ColResize,
-    RowResize,
-    AllScroll,
-    ZoomIn,
-    ZoomOut,
-}
-
-impl fmt::Display for Cursor {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            Cursor::Auto => f.write_str("auto"),
-            Cursor::Default => f.write_str("default"),
-            Cursor::None => f.write_str("none"),
-            Cursor::ContextMenu => f.write_str("context-menu"),
-            Cursor::Help => f.write_str("help"),
-            Cursor::Pointer => f.write_str("pointer"),
-            Cursor::Progress => f.write_str("progress"),
-            Cursor::Wait => f.write_str("wait"),
-            Cursor::Cell => f.write_str("cell"),
-            Cursor::Crosshair => f.write_str("crosshair"),
-            Cursor::Text => f.write_str("text"),
-            Cursor::VerticalText => f.write_str("vertical-text"),
-            Cursor::Alias => f.write_str("alias"),
-            Cursor::Copy => f.write_str("copy"),
-            Cursor::Move => f.write_str("move"),
-            Cursor::NoDrop => f.write_str("no-drop"),
-            Cursor::NotAllowed => f.write_str("not-allowed"),
-            Cursor::Grab => f.write_str("grab"),
-            Cursor::Grabbing => f.write_str("grabbing"),
-            Cursor::EResize => f.write_str("e-resize"),
-            Cursor::NResize => f.write_str("n-resize"),
-            Cursor::NEResize => f.write_str("ne-resize"),
-            Cursor::NWResize => f.write_str("nw-resize"),
-            Cursor::SResize => f.write_str("s-resize"),
-            Cursor::SEResize => f.write_str("se-resize"),
-            Cursor::SWResize => f.write_str("sw-resize"),
-            Cursor::WResize => f.write_str("w-resize"),
-            Cursor::EWResize => f.write_str("ew-resize"),
-            Cursor::NSResize => f.write_str("ns-resize"),
-            Cursor::NESWResize => f.write_str("nesw-resize"),
-            Cursor::NWSEResize => f.write_str("nwse-resize"),
-            Cursor::ColResize => f.write_str("col-resize"),
-            Cursor::RowResize => f.write_str("row-resize"),
-            Cursor::AllScroll => f.write_str("all-scroll"),
-            Cursor::ZoomIn => f.write_str("zoom-in"),
-            Cursor::ZoomOut => f.write_str("zoom-out"),
-        }
-    }
-}
-
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub enum Display {
-    Block,
-    Flex,
-    Inline,
-    // todo incomplete
-}
-
-impl fmt::Display for Display {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            Display::Block => f.write_str("block"),
-            Display::Flex => f.write_str("flex"),
-            Display::Inline => f.write_str("inline"),
-        }
-    }
-}
-
-#[derive(Debug, Clone, PartialEq)]
-pub enum FlexBasis {
-    Width(Width21),
-    Content,
-}
-
-impl fmt::Display for FlexBasis {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            FlexBasis::Width(v) => fmt::Display::fmt(v, f),
-            FlexBasis::Content => f.write_str("content"),
-        }
-    }
-}
-
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub enum FlexDirection {
-    Row,
-    Column,
-}
-
-impl fmt::Display for FlexDirection {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            FlexDirection::Row => f.write_str("row"),
-            FlexDirection::Column => f.write_str("column"),
-        }
-    }
-}
-
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub enum FlexWrap {
-    Wrap,
-    Nowrap,
-}
-
-impl fmt::Display for FlexWrap {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            FlexWrap::Wrap => write!(f, "wrap"),
-            FlexWrap::Nowrap => write!(f, "nowrap"),
-        }
-    }
-}
-
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub enum Float {
-    None,
-    Left,
-    Right,
-    InlineStart,
-    InlineEnd,
-}
-
-impl fmt::Display for Float {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            Float::None => f.write_str("inline-end"),
-            Float::Left => f.write_str("left"),
-            Float::Right => f.write_str("right"),
-            Float::InlineStart => f.write_str("inline-start"),
-            Float::InlineEnd => f.write_str("inline-end"),
-        }
-    }
-}
-
-#[derive(Debug, Clone, PartialEq)]
-pub enum Font {
-    // todo escape when `Display`ing
-    Named(String),
-    Serif,
-    SansSerif,
-    Cursive,
-    Fantasy,
-    Monospace,
-}
-
-impl fmt::Display for Font {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            Font::Named(inner) => write!(f, "\"{}\"", inner),
-            Font::Serif => write!(f, "serif"),
-            Font::SansSerif => write!(f, "sans-serif"),
-            Font::Cursive => write!(f, "cursive"),
-            Font::Fantasy => write!(f, "fantasy"),
-            Font::Monospace => write!(f, "monospace"),
-        }
-    }
-}
-
-pub type FontFamily = NonemptyCommaList<Font>;
-
-#[derive(Debug, Clone, PartialEq)]
-pub enum FontSize {
-    XXSmall,
-    XSmall,
-    Small,
-    Medium,
-    Large,
-    XLarge,
-    XXLarge,
-    XXXLarge,
-    Larger,
-    Smaller,
-    LengthPercentage(Calc),
-}
-
-impl fmt::Display for FontSize {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            FontSize::XXSmall => f.write_str("xx-small"),
-            FontSize::XSmall => f.write_str("x-small"),
-            FontSize::Small => f.write_str("small"),
-            FontSize::Medium => f.write_str("medium"),
-            FontSize::Large => f.write_str("large"),
-            FontSize::XLarge => f.write_str("x-large"),
-            FontSize::XXLarge => f.write_str("xx-large"),
-            FontSize::XXXLarge => f.write_str("xxx-large"),
-            FontSize::Larger => f.write_str("larger"),
-            FontSize::Smaller => f.write_str("smaller"),
-            FontSize::LengthPercentage(v) => fmt::Display::fmt(v, f),
-        }
-    }
-}
-
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub enum FontStyle {
-    Normal,
-    Italic,
-    Oblique,
-}
-
-impl fmt::Display for FontStyle {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            FontStyle::Normal => f.write_str("normal"),
-            FontStyle::Italic => f.write_str("italic"),
-            FontStyle::Oblique => f.write_str("oblique"),
-        }
-    }
-}
-
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub enum FontWeight {
-    Normal,
-    Bold,
-    Lighter,
-    Bolder,
-    /// Between 1 and 1000
-    Number(f64),
-}
-
-impl fmt::Display for FontWeight {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            FontWeight::Normal => f.write_str("normal"),
-            FontWeight::Bold => f.write_str("bold"),
-            FontWeight::Lighter => f.write_str("lighter"),
-            FontWeight::Bolder => f.write_str("bolder"),
-            FontWeight::Number(v) => fmt::Display::fmt(v, f),
-        }
-    }
-}
-
-/// https://www.w3.org/TR/css-flexbox-1/#propdef-justify-content
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub enum JustifyContent {
-    FlexStart,
-    Center,
-    FlexEnd,
-    SpaceBetween,
-    SpaceAround,
-}
-
-impl fmt::Display for JustifyContent {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            JustifyContent::FlexStart => write!(f, "flex-start"),
-            JustifyContent::Center => write!(f, "center"),
-            JustifyContent::FlexEnd => write!(f, "flex-end"),
-            JustifyContent::SpaceAround => write!(f, "space-around"),
-            JustifyContent::SpaceBetween => write!(f, "space-between"),
-        }
-    }
-}
-
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub enum Length {
-    Em(f64),
-    Ex(f64),
-    In(f64),
-    Cm(f64),
-    Mm(f64),
-    Pt(f64),
-    Pc(f64),
-    Px(f64),
-    Zero,
-}
-
-impl fmt::Display for Length {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            Length::Em(val) => write!(f, "{}em", val),
-            Length::Ex(val) => write!(f, "{}ex", val),
-            Length::In(val) => write!(f, "{}in", val),
-            Length::Cm(val) => write!(f, "{}cm", val),
-            Length::Mm(val) => write!(f, "{}mm", val),
-            Length::Pt(val) => write!(f, "{}pt", val),
-            Length::Pc(val) => write!(f, "{}pc", val),
-            Length::Px(val) => write!(f, "{}px", val),
-            Length::Zero => write!(f, "0"),
-        }
-    }
-}
-
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub enum LengthPercentage {
-    Length(Length),
-    Percentage(Percentage),
-}
-
-impl fmt::Display for LengthPercentage {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            LengthPercentage::Length(v) => fmt::Display::fmt(v, f),
-            LengthPercentage::Percentage(v) => fmt::Display::fmt(v, f),
-        }
-    }
-}
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub enum LineStyle {
-    None,
-    Hidden,
-    Dotted,
-    Dashed,
-    Solid,
-    Double,
-    Groove,
-    Ridge,
-    Inset,
-    Outset,
-}
-
-impl fmt::Display for LineStyle {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            LineStyle::None => write!(f, "none"),
-            LineStyle::Hidden => write!(f, "hidden"),
-            LineStyle::Dotted => write!(f, "dotted"),
-            LineStyle::Dashed => write!(f, "dashed"),
-            LineStyle::Solid => write!(f, "solid"),
-            LineStyle::Double => write!(f, "double"),
-            LineStyle::Groove => write!(f, "groove"),
-            LineStyle::Ridge => write!(f, "ridge"),
-            LineStyle::Inset => write!(f, "inset"),
-            LineStyle::Outset => write!(f, "outset"),
-        }
-    }
-}
-
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub enum LineWidth {
-    Length(Length),
-    Thin,
-    Medium,
-    Thick,
-}
-
-impl fmt::Display for LineWidth {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            LineWidth::Length(v) => fmt::Display::fmt(v, f),
-            LineWidth::Thin => write!(f, "thin"),
-            LineWidth::Medium => write!(f, "medium"),
-            LineWidth::Thick => write!(f, "thick"),
-        }
-    }
-}
-
-// TODO this isn't the full spec for lineheight
-// (https://www.w3.org/TR/CSS2/visudet.html#propdef-line-height)
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub struct LineHeight(f64);
-
-impl fmt::Display for LineHeight {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{}", self.0)
-    }
-}
-
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub enum ListStyleType {
-    Disc,
-    Circle,
-    Square,
-    Decimal,
-    DecimalLeadingZero,
-    LowerRoman,
-    UpperRoman,
-    LowerGreek,
-    UpperGreek,
-    LowerLatin,
-    UpperLatin,
-    Armenian,
-    Georgian,
-    LowerAlpha,
-    UpperAlpha,
-    None,
-}
-
-impl fmt::Display for ListStyleType {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            ListStyleType::Disc => write!(f, "disc"),
-            ListStyleType::Circle => write!(f, "circle"),
-            ListStyleType::Square => write!(f, "square"),
-            ListStyleType::Decimal => write!(f, "decimal"),
-            ListStyleType::DecimalLeadingZero => write!(f, "decimal-leading-zero"),
-            ListStyleType::LowerRoman => write!(f, "lower-roman"),
-            ListStyleType::UpperRoman => write!(f, "upper-roman"),
-            ListStyleType::LowerGreek => write!(f, "lower-greek"),
-            ListStyleType::UpperGreek => write!(f, "upper-greek"),
-            ListStyleType::LowerLatin => write!(f, "lower-latin"),
-            ListStyleType::UpperLatin => write!(f, "upper-latin"),
-            ListStyleType::Armenian => write!(f, "armenian"),
-            ListStyleType::Georgian => write!(f, "georgian"),
-            ListStyleType::LowerAlpha => write!(f, "lower-alpha"),
-            ListStyleType::UpperAlpha => write!(f, "upper-alpha"),
-            ListStyleType::None => write!(f, "none"),
-        }
-    }
-}
-
-pub type Margin = Rect<MarginWidth>;
-
-#[derive(Debug, Clone, PartialEq)]
-pub enum AutoLengthPercentage {
-    LengthPercentage(Calc),
-    Auto,
-}
-
-impl fmt::Display for AutoLengthPercentage {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            AutoLengthPercentage::LengthPercentage(v) => fmt::Display::fmt(v, f),
-            AutoLengthPercentage::Auto => write!(f, "auto"),
-        }
-    }
-}
-
-pub type MarginWidth = AutoLengthPercentage;
-
-/// for max-width and max-height
-#[derive(Debug, Clone, PartialEq)]
-pub enum MaxWidthHeight {
-    None,
-    LengthPercentage(Calc),
-    MinContent,
-    MaxContent,
-    FitContent(Calc),
-}
-
-impl fmt::Display for MaxWidthHeight {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            MaxWidthHeight::None => write!(f, "none"),
-            MaxWidthHeight::LengthPercentage(v) => write!(f, "{}", v),
-            MaxWidthHeight::MinContent => write!(f, "min-content"),
-            MaxWidthHeight::MaxContent => write!(f, "max-content"),
-            MaxWidthHeight::FitContent(v) => write!(f, "fit-content({})", v),
-        }
-    }
-}
-
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub enum ObjectFit {
-    Fill,
-    None,
-    Contain { scale_down: bool },
-    Cover { scale_down: bool },
-}
-
-impl fmt::Display for ObjectFit {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            ObjectFit::Fill => write!(f, "fill"),
-            ObjectFit::None => write!(f, "none"),
-            ObjectFit::Contain { scale_down } => {
-                if *scale_down {
-                    write!(f, "contain scale-down")
-                } else {
-                    write!(f, "contain")
-                }
-            }
-            ObjectFit::Cover { scale_down } => {
-                if *scale_down {
-                    write!(f, "cover scale-down")
-                } else {
-                    write!(f, "cover")
-                }
-            }
-        }
-    }
-}
-
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub enum Overflow {
-    Both(OverflowXY),
-    XY(OverflowXY, OverflowXY),
-}
-
-impl fmt::Display for Overflow {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            Overflow::Both(v) => write!(f, "{}", v),
-            Overflow::XY(x, y) => write!(f, "{} {}", x, y),
-        }
-    }
-}
-
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub enum OverflowXY {
-    Visible,
-    Hidden,
-    Clip,
-    Scroll,
-    Auto,
-}
-
-impl fmt::Display for OverflowXY {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            OverflowXY::Visible => write!(f, "visible"),
-            OverflowXY::Hidden => write!(f, "hidden"),
-            OverflowXY::Clip => write!(f, "clip"),
-            OverflowXY::Scroll => write!(f, "scroll"),
-            OverflowXY::Auto => write!(f, "auto"),
-        }
-    }
-}
-
-pub type Padding = Rect<Calc>;
-
-/// for e.g. `padding-top`
-pub type PaddingWidth = Calc;
-
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub struct Percentage(pub f64);
-
-impl fmt::Display for Percentage {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{}%", self.0)
-    }
-}
-
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub enum Position {
-    Static,
-    Relative,
-    Absolute,
-    Fixed,
-}
-
-impl fmt::Display for Position {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            Position::Static => write!(f, "static"),
-            Position::Relative => write!(f, "relative"),
-            Position::Absolute => write!(f, "absolute"),
-            Position::Fixed => write!(f, "fixed"),
-        }
-    }
-}
-
-/// For parsing things in groups of 1, 2, 3 or 4 for specifying the sides of a rectangle.
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub enum Rect<T> {
-    All(T),
-    VerticalHorizontal(T, T),
-    TopHorizontalBottom(T, T, T),
-    TopRightBottomLeft(T, T, T, T),
-}
-
-impl<T> fmt::Display for Rect<T>
-where
-    T: fmt::Display,
-{
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            Rect::All(a) => write!(f, "{}", a),
-            Rect::VerticalHorizontal(v, h) => write!(f, "{} {}", v, h),
-            Rect::TopHorizontalBottom(t, h, b) => write!(f, "{} {} {}", t, h, b),
-            Rect::TopRightBottomLeft(t, r, b, l) => write!(f, "{} {} {} {}", t, r, b, l),
-        }
-    }
-}
-
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub enum Resize {
-    None,
-    Both,
-    Horizontal,
-    Vertical,
-}
-
-impl fmt::Display for Resize {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            Resize::None => write!(f, "none"),
-            Resize::Both => write!(f, "both"),
-            Resize::Horizontal => write!(f, "horizontal"),
-            Resize::Vertical => write!(f, "vertical"),
-        }
-    }
-}
-
-#[derive(Debug, Clone, PartialEq)]
-pub struct Shadow {
-    pub color: Option<Color>,
-    pub length: ShadowLength,
-    pub inset: bool,
-}
-
-impl fmt::Display for Shadow {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        // we do it in this order because it makes spacing easier.
-        write!(f, "{}", self.length)?;
-        if let Some(color) = self.color {
-            write!(f, " {}", color)?;
-        }
-        if self.inset {
-            write!(f, " inset")?;
-        }
-        Ok(())
-    }
-}
-
-#[derive(Debug, Clone, PartialEq)]
-pub enum ShadowLength {
-    Offsets {
-        horizontal: Length,
-        vertical: Length,
-    },
-    OffsetsBlur {
-        horizontal: Length,
-        vertical: Length,
-        blur: Length,
-    },
-    OffsetsBlurSpread {
-        horizontal: Length,
-        vertical: Length,
-        blur: Length,
-        spread: Length,
-    },
-}
-
-impl fmt::Display for ShadowLength {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            ShadowLength::Offsets {
-                horizontal,
-                vertical,
-            } => write!(f, "{} {}", horizontal, vertical),
-            ShadowLength::OffsetsBlur {
-                horizontal,
-                vertical,
-                blur,
-            } => write!(f, "{} {} {}", horizontal, vertical, blur),
-            ShadowLength::OffsetsBlurSpread {
-                horizontal,
-                vertical,
-                blur,
-                spread,
-            } => write!(f, "{} {} {} {}", horizontal, vertical, blur, spread),
-        }
-    }
-}
-
-#[test]
-fn test_shadow_length() {
-    for (input, output) in vec![
-        (
-            "0 10px",
-            ShadowLength::Offsets {
-                horizontal: Length::Zero,
-                vertical: Length::Px(10.0),
-            },
-        ),
-        (
-            "0 10px -10px",
-            ShadowLength::OffsetsBlur {
-                horizontal: Length::Zero,
-                vertical: Length::Px(10.0),
-                blur: Length::Px(-10.0),
-            },
-        ),
-    ] {
-        assert_eq!(syn::parse_str::<ShadowLength>(input).unwrap(), output)
-    }
-}
-
-#[derive(Debug, Copy, Clone, PartialEq)]
-pub enum TextAlign {
-    Left,
-    Right,
-    Center,
-    Justify,
-}
-
-impl fmt::Display for TextAlign {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            TextAlign::Left => write!(f, "left"),
-            TextAlign::Right => write!(f, "right"),
-            TextAlign::Center => write!(f, "center"),
-            TextAlign::Justify => write!(f, "justify"),
-        }
-    }
-}
-
-#[derive(Debug, Clone, PartialEq)]
-pub struct Url {
-    // todo modifiers
-    url: String,
-}
-
-impl fmt::Display for Url {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "url(\"{}\")", self.url)
-    }
-}
-
-#[derive(Debug, Clone, PartialEq)]
-pub enum WhiteSpace {
-    Normal,
-    Pre,
-    Nowrap,
-    PreWrap,
-    PreLine,
-}
-
-impl fmt::Display for WhiteSpace {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            WhiteSpace::Normal => write!(f, "normal"),
-            WhiteSpace::Pre => write!(f, "pre"),
-            WhiteSpace::Nowrap => write!(f, "nowrap"),
-            WhiteSpace::PreWrap => write!(f, "pre-wrap"),
-            WhiteSpace::PreLine => write!(f, "pre-line"),
-        }
-    }
-}
-
-/// values of `width` and `height`, `min-width`, `min-height`.
-#[derive(Debug, Clone, PartialEq)]
-pub enum WidthHeight {
-    Auto,
-    LengthPercentage(Calc),
-    MinContent,
-    MaxContent,
-    FitContent(Calc),
-}
-
-impl fmt::Display for WidthHeight {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            WidthHeight::Auto => write!(f, "auto"),
-            WidthHeight::LengthPercentage(v) => write!(f, "{}", v),
-            WidthHeight::MinContent => write!(f, "min-content"),
-            WidthHeight::MaxContent => write!(f, "max-content"),
-            WidthHeight::FitContent(v) => write!(f, "fit-content({})", v),
-        }
-    }
-}
-
-/// CSS2.1 width, for use with flexbox.
-#[derive(Debug, Clone, PartialEq)]
-pub enum Width21 {
-    Auto,
-    LengthPercentage(Calc),
-}
-
-impl fmt::Display for Width21 {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            Width21::Auto => write!(f, "auto"),
-            Width21::LengthPercentage(v) => fmt::Display::fmt(v, f),
-        }
-    }
-}
-
-/// A generic container for a non-empty comma-separated list of values
-#[derive(Debug, Clone, PartialEq)]
-pub struct NonemptyCommaList<T> {
-    first: T,
-    rest: Vec<T>,
-}
-
-impl<T> fmt::Display for NonemptyCommaList<T>
-where
-    T: fmt::Display,
-{
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{}", self.first)?;
-        for t in &self.rest {
-            write!(f, ",{}", t)?;
-        }
-        Ok(())
-    }
-}
-
-/// Matches one or two variables.
-#[derive(Debug, Clone, PartialEq)]
-pub enum SingleOrDouble<T> {
-    Single(T),
-    Double { horiz: T, vert: T },
-}
-
-impl<T> fmt::Display for SingleOrDouble<T>
-where
-    T: fmt::Display,
-{
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            SingleOrDouble::Single(t) => t.fmt(f),
-            SingleOrDouble::Double { vert, horiz } => write!(f, "{} {}", vert, horiz),
-        }
-    }
-}

+ 0 - 502
packages/core-macro/styles/string/lexer.rs

@@ -1,502 +0,0 @@
-//! Parse the various css types from strings directly (avoid pulling in syn if working at runtime)
-//!
-//! Differences to spec:
-//!  - Exponential floats are not supported for now.
-use std::{char, fmt, iter};
-
-const REPLACEMENT_CHAR: char = '�';
-
-#[derive(Copy, Clone, Debug, PartialEq)]
-#[non_exhaustive] // Don't allow user to create
-pub struct Span {
-    /// Inclusive
-    start: usize,
-    /// Exclusive
-    end: usize,
-}
-
-impl Span {
-    fn new(start: usize, end: usize) -> Self {
-        assert!(end > start, "end must be greater than start");
-        Span { start, end }
-    }
-
-    pub fn len(&self) -> usize {
-        self.end - self.start
-    }
-}
-
-#[derive(Debug)]
-pub struct InvalidChar {
-    ch: char,
-    pos: usize,
-}
-
-impl fmt::Display for InvalidChar {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(
-            f,
-            "invalid character `{}` found at position {}",
-            self.ch.escape_debug(),
-            self.pos
-        )
-    }
-}
-
-#[derive(Debug)]
-pub struct Lexer<'src> {
-    src: &'src str,
-    cursor: usize,
-}
-
-impl<'src> Lexer<'src> {
-    pub fn new(src: &'src str) -> Result<Lexer<'src>, InvalidChar> {
-        // Check that the user has already replaced characters as specified at
-        // https://www.w3.org/TR/css-syntax-3/#input-preprocessing
-        for (pos, ch) in src.char_indices() {
-            if ch == '\r' || ch == '\u{d}' || ch == '\0' {
-                return Err(InvalidChar { ch, pos });
-            }
-        }
-        Ok(Lexer { src, cursor: 0 })
-    }
-
-    fn len(&self) -> usize {
-        self.src.len()
-    }
-
-    fn remaining(&self) -> usize {
-        self.src.len() - self.cursor
-    }
-
-    pub fn next_token(&mut self) -> Option<Token> {
-        match self.peek() {
-            Some(token) => {
-                self.consume(&token);
-                Some(token)
-            }
-            None => None,
-        }
-    }
-
-    pub fn peek(&self) -> Option<Token> {
-        // https://www.w3.org/TR/css-syntax-3/#tokenizer-definitions
-        if let Some(comment) = self.comment() {
-            return Some(comment);
-        }
-        if let Some(tok) = self.whitespace() {
-            return Some(tok);
-        }
-        if let Some(tok) = self.string() {
-            return Some(tok);
-        }
-        match self.chars().next() {
-            Some(other) => Some(Token::new(
-                TokenKind::Error,
-                Span::new(self.cursor, self.cursor + other.len_utf8()),
-            )),
-            None => None,
-        }
-    }
-
-    pub fn peek_n(&self, n: usize) -> Option<Token> {
-        todo!()
-    }
-
-    pub fn is_empty(&self) -> bool {
-        todo!() //self.peek().is_none()
-    }
-
-    pub fn resolve_span(&self, span: Span) -> &'src str {
-        if span.end > self.len() {
-            panic!("End of requested span is past the end of the source");
-        }
-        &self.src[span.start..span.end]
-    }
-
-    /// Create another independent lexer at the given start point
-    fn fork(&self) -> Lexer {
-        Lexer {
-            src: self.src,
-            cursor: self.cursor,
-        }
-    }
-
-    pub fn consume(&mut self, tok: &Token) {
-        assert!(
-            tok.len() <= self.remaining(),
-            "trying to consume a token that would be bigger \
-            than all remaining text"
-        );
-        self.cursor += tok.len();
-    }
-
-    /// Resolve a position from cursor to position from start of src
-    fn resolve_pos(&self, pos: usize) -> usize {
-        self.cursor + pos
-    }
-
-    /// Create a span from the current position with the given length
-    fn span(&self, len: usize) -> Span {
-        debug_assert!(self.cursor + len <= self.len());
-        Span::new(self.cursor, self.cursor + len)
-    }
-
-    /// Create a span from the current position to the end
-    fn span_to_end(&self) -> Span {
-        Span::new(self.cursor, self.len())
-    }
-
-    /// Iterate over the remaining chars of the input
-    fn chars(&self) -> std::str::Chars {
-        self.src[self.cursor..].chars()
-    }
-
-    /// Iterate over the remaining chars of the input
-    fn char_indices(&self) -> std::str::CharIndices {
-        self.src[self.cursor..].char_indices()
-    }
-
-    /// Parse a comment
-    fn comment(&self) -> Option<Token> {
-        let mut ch_iter = self.char_indices().peekable();
-        if let Some((_, '/')) = ch_iter.next() {
-            if let Some((_, '*')) = ch_iter.next() {
-                loop {
-                    match ch_iter.next() {
-                        Some((_, '*')) => {
-                            if let Some((idx, '/')) = ch_iter.peek() {
-                                return Some(Token {
-                                    kind: TokenKind::Comment,
-                                    span: self.span(*idx + '/'.len_utf8()),
-                                });
-                            }
-                        }
-                        None => {
-                            return Some(Token::new(
-                                TokenKind::UnclosedComment,
-                                self.span_to_end(),
-                            ));
-                        }
-                        _ => (),
-                    }
-                }
-            }
-        }
-        None
-    }
-
-    /// Parse whitespace
-    fn whitespace(&self) -> Option<Token> {
-        let mut ch_iter = self.chars();
-        let mut len = match ch_iter.next() {
-            Some(ch) if ch.is_ascii_whitespace() => ch.len_utf8(),
-            _ => return None,
-        };
-        loop {
-            match ch_iter.next() {
-                Some(ch) if ch.is_ascii_whitespace() => len += ch.len_utf8(),
-                _ => break,
-            }
-        }
-        Some(Token {
-            kind: TokenKind::Whitespace,
-            span: self.span(len),
-        })
-    }
-
-    /// Parse either a single or double quoted string
-    fn string(&self) -> Option<Token> {
-        let mut ch_iter = self.char_indices().fuse().peekable();
-        let delim = match ch_iter.next() {
-            Some((_, '"')) => '"',
-            Some((_, '\'')) => '\'',
-            _ => return None,
-        };
-        let mut decoded_string = String::new();
-        loop {
-            match ch_iter.next() {
-                Some((end, ch)) if ch == delim => {
-                    return Some(Token {
-                        kind: TokenKind::String(decoded_string),
-                        span: self.span(end + 1), // '"'.len_utf8() == 1
-                    });
-                }
-                Some((end, '\n')) => {
-                    return Some(Token {
-                        kind: TokenKind::BadString(decoded_string),
-                        span: self.span(end + 1), // '\n'.len_utf8() == 1
-                    });
-                }
-                Some((_, '\\')) => match ch_iter.peek() {
-                    Some((_, ch)) => {
-                        if *ch == '\n' {
-                            // do nothing - skip the backslash and newline.
-                            ch_iter.next().unwrap();
-                        } else if let Some(decoded_ch) = unescape(&mut ch_iter) {
-                            decoded_string.push(decoded_ch);
-                        } else {
-                            decoded_string.push(ch_iter.next().unwrap().1);
-                        }
-                    }
-                    None => {
-                        // The spec says not to add the last '\'.
-                        // a bad string will be returned on next pass
-                        ch_iter.next().unwrap();
-                    }
-                },
-                Some((_, ch)) => decoded_string.push(ch),
-                None => {
-                    return Some(Token {
-                        kind: TokenKind::BadString(decoded_string),
-                        span: self.span_to_end(),
-                    })
-                }
-            }
-        }
-    }
-
-    /*
-    fn hash(&self) -> Option<Token> {
-        let mut iter = self.char_indices();
-        match iter.next() {
-            Some((_, '#')) => (),
-            None => return None,
-        };
-        match iter.next() {
-            Some((_, '\\')) => {}
-            _ => Some(Token {
-                kind: TokenKind::Delim('#'),
-                span: self.span(1),
-            }),
-        }
-    }
-    */
-}
-
-impl<'src> Iterator for Lexer<'src> {
-    type Item = Token;
-
-    fn next(&mut self) -> Option<Self::Item> {
-        self.next_token()
-    }
-}
-
-#[derive(Debug, PartialEq)]
-#[non_exhaustive]
-pub struct Token {
-    pub kind: TokenKind,
-    pub span: Span,
-}
-
-impl Token {
-    fn new(kind: TokenKind, span: Span) -> Self {
-        Token { kind, span }
-    }
-
-    pub fn len(&self) -> usize {
-        self.span.len()
-    }
-}
-
-#[derive(Debug, PartialEq)]
-pub enum TokenKind {
-    Ident,
-    Function,
-    At,
-    Hash,
-    String(String),
-    BadString(String),
-    Url,
-    BadUrl,
-    Delim(char),
-    Number,
-    Percentage,
-    Dimension,
-    Whitespace,
-    /// <!--
-    CDO,
-    /// -->
-    CDC,
-    /// :
-    Colon,
-    /// ;
-    Semicolon,
-    /// ,
-    Comma,
-    /// [
-    LBracket,
-    /// ]
-    RBracket,
-    /// (
-    LParen,
-    /// )
-    RParen,
-    /// {
-    LBrace,
-    /// }
-    RBrace,
-    Comment,
-    UnclosedComment,
-    /// Could not parse the next token
-    Error,
-}
-
-// Helpers
-
-/// Hex to char (up to 6 characters, e.g. "ffffff").
-///
-/// For example `"5c" => '\'`. Returns None if first char is not hex.  Consumes the hex values.
-fn unescape(input: &mut iter::Peekable<impl Iterator<Item = (usize, char)>>) -> Option<char> {
-    fn hex_acc(acc: &mut u32, next: char) {
-        debug_assert!(*acc & 0xf0000000 == 0); // make sure we don't overflow
-        (*acc) = (*acc << 4) + next.to_digit(16).unwrap()
-    }
-
-    let (_, ch) = match input.peek() {
-        Some((idx, ch)) if ch.is_ascii_hexdigit() => input.next().unwrap(),
-        _ => return None,
-    };
-
-    let mut acc = 0;
-    let mut count = 0;
-    hex_acc(&mut acc, ch);
-
-    // Here we use that the length of all valid hexdigits in utf8 is 1.
-    while count < 5
-        && input
-            .peek()
-            .map(|(_, ch)| ch.is_ascii_hexdigit())
-            .unwrap_or(false)
-    {
-        let ch = input.next().unwrap().1;
-        hex_acc(&mut acc, ch);
-        count += 1;
-    }
-
-    // consume a whitespace char if it's there
-    if input
-        .peek()
-        .map(|(_, ch)| ch.is_ascii_whitespace())
-        .unwrap_or(false)
-    {
-        input.next().unwrap();
-    }
-
-    // maybe we could just directly use `char::from_u32(acc).unwrap_or(REPLACEMENT_CHAR)`
-    // null, surrogate, or too big
-    Some(
-        if acc == 0 || (acc >= 0xd800 && acc < 0xe000) || acc >= 0x110000 {
-            REPLACEMENT_CHAR
-        } else {
-            char::from_u32(acc).unwrap() // there should be no other invalid chars.
-        },
-    )
-}
-
-#[cfg(test)]
-mod test {
-    use super::{Lexer, Span, Token, TokenKind};
-
-    #[test]
-    fn comment() {
-        println!();
-        let mut input = Lexer::new("/* a valid comment */").unwrap();
-        match input.next_token() {
-            Some(Token {
-                kind: TokenKind::Comment,
-                span,
-            }) => {
-                assert_eq!(
-                    input.resolve_span(span),
-                    "/* a valid comment */".to_string()
-                );
-                assert_eq!(span.len(), 21);
-            }
-            _ => panic!("not a comment"),
-        };
-
-        let mut input = Lexer::new("/* a comment").unwrap();
-        match input.next_token() {
-            Some(Token {
-                kind: TokenKind::UnclosedComment,
-                span,
-            }) => {
-                assert_eq!(input.resolve_span(span), "/* a comment".to_string());
-                assert_eq!(span.len(), 12);
-            }
-            _ => panic!("not a comment"),
-        };
-
-        let mut input = Lexer::new("/!* not a comment").unwrap();
-        match input.next_token() {
-            Some(Token {
-                kind: TokenKind::Error,
-                span,
-            }) => {}
-            _ => panic!("not a comment"),
-        };
-    }
-
-    #[test]
-    fn string() {
-        println!("h");
-        let mut input = Lexer::new("\" a vali\\64\\e9 \\\n string \"").unwrap();
-        match input.next_token() {
-            Some(Token {
-                kind: TokenKind::String(s),
-                span,
-            }) => {
-                assert_eq!(s, " a validé string ".to_string());
-                assert_eq!(span.len(), 26);
-            }
-            _ => panic!("not a string"),
-        };
-
-        let mut input = Lexer::new("' a valid string '").unwrap();
-        match input.next_token() {
-            Some(Token {
-                kind: TokenKind::String(s),
-                span,
-            }) => {
-                assert_eq!(s, " a valid string ".to_string());
-                assert_eq!(span.len(), 18);
-            }
-            _ => panic!("not a string"),
-        };
-
-        let mut input = Lexer::new("\" a string").unwrap();
-        match input.next_token() {
-            Some(Token {
-                kind: TokenKind::BadString(s),
-                span,
-            }) => {
-                assert_eq!(s, " a string".to_string());
-                assert_eq!(span.len(), 10);
-            }
-            _ => panic!("not a string"),
-        };
-    }
-
-    #[test]
-    fn whitespace() {
-        println!();
-        let mut input = Lexer::new("\n\t ").unwrap();
-        match input.next_token() {
-            Some(Token {
-                kind: TokenKind::Whitespace,
-                span,
-            }) => {
-                assert_eq!(input.resolve_span(span), "\n\t ".to_string());
-                assert_eq!(span.len(), 3);
-            }
-            _ => panic!("not a string"),
-        };
-    }
-
-    #[test]
-    fn escape() {
-        let mut iter = "e9".char_indices().peekable();
-        assert_eq!(super::unescape(&mut iter), Some('é'));
-    }
-}

+ 0 - 1
packages/core-macro/styles/string/mod.rs

@@ -1 +0,0 @@
-pub mod lexer;

+ 0 - 2411
packages/core-macro/styles/syn_parse.rs

@@ -1,2411 +0,0 @@
-//! Implementation of `syn::parse::Parse` for styles, and associated helper data/functions.
-// TODO make all parsers use HyphenWord where appropriate.
-// TODO make all error messages nice
-// TODO 100% test coverage
-// TODO see if I can get https://github.com/rust-lang/rust/issues/67544 accepted. then change "em" to
-// em and "ex" to ex.
-// TODO Split out extra "Dynamic" layer for each type for use in proc macro (so we can have `{ <arbitary
-// rust code> }`)
-use crate::*;
-use proc_macro2::Span;
-use std::{
-    cell::RefCell,
-    collections::BTreeSet,
-    fmt::{self, Write},
-    ops::RangeBounds,
-    str,
-};
-use syn::{
-    ext::IdentExt,
-    parse::{discouraged::Speculative, Parse, ParseStream},
-    punctuated::Punctuated,
-    spanned::Spanned,
-    Ident, Token,
-};
-
-use super::{DynamicStyle, DynamicStyles, Styles};
-
-impl Parse for DynamicStyles {
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        let punc = s.parse_terminated::<_, Token![;]>(<DynamicStyle as Parse>::parse)?;
-        Ok(DynamicStyles::from(punc.into_iter().collect::<Vec<_>>()))
-    }
-}
-
-impl Parse for Styles {
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        let punc = s.parse_terminated::<_, Token![;]>(<Style as Parse>::parse)?;
-        Ok(Styles::from(punc.into_iter().collect::<Vec<_>>()))
-    }
-}
-
-impl Parse for DynamicStyle {
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        // Pass through brackets
-        if s.peek(syn::token::Brace) {
-            Ok(DynamicStyle::Dynamic(s.parse()?))
-        } else {
-            Ok(DynamicStyle::Literal(s.parse()?))
-        }
-    }
-}
-
-impl Parse for Style {
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        if s.peek(syn::LitStr) {
-            let unchecked: syn::LitStr = s.parse()?;
-            return Ok(Style::Unchecked(unchecked.value()));
-        }
-
-        let name: HyphenWord = s.parse()?;
-        if name.try_match("dummy") {
-            return Ok(Style::Dummy);
-        }
-
-        s.parse::<Token![:]>()?;
-
-        let output = if name.try_match("align-content") {
-            Style::AlignContent(s.parse()?)
-        } else if name.try_match("align-items") {
-            Style::AlignItems(s.parse()?)
-        } else if name.try_match("align-self") {
-            Style::AlignSelf(s.parse()?)
-        // all
-        // background
-        } else if name.try_match("background-attachment") {
-            Style::BackgroundAttachment(s.parse()?)
-        } else if name.try_match("background-blend-mode") {
-            Style::BackgroundBlendMode(s.parse()?)
-        } else if name.try_match("background-clip") {
-            Style::BackgroundClip(s.parse()?)
-        } else if name.try_match("background-color") {
-            Style::BackgroundColor(s.parse()?)
-        } else if name.try_match("background-image") {
-            Style::BackgroundImage(s.parse()?)
-        } else if name.try_match("background-origin") {
-            Style::BackgroundOrigin(s.parse()?)
-        } else if name.try_match("background-position") {
-            Style::BackgroundPosition(s.parse()?)
-        } else if name.try_match("background-repeat") {
-            Style::BackgroundRepeat(s.parse()?)
-        } else if name.try_match("background-size") {
-            Style::BackgroundSize(s.parse()?)
-        } else if name.try_match("border") {
-            Style::Border(s.parse()?)
-        } else if name.try_match("border-bottom") {
-            Style::BorderBottom(s.parse()?)
-        } else if name.try_match("border-bottom-color") {
-            Style::BorderBottomColor(s.parse()?)
-        } else if name.try_match("border-bottom-left-radius") {
-            Style::BorderBottomLeftRadius(s.parse()?)
-        } else if name.try_match("border-bottom-right-radius") {
-            Style::BorderBottomRightRadius(s.parse()?)
-        } else if name.try_match("border-bottom-style") {
-            Style::BorderBottomStyle(s.parse()?)
-        } else if name.try_match("border-bottom-width") {
-            Style::BorderBottomWidth(s.parse()?)
-        } else if name.try_match("border-collapse") {
-            Style::BorderCollapse(s.parse()?)
-        } else if name.try_match("border-color") {
-            Style::BorderColor(s.parse()?)
-        // border-image
-        // border-image-outset
-        // border-image-repeat
-        // border-image-slice
-        // border-image-source
-        // border-image-width
-        } else if name.try_match("border-left") {
-            Style::BorderLeft(s.parse()?)
-        } else if name.try_match("border-left-color") {
-            Style::BorderLeftColor(s.parse()?)
-        } else if name.try_match("border-left-style") {
-            Style::BorderLeftStyle(s.parse()?)
-        } else if name.try_match("border-left-width") {
-            Style::BorderLeftWidth(s.parse()?)
-        } else if name.try_match("border-radius") {
-            Style::BorderRadius(s.parse()?)
-        } else if name.try_match("border-right") {
-            Style::BorderRight(s.parse()?)
-        } else if name.try_match("border-right-color") {
-            Style::BorderRightColor(s.parse()?)
-        } else if name.try_match("border-right-style") {
-            Style::BorderRightStyle(s.parse()?)
-        } else if name.try_match("border-right-width") {
-            Style::BorderRightWidth(s.parse()?)
-        // border-spacing
-        } else if name.try_match("border-style") {
-            Style::BorderStyle(s.parse()?)
-        } else if name.try_match("border-top") {
-            Style::BorderTop(s.parse()?)
-        } else if name.try_match("border-top-color") {
-            Style::BorderTopColor(s.parse()?)
-        } else if name.try_match("border-top-left-radius") {
-            Style::BorderTopLeftRadius(s.parse()?)
-        } else if name.try_match("border-top-right-radius") {
-            Style::BorderTopRightRadius(s.parse()?)
-        } else if name.try_match("border-top-style") {
-            Style::BorderTopStyle(s.parse()?)
-        } else if name.try_match("border-top-width") {
-            Style::BorderTopWidth(s.parse()?)
-        } else if name.try_match("border-width") {
-            Style::BorderWidth(s.parse()?)
-        } else if name.try_match("bottom") {
-            Style::Bottom(s.parse()?)
-        // box-decoration-break
-        } else if name.try_match("box-shadow") {
-            Style::BoxShadow(s.parse()?)
-        } else if name.try_match("box-sizing") {
-            Style::BoxSizing(s.parse()?)
-        // break-after
-        // break-before
-        // break-inside
-        // caption-side
-        // caret-color
-        } else if name.try_match("clear") {
-            Style::Clear(s.parse()?)
-        // clip
-        // clip-path
-        // clip-rule
-        } else if name.try_match("column-count") {
-            Style::ColumnCount(s.parse()?)
-        } else if name.try_match("color") {
-            Style::Color(s.parse()?)
-        // contain
-        // content
-        // counter-increment
-        // counter-reset
-        // cue
-        // cue-after
-        // cue-before
-        } else if name.try_match("cursor") {
-            Style::Cursor(s.parse()?)
-        // direction
-        } else if name.try_match("display") {
-            Style::Display(s.parse()?)
-        // elevation
-        // empty-cells
-        // flex
-        } else if name.try_match("flex-basis") {
-            Style::FlexBasis(s.parse()?)
-        } else if name.try_match("flex-direction") {
-            Style::FlexDirection(s.parse()?)
-        // flex-flow
-        } else if name.try_match("flex-grow") {
-            let number: Number = s.parse()?;
-            if !number.suffix.is_empty() {
-                return Err(syn::Error::new(number.span, "expected number"));
-            }
-            Style::FlexGrow(number.value)
-        } else if name.try_match("flex-shrink") {
-            let number: Number = s.parse()?;
-            if !number.suffix.is_empty() {
-                return Err(syn::Error::new(number.span, "expected number"));
-            }
-            Style::FlexShrink(number.value)
-        } else if name.try_match("flex-wrap") {
-            Style::FlexWrap(s.parse()?)
-        } else if name.try_match("float") {
-            Style::Float(s.parse()?)
-        // font
-        } else if name.try_match("font-family") {
-            Style::FontFamily(s.parse()?)
-        // font-feature-settings
-        // font-kerning
-        } else if name.try_match("font-size") {
-            Style::FontSize(s.parse()?)
-        // font-size-adjust
-        // font-stretch
-        } else if name.try_match("font-style") {
-            Style::FontStyle(s.parse()?)
-        // font-synthesis
-        // font-variant
-        // font-variant-caps
-        // font-variant-east-asian
-        // font-variant-ligatures
-        // font-variant-numeric
-        // font-variant-position
-        } else if name.try_match("font-weight") {
-            Style::FontWeight(s.parse()?)
-        // glyph-orientation-vertical
-        // grid
-        // grid-area
-        // grid-auto-columns
-        // grid-auto-flow
-        // grid-auto-rows
-        // grid-column
-        // grid-column-end
-        // grid-column-start
-        // grid-row
-        // grid-row-end
-        // grid-row-start
-        // grid-template
-        // grid-template-areas
-        // grid-template-columns
-        // grid-template-rows
-        } else if name.try_match("height") {
-            Style::Height(s.parse()?)
-        // image-orientation
-        // image-rendering
-        // isolation
-        } else if name.try_match("justify-content") {
-            Style::JustifyContent(s.parse()?)
-        } else if name.try_match("left") {
-            Style::Left(s.parse()?)
-        // letter-spacing
-        } else if name.try_match("line-height") {
-            Style::LineHeight(s.parse()?)
-        // list-style
-        // list-style-image
-        // list-style-position
-        } else if name.try_match("list-style-type") {
-            Style::ListStyleType(s.parse()?)
-        } else if name.try_match("margin") {
-            Style::Margin(s.parse()?)
-        } else if name.try_match("margin-bottom") {
-            Style::MarginBottom(s.parse()?)
-        } else if name.try_match("margin-left") {
-            Style::MarginLeft(s.parse()?)
-        } else if name.try_match("margin-right") {
-            Style::MarginRight(s.parse()?)
-        } else if name.try_match("margin-top") {
-            Style::MarginTop(s.parse()?)
-        // mask
-        // mask-border
-        // mask-border-mode
-        // mask-border-outset
-        // mask-border-repeat
-        // mask-border-slice
-        // mask-border-source
-        // mask-border-width
-        // mask-clip
-        // mask-composite
-        // mask-image
-        // mask-mode
-        // mask-origin
-        // mask-position
-        // mask-repeat
-        // mask-size
-        // mask-type
-        } else if name.try_match("max-height") {
-            Style::MaxHeight(s.parse()?)
-        } else if name.try_match("max-width") {
-            Style::MaxWidth(s.parse()?)
-        } else if name.try_match("min-height") {
-            Style::MinHeight(s.parse()?)
-        } else if name.try_match("min-width") {
-            Style::MinWidth(s.parse()?)
-        // mix-blend-mode
-        } else if name.try_match("object-fit") {
-            Style::ObjectFit(s.parse()?)
-        // object-position
-        // opacity
-        // order
-        // orphans
-        // outline
-        // outline-color
-        // outline-offset
-        // outline-style
-        // outline-width
-        } else if name.try_match("overflow") {
-            Style::Overflow(s.parse()?)
-        } else if name.try_match("overflow-x") {
-            Style::OverflowX(s.parse()?)
-        } else if name.try_match("overflow-y") {
-            Style::OverflowY(s.parse()?)
-        } else if name.try_match("padding") {
-            Style::Padding(s.parse()?)
-        } else if name.try_match("padding-bottom") {
-            Style::PaddingBottom(s.parse()?)
-        } else if name.try_match("padding-left") {
-            Style::PaddingLeft(s.parse()?)
-        } else if name.try_match("padding-right") {
-            Style::PaddingRight(s.parse()?)
-        } else if name.try_match("padding-top") {
-            Style::PaddingTop(s.parse()?)
-        // page-break-after
-        // page-break-before
-        // page-break-inside
-        // pause
-        // pause-after
-        // pause-before
-        // pitch
-        // pitch-range
-        // play-during
-        } else if name.try_match("position") {
-            Style::Position(s.parse()?)
-        // quotes
-        } else if name.try_match("resize") {
-            Style::Resize(s.parse()?)
-        // richness
-        } else if name.try_match("right") {
-            Style::Right(s.parse()?)
-        // scroll-margin
-        // scroll-margin-block
-        // scroll-margin-block-end
-        // scroll-margin-block-start
-        // scroll-margin-bottom
-        // scroll-margin-inline
-        // scroll-margin-inline-end
-        // scroll-margin-inline-start
-        // scroll-margin-left
-        // scroll-margin-right
-        // scroll-margin-top
-        // scroll-padding
-        // scroll-padding-block
-        // scroll-padding-block-end
-        // scroll-padding-block-start
-        // scroll-padding-bottom
-        // scroll-padding-inline
-        // scroll-padding-inline-end
-        // scroll-padding-inline-start
-        // scroll-padding-left
-        // scroll-padding-right
-        // scroll-padding-top
-        // scroll-snap-align
-        // scroll-snap-stop
-        // scroll-snap-type
-        // shape-image-threshold
-        // shape-margin
-        // shape-outside
-        // speak
-        // speak-header
-        // speak-numeral
-        // speak-punctuation
-        // speech-rate
-        // stress
-        // table-layout
-        } else if name.try_match("text-align") {
-            Style::TextAlign(s.parse()?)
-        // text-combine-upright
-        // text-decoration
-        // text-decoration-color
-        // text-decoration-line
-        // text-decoration-style
-        // text-emphasis
-        // text-emphasis-color
-        // text-emphasis-position
-        // text-emphasis-style
-        // text-indent
-        // text-orientation
-        // text-overflow
-        // text-shadow
-        // text-transform
-        // text-underline-position
-        } else if name.try_match("top") {
-            Style::Top(s.parse()?)
-        // transform
-        // transform-box
-        // transform-origin
-        // unicode-bidi
-        // vertical-align
-        // visibility
-        // voice-family
-        // volume
-        } else if name.try_match("white-space") {
-            Style::WhiteSpace(s.parse()?)
-        } else if name.try_match("widows") {
-            Style::Widows(integer(s, 1..)?)
-        } else if name.try_match("width") {
-            Style::Width(s.parse()?)
-        // will-change
-        // word-spacing
-        // writing-mode
-        // z-index
-        } else {
-            return Err(name.error());
-        };
-
-        if !finished_rule(s) {
-            return Err(s.error("unexpected trailing tokens in style rule"));
-        }
-
-        Ok(output)
-    }
-}
-
-impl Parse for AlignContent {
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        let name: HyphenWord = s.parse()?;
-
-        if name.try_match("flex-start") {
-            Ok(AlignContent::FlexStart)
-        } else if name.try_match("flex-end") {
-            Ok(AlignContent::FlexEnd)
-        } else if name.try_match("center") {
-            Ok(AlignContent::Center)
-        } else if name.try_match("space-between") {
-            Ok(AlignContent::SpaceBetween)
-        } else if name.try_match("space-around") {
-            Ok(AlignContent::SpaceAround)
-        } else if name.try_match("stretch") {
-            Ok(AlignContent::Stretch)
-        } else {
-            Err(name.error())
-        }
-    }
-}
-
-#[test]
-fn test_align_content() {
-    for test in vec![
-        "flex-start",
-        "flex-end",
-        "center",
-        "space-between",
-        "space-around",
-        "stretch",
-    ] {
-        assert_eq!(
-            &syn::parse_str::<AlignContent>(test).unwrap().to_string(),
-            test
-        );
-    }
-    assert_eq!(
-        &syn::parse_str::<Style>("align-content:flex-start")
-            .unwrap()
-            .to_string(),
-        "align-content:flex-start"
-    );
-}
-
-impl Parse for AlignItems {
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        let word: HyphenWord = s.parse()?;
-        if word.try_match("normal") {
-            Ok(AlignItems::Normal)
-        } else if word.try_match("stretch") {
-            Ok(AlignItems::Stretch)
-        } else if word.try_match("center") {
-            Ok(AlignItems::Center)
-        } else if word.try_match("start") {
-            Ok(AlignItems::Start)
-        } else if word.try_match("end") {
-            Ok(AlignItems::End)
-        } else if word.try_match("flex-start") {
-            Ok(AlignItems::FlexStart)
-        } else if word.try_match("flex-end") {
-            Ok(AlignItems::FlexEnd)
-        } else if word.try_match("baseline") {
-            Ok(AlignItems::Baseline)
-        } else if word.try_match("first") {
-            let word: HyphenWord = s.parse()?;
-            if word.try_match("baseline") {
-                Ok(AlignItems::FirstBaseline)
-            } else {
-                Err(word.error())
-            }
-        } else if word.try_match("last") {
-            let word: HyphenWord = s.parse()?;
-            if word.try_match("baseline") {
-                Ok(AlignItems::LastBaseline)
-            } else {
-                Err(word.error())
-            }
-        } else if word.try_match("safe") {
-            let word: HyphenWord = s.parse()?;
-            if word.try_match("center") {
-                Ok(AlignItems::SafeCenter)
-            } else {
-                Err(word.error())
-            }
-        } else if word.try_match("unsafe") {
-            let word: HyphenWord = s.parse()?;
-            if word.try_match("center") {
-                Ok(AlignItems::UnsafeCenter)
-            } else {
-                Err(word.error())
-            }
-        } else {
-            Err(word.error())
-        }
-    }
-}
-
-impl Parse for AlignSelf {
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        let word: HyphenWord = s.parse()?;
-        if word.try_match("auto") {
-            Ok(AlignSelf::Auto)
-        } else if word.try_match("normal") {
-            Ok(AlignSelf::Normal)
-        } else if word.try_match("center") {
-            Ok(AlignSelf::Center)
-        } else if word.try_match("start") {
-            Ok(AlignSelf::Start)
-        } else if word.try_match("self-start") {
-            Ok(AlignSelf::SelfStart)
-        } else if word.try_match("self-end") {
-            Ok(AlignSelf::SelfEnd)
-        } else if word.try_match("flex-start") {
-            Ok(AlignSelf::FlexStart)
-        } else if word.try_match("flex-end") {
-            Ok(AlignSelf::FlexEnd)
-        } else if word.try_match("baseline") {
-            Ok(AlignSelf::Baseline)
-        } else if word.try_match("first") {
-            let word: HyphenWord = s.parse()?;
-            if word.try_match("baseline") {
-                Ok(AlignSelf::FirstBaseline)
-            } else {
-                Err(word.error())
-            }
-        } else if word.try_match("last") {
-            let word: HyphenWord = s.parse()?;
-            if word.try_match("baseline") {
-                Ok(AlignSelf::LastBaseline)
-            } else {
-                Err(word.error())
-            }
-        } else if word.try_match("stretch") {
-            Ok(AlignSelf::Stretch)
-        } else if word.try_match("safe") {
-            let word: HyphenWord = s.parse()?;
-            if word.try_match("center") {
-                Ok(AlignSelf::SafeCenter)
-            } else {
-                Err(word.error())
-            }
-        } else if word.try_match("unsafe") {
-            let word: HyphenWord = s.parse()?;
-            if word.try_match("center") {
-                Ok(AlignSelf::UnsafeCenter)
-            } else {
-                Err(word.error())
-            }
-        } else {
-            Err(word.error())
-        }
-    }
-}
-
-impl Parse for BackgroundAttachment {
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        let word: HyphenWord = s.parse()?;
-        if word.try_match("scroll") {
-            Ok(BackgroundAttachment::Scroll)
-        } else if word.try_match("fixed") {
-            Ok(BackgroundAttachment::Fixed)
-        } else if word.try_match("local") {
-            Ok(BackgroundAttachment::Local)
-        } else {
-            Err(word.error())
-        }
-    }
-}
-
-impl Parse for BlendMode {
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        let word: HyphenWord = s.parse()?;
-        if word.try_match("normal") {
-            Ok(BlendMode::Normal)
-        } else if word.try_match("multiply") {
-            Ok(BlendMode::Multiply)
-        } else if word.try_match("screen") {
-            Ok(BlendMode::Screen)
-        } else if word.try_match("overlay") {
-            Ok(BlendMode::Overlay)
-        } else if word.try_match("darken") {
-            Ok(BlendMode::Darken)
-        } else if word.try_match("lighten") {
-            Ok(BlendMode::Lighten)
-        } else if word.try_match("color-dodge") {
-            Ok(BlendMode::ColorDodge)
-        } else if word.try_match("color-burn") {
-            Ok(BlendMode::ColorBurn)
-        } else if word.try_match("hard-light") {
-            Ok(BlendMode::HardLight)
-        } else if word.try_match("soft-light") {
-            Ok(BlendMode::SoftLight)
-        } else if word.try_match("difference") {
-            Ok(BlendMode::Difference)
-        } else if word.try_match("exclusion") {
-            Ok(BlendMode::Exclusion)
-        } else if word.try_match("hue") {
-            Ok(BlendMode::Hue)
-        } else if word.try_match("saturation") {
-            Ok(BlendMode::Saturation)
-        } else if word.try_match("color") {
-            Ok(BlendMode::Color)
-        } else if word.try_match("luminosity") {
-            Ok(BlendMode::Luminosity)
-        } else {
-            Err(word.error())
-        }
-    }
-}
-
-impl Parse for BackgroundImage {
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        let peek = HyphenWord::peek_specific(s);
-        if peek.as_ref().map(|s| s.as_str()) == Some("url") {
-            let url;
-            syn::parenthesized!(url in s);
-            let url = url.parse::<syn::LitStr>()?;
-            Ok(BackgroundImage::Url(url.value()))
-        } else {
-            let word: HyphenWord = s.parse()?;
-            word.add_expected("url");
-            if word.try_match("none") {
-                Ok(BackgroundImage::None)
-            } else {
-                Err(word.error())
-            }
-        }
-    }
-}
-
-impl Parse for BackgroundBox {
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        let word: HyphenWord = s.parse()?;
-        if word.try_match("border-box") {
-            Ok(BackgroundBox::BorderBox)
-        } else if word.try_match("padding-box") {
-            Ok(BackgroundBox::PaddingBox)
-        } else if word.try_match("content-box") {
-            Ok(BackgroundBox::ContentBox)
-        } else {
-            Err(word.error())
-        }
-    }
-}
-
-impl Parse for BackgroundPosition {
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        let word: HyphenWord = s.parse()?;
-        if word.try_match("top") {
-            Ok(BackgroundPosition::Top)
-        } else if word.try_match("bottom") {
-            Ok(BackgroundPosition::Bottom)
-        } else if word.try_match("left") {
-            Ok(BackgroundPosition::Left)
-        } else if word.try_match("right") {
-            Ok(BackgroundPosition::Right)
-        } else if word.try_match("center") {
-            Ok(BackgroundPosition::Center)
-        } else {
-            Err(word.error())
-        }
-    }
-}
-
-impl Parse for BackgroundRepeat {
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        let word: HyphenWord = s.parse()?;
-        if word.try_match("repeat-x") {
-            Ok(BackgroundRepeat::RepeatX)
-        } else if word.try_match("repeat-y") {
-            Ok(BackgroundRepeat::RepeatY)
-        } else if let Ok(v) = s.parse() {
-            Ok(BackgroundRepeat::SingleOrDouble(v))
-        } else {
-            word.add_expected("repeat");
-            word.add_expected("space");
-            word.add_expected("round");
-            word.add_expected("no-repeat");
-            Err(word.error())
-        }
-    }
-}
-
-impl Parse for BgRepeatPart {
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        let word: HyphenWord = s.parse()?;
-        if word.try_match("repeat") {
-            Ok(BgRepeatPart::Repeat)
-        } else if word.try_match("space") {
-            Ok(BgRepeatPart::Space)
-        } else if word.try_match("round") {
-            Ok(BgRepeatPart::Round)
-        } else if word.try_match("no-repeat") {
-            Ok(BgRepeatPart::NoRepeat)
-        } else {
-            Err(word.error())
-        }
-    }
-}
-
-impl Parse for BackgroundSize {
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        let word: HyphenWord = s.parse()?;
-        if word.try_match("cover") {
-            Ok(BackgroundSize::Cover)
-        } else if word.try_match("contain") {
-            Ok(BackgroundSize::Contain)
-        } else if let Ok(v) = s.parse() {
-            Ok(BackgroundSize::SingleOrDouble(v))
-        } else {
-            word.add_expected("<length>");
-            word.add_expected("<percentage>");
-            word.add_expected("auto");
-            Err(word.error())
-        }
-    }
-}
-
-impl Parse for Border {
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        fn line_width_error(span: Span) -> syn::Error {
-            syn::Error::new(span, "the border width was specified more than once")
-        }
-        fn line_style_error(span: Span) -> syn::Error {
-            syn::Error::new(span, "the border style was specified more than once")
-        }
-        fn color_error(span: Span) -> syn::Error {
-            syn::Error::new(span, "the border color was specified more than once")
-        }
-        let mut border = Border::new();
-        while !(border.is_full() || finished_rule(s)) {
-            let mut matched_something = false; // prevents an infinite loop when no matches
-            let width_fork = s.fork();
-            match width_fork.parse::<LineWidth>() {
-                Ok(line_width) => {
-                    if border.has_line_width() {
-                        return Err(line_width_error(width_fork.cursor().span()));
-                    }
-                    matched_something = true;
-                    border.line_width = Some(line_width);
-                    s.advance_to(&width_fork);
-                }
-                Err(_) => (),
-            }
-            let style_fork = s.fork();
-            match style_fork.parse::<LineStyle>() {
-                Ok(line_style) => {
-                    if border.has_line_style() {
-                        return Err(line_style_error(style_fork.cursor().span()));
-                    }
-                    matched_something = true;
-                    border.line_style = Some(line_style);
-                    s.advance_to(&style_fork);
-                }
-                Err(_) => (),
-            }
-            let color_fork = s.fork();
-            match color_fork.parse::<Color>() {
-                Ok(color) => {
-                    if border.has_color() {
-                        return Err(color_error(color_fork.cursor().span()));
-                    }
-                    matched_something = true;
-                    border.color = Some(color);
-                    s.advance_to(&color_fork);
-                }
-                Err(_) => (),
-            }
-            if !(matched_something || finished_rule(s)) {
-                return Err(syn::Error::new(
-                    s.cursor().span(),
-                    "unexpected input - expected one of border-width, border-style, color",
-                ));
-            }
-        }
-        Ok(border)
-    }
-}
-
-#[test]
-fn test_border_color() {
-    for (input, output) in vec![
-        ("black", Rect::All(Color::Black)),
-        (
-            "#fff blue",
-            Rect::VerticalHorizontal(Color::HexRGB(255, 255, 255), Color::Blue),
-        ),
-        (
-            "blue hsl(20, 5%, 100%) white",
-            Rect::TopHorizontalBottom(Color::Blue, Color::HSL(20.0, 5.0, 100.0), Color::White),
-        ),
-        (
-            "hsla(20, 5%, 100%, 0.2) #fff #ccc white",
-            Rect::TopRightBottomLeft(
-                Color::HSLA(20.0, 5.0, 100.0, 0.2),
-                Color::HexRGB(255, 255, 255),
-                Color::HexRGB(204, 204, 204),
-                Color::White,
-            ),
-        ),
-    ] {
-        assert_eq!(syn::parse_str::<Rect<Color>>(input).unwrap(), output);
-    }
-}
-
-#[test]
-fn test_border_width() {
-    for (input, output) in vec![
-        ("1px", BorderWidth::All(LineWidth::Length(Length::Px(1.0)))),
-        (
-            "1px 2\"em\"",
-            BorderWidth::VerticalHorizontal(
-                LineWidth::Length(Length::Px(1.0)),
-                LineWidth::Length(Length::Em(2.0)),
-            ),
-        ),
-        (
-            "2\"em\" medium thick",
-            BorderWidth::TopHorizontalBottom(
-                LineWidth::Length(Length::Em(2.0)),
-                LineWidth::Medium,
-                LineWidth::Thick,
-            ),
-        ),
-        (
-            "2\"em\" medium 1px thick",
-            BorderWidth::TopRightBottomLeft(
-                LineWidth::Length(Length::Em(2.0)),
-                LineWidth::Medium,
-                LineWidth::Length(Length::Px(1.0)),
-                LineWidth::Thick,
-            ),
-        ),
-    ] {
-        assert_eq!(syn::parse_str::<BorderWidth>(input).unwrap(), output);
-    }
-
-    for input in vec!["thi", "1px 1px 1px 1px 1px"] {
-        assert!(syn::parse_str::<BorderWidth>(input).is_err());
-    }
-}
-
-impl Parse for BorderCollapse {
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        let word: HyphenWord = s.parse()?;
-        if word.try_match("collapse") {
-            Ok(BorderCollapse::Collapse)
-        } else if word.try_match("separate") {
-            Ok(BorderCollapse::Separate)
-        } else {
-            Err(word.error())
-        }
-    }
-}
-
-impl Parse for BoxShadow {
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        syn::custom_keyword!(none);
-        if s.peek(none) {
-            s.parse::<none>()?;
-            Ok(BoxShadow::None)
-        } else {
-            Ok(BoxShadow::Shadows(s.parse()?))
-        }
-    }
-}
-
-impl Parse for BoxSizing {
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        let word: HyphenWord = s.parse()?;
-        if word.try_match("border-box") {
-            Ok(BoxSizing::BorderBox)
-        } else if word.try_match("content-box") {
-            Ok(BoxSizing::ContentBox)
-        } else {
-            Err(word.error())
-        }
-    }
-}
-
-impl Parse for Clear {
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        let word: HyphenWord = s.parse()?;
-        if word.try_match("none") {
-            Ok(Clear::None)
-        } else if word.try_match("left") {
-            Ok(Clear::Left)
-        } else if word.try_match("right") {
-            Ok(Clear::Right)
-        } else if word.try_match("both") {
-            Ok(Clear::Both)
-        } else if word.try_match("inline-start") {
-            Ok(Clear::InlineStart)
-        } else if word.try_match("inline-end") {
-            Ok(Clear::InlineEnd)
-        } else {
-            Err(word.error())
-        }
-    }
-}
-
-impl Parse for ColumnCount {
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        if s.peek(syn::LitInt) {
-            Ok(ColumnCount::Fixed(s.parse::<Integer<u32>>()?.into_inner()))
-        } else {
-            let word: HyphenWord = s.parse()?;
-            word.add_expected("integer");
-            if word.try_match("auto") {
-                Ok(ColumnCount::Auto)
-            } else {
-                Err(word.error())
-            }
-        }
-    }
-}
-
-#[test]
-fn test_clear() {
-    for (input, output) in vec![
-        ("none", Clear::None),
-        ("left", Clear::Left),
-        ("right", Clear::Right),
-        ("both", Clear::Both),
-        ("inline-start", Clear::InlineStart),
-        ("inline-end", Clear::InlineEnd),
-    ] {
-        assert_eq!(syn::parse_str::<Clear>(input).unwrap(), output);
-    }
-}
-
-impl Parse for Cursor {
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        let word: HyphenWord = s.parse()?;
-        if word.try_match("auto") {
-            Ok(Cursor::Auto)
-        } else if word.try_match("default") {
-            Ok(Cursor::Default)
-        } else if word.try_match("none") {
-            Ok(Cursor::None)
-        } else if word.try_match("context-menu") {
-            Ok(Cursor::ContextMenu)
-        } else if word.try_match("help") {
-            Ok(Cursor::Help)
-        } else if word.try_match("pointer") {
-            Ok(Cursor::Pointer)
-        } else if word.try_match("progress") {
-            Ok(Cursor::Progress)
-        } else if word.try_match("wait") {
-            Ok(Cursor::Wait)
-        } else if word.try_match("cell") {
-            Ok(Cursor::Cell)
-        } else if word.try_match("crosshair") {
-            Ok(Cursor::Crosshair)
-        } else if word.try_match("text") {
-            Ok(Cursor::Text)
-        } else if word.try_match("vertical-text") {
-            Ok(Cursor::VerticalText)
-        } else if word.try_match("alias") {
-            Ok(Cursor::Alias)
-        } else if word.try_match("copy") {
-            Ok(Cursor::Copy)
-        } else if word.try_match("move") {
-            Ok(Cursor::Move)
-        } else if word.try_match("no-drop") {
-            Ok(Cursor::NoDrop)
-        } else if word.try_match("not-allowed") {
-            Ok(Cursor::NotAllowed)
-        } else if word.try_match("grab") {
-            Ok(Cursor::Grab)
-        } else if word.try_match("grabbing") {
-            Ok(Cursor::Grabbing)
-        } else if word.try_match("e-resize") {
-            Ok(Cursor::EResize)
-        } else if word.try_match("n-resize") {
-            Ok(Cursor::NResize)
-        } else if word.try_match("ne-resize") {
-            Ok(Cursor::NEResize)
-        } else if word.try_match("nw-resize") {
-            Ok(Cursor::NWResize)
-        } else if word.try_match("s-resize") {
-            Ok(Cursor::SResize)
-        } else if word.try_match("se-resize") {
-            Ok(Cursor::SEResize)
-        } else if word.try_match("sw-resize") {
-            Ok(Cursor::SWResize)
-        } else if word.try_match("w-resize") {
-            Ok(Cursor::WResize)
-        } else if word.try_match("ew-resize") {
-            Ok(Cursor::EWResize)
-        } else if word.try_match("ns-resize") {
-            Ok(Cursor::NSResize)
-        } else if word.try_match("nesw-resize") {
-            Ok(Cursor::NESWResize)
-        } else if word.try_match("nwse-resize") {
-            Ok(Cursor::NWSEResize)
-        } else if word.try_match("col-resize") {
-            Ok(Cursor::ColResize)
-        } else if word.try_match("row-resize") {
-            Ok(Cursor::RowResize)
-        } else if word.try_match("all-scroll") {
-            Ok(Cursor::AllScroll)
-        } else if word.try_match("zoom-in") {
-            Ok(Cursor::ZoomIn)
-        } else if word.try_match("zoom-out") {
-            Ok(Cursor::ZoomOut)
-        } else {
-            Err(word.error())
-        }
-    }
-}
-
-impl Parse for Display {
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        let word: HyphenWord = s.parse()?;
-        if word.try_match("block") {
-            Ok(Display::Block)
-        } else if word.try_match("flex") {
-            Ok(Display::Flex)
-        } else if word.try_match("inline") {
-            Ok(Display::Inline)
-        } else {
-            Err(word.error())
-        }
-    }
-}
-
-impl Parse for FlexBasis {
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        syn::custom_keyword!(content);
-
-        if s.peek(content) {
-            s.parse::<content>()?;
-            Ok(FlexBasis::Content)
-        } else {
-            let w: Width21 = s.parse()?;
-            Ok(FlexBasis::Width(w))
-        }
-    }
-}
-
-impl Parse for FlexDirection {
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        let word: HyphenWord = s.parse()?;
-        if word.try_match("column") {
-            Ok(FlexDirection::Column)
-        } else if word.try_match("row") {
-            Ok(FlexDirection::Row)
-        } else {
-            Err(word.error())
-        }
-    }
-}
-
-impl Parse for FlexWrap {
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        let word: HyphenWord = s.parse()?;
-        if word.try_match("wrap") {
-            Ok(FlexWrap::Wrap)
-        } else if word.try_match("nowrap") {
-            Ok(FlexWrap::Nowrap)
-        } else {
-            Err(word.error())
-        }
-    }
-}
-
-impl Parse for Float {
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        let word: HyphenWord = s.parse()?;
-        if word.try_match("none") {
-            Ok(Float::None)
-        } else if word.try_match("left") {
-            Ok(Float::Left)
-        } else if word.try_match("right") {
-            Ok(Float::Right)
-        } else if word.try_match("inline-start") {
-            Ok(Float::InlineStart)
-        } else if word.try_match("inline-end") {
-            Ok(Float::InlineEnd)
-        } else {
-            Err(word.error())
-        }
-    }
-}
-
-impl Parse for Font {
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        if s.peek(syn::LitStr) {
-            Ok(Font::Named(s.parse::<syn::LitStr>()?.value()))
-        } else {
-            let name: HyphenWord = s.parse()?;
-            name.add_expected("named font");
-
-            if name.try_match("serif") {
-                Ok(Font::Serif)
-            } else if name.try_match("sans-serif") {
-                Ok(Font::SansSerif)
-            } else if name.try_match("cursive") {
-                Ok(Font::Cursive)
-            } else if name.try_match("fantasy") {
-                Ok(Font::Fantasy)
-            } else if name.try_match("monospace") {
-                Ok(Font::Fantasy)
-            } else {
-                Err(name.error())
-            }
-        }
-    }
-}
-
-#[test]
-fn test_font_family() {
-    for (input, output) in vec![
-        (
-            "cursive",
-            FontFamily {
-                first: Font::Cursive,
-                rest: vec![],
-            },
-        ),
-        (
-            "\"Amatic SC\", sans-serif",
-            FontFamily {
-                first: Font::Named("Amatic SC".to_string()),
-                rest: vec![Font::SansSerif],
-            },
-        ),
-    ] {
-        assert_eq!(syn::parse_str::<FontFamily>(input).unwrap(), output);
-    }
-
-    for val in vec![
-        "font-family:\"Font Awesome 5 Free\"",
-        "font-family:\"Some Name\",\"Another Name\",serif",
-    ] {
-        assert_eq!(&syn::parse_str::<Style>(val).unwrap().to_string(), val);
-    }
-}
-
-impl Parse for FontSize {
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        let word_fork = s.fork();
-        let name: HyphenWord = word_fork.parse()?;
-
-        if name.try_match("xx-small") {
-            s.advance_to(&word_fork);
-            Ok(FontSize::XXSmall)
-        } else if name.try_match("x-small") {
-            s.advance_to(&word_fork);
-            Ok(FontSize::XSmall)
-        } else if name.try_match("small") {
-            s.advance_to(&word_fork);
-            Ok(FontSize::Small)
-        } else if name.try_match("medium") {
-            s.advance_to(&word_fork);
-            Ok(FontSize::Medium)
-        } else if name.try_match("large") {
-            s.advance_to(&word_fork);
-            Ok(FontSize::Large)
-        } else if name.try_match("x-large") {
-            s.advance_to(&word_fork);
-            Ok(FontSize::XLarge)
-        } else if name.try_match("xx-large") {
-            s.advance_to(&word_fork);
-            Ok(FontSize::XXLarge)
-        } else if name.try_match("xxx-large") {
-            s.advance_to(&word_fork);
-            Ok(FontSize::XXXLarge)
-        } else if name.try_match("larger") {
-            s.advance_to(&word_fork);
-            Ok(FontSize::Larger)
-        } else if name.try_match("smaller") {
-            s.advance_to(&word_fork);
-            Ok(FontSize::Smaller)
-        } else {
-            s.parse().map(FontSize::LengthPercentage).map_err(|_| {
-                name.add_expected("length");
-                name.add_expected("percentage");
-                name.error()
-            })
-        }
-    }
-}
-impl Parse for FontStyle {
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        let name: HyphenWord = s.parse()?;
-
-        if name.try_match("normal") {
-            Ok(FontStyle::Normal)
-        } else if name.try_match("italic") {
-            Ok(FontStyle::Italic)
-        } else if name.try_match("oblique") {
-            Ok(FontStyle::Oblique)
-        } else {
-            Err(name.error())
-        }
-    }
-}
-
-#[test]
-fn test_font_style() {
-    for (input, output) in vec![
-        ("normal", FontStyle::Normal),
-        ("italic", FontStyle::Italic),
-        ("oblique", FontStyle::Oblique),
-    ] {
-        assert_eq!(syn::parse_str::<FontStyle>(input).unwrap(), output);
-    }
-
-    for input in vec!["norma", "normal trailing"] {
-        assert!(syn::parse_str::<FontStyle>(input).is_err());
-    }
-}
-
-impl Parse for FontWeight {
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        let name: HyphenWord = s.parse()?;
-        name.add_expected("number where 1 <= number <= 1000");
-
-        if name.try_match("normal") {
-            Ok(FontWeight::Normal)
-        } else if name.try_match("bold") {
-            Ok(FontWeight::Bold)
-        } else if name.try_match("lighter") {
-            Ok(FontWeight::Lighter)
-        } else if name.try_match("bolder") {
-            Ok(FontWeight::Bolder)
-        } else {
-            let n: Number = s.parse().map_err(|_| name.error())?;
-            if n.suffix.is_empty() && n.value >= 1.0 && n.value <= 1000.0 {
-                Ok(FontWeight::Number(n.value))
-            } else {
-                Err(name.error())
-            }
-        }
-    }
-}
-
-#[test]
-fn test_font_weight() {
-    for (input, output) in vec![
-        ("normal", FontWeight::Normal),
-        ("bold", FontWeight::Bold),
-        ("lighter", FontWeight::Lighter),
-        ("bolder", FontWeight::Bolder),
-        ("1", FontWeight::Number(1.0)),
-        ("1.0", FontWeight::Number(1.0)),
-        ("1000", FontWeight::Number(1000.0)),
-        ("1000.0", FontWeight::Number(1000.0)),
-        ("246.15", FontWeight::Number(246.15)),
-    ] {
-        match syn::parse_str::<FontWeight>(input) {
-            Ok(v) => assert_eq!(v, output),
-            Err(e) => panic!("error parsing {}: {}", input, e),
-        }
-    }
-}
-
-impl Parse for JustifyContent {
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        let name: HyphenWord = s.parse()?;
-
-        if name.try_match("flex-start") {
-            Ok(JustifyContent::FlexStart)
-        } else if name.try_match("flex-end") {
-            Ok(JustifyContent::FlexEnd)
-        } else if name.try_match("center") {
-            Ok(JustifyContent::Center)
-        } else if name.try_match("space-between") {
-            Ok(JustifyContent::SpaceBetween)
-        } else if name.try_match("space-around") {
-            Ok(JustifyContent::SpaceAround)
-        } else if name.try_match("start") {
-            // - not in level 1 spec
-            Ok(JustifyContent::FlexStart)
-        } else if name.try_match("end") {
-            // - not in level 1 spec
-            Ok(JustifyContent::FlexEnd)
-        } else {
-            Err(name.error())
-        }
-    }
-}
-
-impl Parse for Length {
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        let neg = if s.peek(Token![-]) {
-            s.parse::<Token![-]>()?;
-            true
-        } else {
-            false
-        };
-        let n: Number = s.parse()?;
-        Length::parse_from_number(n, neg)
-    }
-}
-
-impl Length {
-    fn parse_from_number(n: Number, neg: bool) -> syn::Result<Self> {
-        let neg = if neg { -1.0 } else { 1.0 };
-        if n.suffix == "em" {
-            Ok(Length::Em(n.value * neg))
-        } else if n.suffix == "ex" {
-            Ok(Length::Ex(n.value * neg))
-        } else if n.suffix == "in" {
-            Ok(Length::In(n.value * neg))
-        } else if n.suffix == "cm" {
-            Ok(Length::Cm(n.value * neg))
-        } else if n.suffix == "mm" {
-            Ok(Length::Mm(n.value * neg))
-        } else if n.suffix == "pt" {
-            Ok(Length::Pt(n.value * neg))
-        } else if n.suffix == "pc" {
-            Ok(Length::Pc(n.value * neg))
-        } else if n.suffix == "px" {
-            Ok(Length::Px(n.value * neg))
-        } else if n.suffix == "" && n.value == 0.0 {
-            Ok(Length::Zero)
-        } else {
-            // No matches so return error
-            Err(syn::Error::new(
-                n.span,
-                "expected one of `\"em\"`, `\"ex\"`, `in`, `cm`, `mm`, `pt`, `pc`, `px` after number, or 0",
-            ))
-        }
-    }
-}
-
-impl Parse for LineStyle {
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        let name = s.parse::<HyphenWord>()?;
-        if name.try_match("none") {
-            Ok(LineStyle::None)
-        } else if name.try_match("hidden") {
-            Ok(LineStyle::Hidden)
-        } else if name.try_match("dotted") {
-            Ok(LineStyle::Dotted)
-        } else if name.try_match("dashed") {
-            Ok(LineStyle::Dashed)
-        } else if name.try_match("solid") {
-            Ok(LineStyle::Solid)
-        } else if name.try_match("double") {
-            Ok(LineStyle::Double)
-        } else if name.try_match("groove") {
-            Ok(LineStyle::Groove)
-        } else if name.try_match("ridge") {
-            Ok(LineStyle::Ridge)
-        } else if name.try_match("inset") {
-            Ok(LineStyle::Inset)
-        } else if name.try_match("outset") {
-            Ok(LineStyle::Outset)
-        } else {
-            Err(name.error())
-        }
-    }
-}
-
-impl Parse for LineWidth {
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        let name = s.parse::<HyphenWord>()?;
-        if name.try_match("thin") {
-            Ok(LineWidth::Thin)
-        } else if name.try_match("medium") {
-            Ok(LineWidth::Medium)
-        } else if name.try_match("thick") {
-            Ok(LineWidth::Thick)
-        } else {
-            match s.parse::<Length>() {
-                Ok(l) => Ok(LineWidth::Length(l)),
-                Err(_) => {
-                    name.add_expected("length");
-                    Err(name.error())
-                }
-            }
-        }
-    }
-}
-
-#[test]
-fn test_parse_line_width() {
-    assert_eq!(
-        syn::parse_str::<LineWidth>("thin").unwrap(),
-        LineWidth::Thin
-    );
-}
-
-impl Parse for LineHeight {
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        Ok(LineHeight(s.parse::<syn::LitFloat>()?.base10_parse()?))
-    }
-}
-
-impl Parse for ListStyleType {
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        let name: HyphenWord = s.parse()?;
-
-        if name.try_match("disc") {
-            Ok(ListStyleType::Disc)
-        } else if name.try_match("circle") {
-            Ok(ListStyleType::Circle)
-        } else if name.try_match("square") {
-            Ok(ListStyleType::Square)
-        } else if name.try_match("decimal") {
-            Ok(ListStyleType::Decimal)
-        } else if name.try_match("decimal-leading-zero") {
-            Ok(ListStyleType::DecimalLeadingZero)
-        } else if name.try_match("lower-roman") {
-            Ok(ListStyleType::LowerRoman)
-        } else if name.try_match("upper-roman") {
-            Ok(ListStyleType::UpperRoman)
-        } else if name.try_match("lower-greek") {
-            Ok(ListStyleType::LowerGreek)
-        } else if name.try_match("upper-greek") {
-            Ok(ListStyleType::UpperGreek)
-        } else if name.try_match("lower-latin") {
-            Ok(ListStyleType::LowerLatin)
-        } else if name.try_match("upper-latin") {
-            Ok(ListStyleType::UpperLatin)
-        } else if name.try_match("armenian") {
-            Ok(ListStyleType::Armenian)
-        } else if name.try_match("georgian") {
-            Ok(ListStyleType::Georgian)
-        } else if name.try_match("lower-alpha") {
-            Ok(ListStyleType::LowerAlpha)
-        } else if name.try_match("upper-alpha") {
-            Ok(ListStyleType::UpperAlpha)
-        } else if name.try_match("none") {
-            Ok(ListStyleType::None)
-        } else {
-            Err(name.error())
-        }
-    }
-}
-
-impl Parse for MaxWidthHeight {
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        let name = s.parse::<HyphenWord>()?;
-        name.add_expected("length");
-        name.add_expected("percentage");
-        if name.try_match("none") {
-            Ok(MaxWidthHeight::None)
-        } else if name.try_match("min-content") {
-            Ok(MaxWidthHeight::MinContent)
-        } else if name.try_match("max-content") {
-            Ok(MaxWidthHeight::MaxContent)
-        } else if name.try_match("fit-content") {
-            let content;
-            syn::parenthesized!(content in s);
-            Ok(MaxWidthHeight::FitContent(content.parse()?))
-        } else {
-            s.parse()
-                .map(|lp| MaxWidthHeight::LengthPercentage(lp))
-                .map_err(|_| name.error())
-        }
-    }
-}
-
-#[test]
-fn test_max_width_height() {
-    let style: Style = syn::parse_str("max-width: 200px").unwrap();
-    assert_eq!(&style.to_string(), "max-width:200px");
-}
-
-impl<T> Parse for Rect<T>
-where
-    T: Parse,
-{
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        let first = s.parse::<T>()?;
-        let fork = s.fork();
-        let second = match fork.parse::<T>() {
-            Ok(v) => {
-                s.advance_to(&fork);
-                v
-            }
-            Err(_) => return Ok(Rect::All(first)),
-        };
-        let third = match fork.parse::<T>() {
-            Ok(v) => {
-                s.advance_to(&fork);
-                v
-            }
-            Err(_) => return Ok(Rect::VerticalHorizontal(first, second)),
-        };
-        match fork.parse::<T>() {
-            Ok(v) => {
-                s.advance_to(&fork);
-                Ok(Rect::TopRightBottomLeft(first, second, third, v))
-            }
-            Err(_) => Ok(Rect::TopHorizontalBottom(first, second, third)),
-        }
-    }
-}
-
-impl Parse for AutoLengthPercentage {
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        syn::custom_keyword!(auto);
-        if s.peek(auto) {
-            s.parse::<auto>()?;
-            Ok(AutoLengthPercentage::Auto)
-        } else {
-            Ok(AutoLengthPercentage::LengthPercentage(s.parse()?))
-        }
-    }
-}
-
-impl Parse for ObjectFit {
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        let name: HyphenWord = s.parse()?;
-        if name.try_match("fill") {
-            Ok(ObjectFit::Fill)
-        } else if name.try_match("none") {
-            Ok(ObjectFit::None)
-        } else if name.try_match("contain") {
-            if s.is_empty() {
-                Ok(ObjectFit::Contain { scale_down: false })
-            } else {
-                let scale_down_word: HyphenWord = s.parse()?;
-                if scale_down_word.try_match("scale-down") {
-                    Ok(ObjectFit::Contain { scale_down: true })
-                } else {
-                    Err(scale_down_word.error())
-                }
-            }
-        } else if name.try_match("cover") {
-            if HyphenWord::peek(s) {
-                let scale_down_word: HyphenWord = s.parse()?;
-                if scale_down_word.try_match("scale-down") {
-                    Ok(ObjectFit::Cover { scale_down: true })
-                } else {
-                    Err(scale_down_word.error())
-                }
-            } else {
-                Ok(ObjectFit::Cover { scale_down: false })
-            }
-        } else if name.try_match("scale-down") {
-            if HyphenWord::peek(s) {
-                let cover_contain: HyphenWord = s.parse()?;
-                if cover_contain.try_match("cover") {
-                    Ok(ObjectFit::Cover { scale_down: true })
-                } else if cover_contain.try_match("contain") {
-                    Ok(ObjectFit::Contain { scale_down: true })
-                } else {
-                    Err(cover_contain.error())
-                }
-            } else {
-                // defaults to contain when cover/contain not present
-                Ok(ObjectFit::Contain { scale_down: true })
-            }
-        } else {
-            Err(name.error())
-        }
-    }
-}
-
-impl Parse for Overflow {
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        let first = s.parse::<OverflowXY>()?;
-        Ok(match s.parse::<OverflowXY>() {
-            Ok(second) => Overflow::XY(first, second),
-            Err(_) => Overflow::Both(first),
-        })
-    }
-}
-
-impl Parse for OverflowXY {
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        let name: HyphenWord = s.parse()?;
-
-        if name.try_match("visible") {
-            Ok(OverflowXY::Visible)
-        } else if name.try_match("hidden") {
-            Ok(OverflowXY::Hidden)
-        } else if name.try_match("clip") {
-            Ok(OverflowXY::Clip)
-        } else if name.try_match("scroll") {
-            Ok(OverflowXY::Scroll)
-        } else if name.try_match("auto") {
-            Ok(OverflowXY::Auto)
-        } else {
-            Err(name.error())
-        }
-    }
-}
-
-impl Parse for Position {
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        let name: HyphenWord = s.parse()?;
-        if name.try_match("static") {
-            Ok(Position::Static)
-        } else if name.try_match("relative") {
-            Ok(Position::Relative)
-        } else if name.try_match("absolute") {
-            Ok(Position::Absolute)
-        } else if name.try_match("fixed") {
-            Ok(Position::Fixed)
-        } else {
-            Err(name.error())
-        }
-    }
-}
-
-#[test]
-fn test_padding() {
-    for (input, output) in vec![(
-        "padding:1\"em\"",
-        Style::Padding(Padding::All(Calc::Normal(LengthPercentage::Length(
-            Length::Em(1.0),
-        )))),
-    )] {
-        assert_eq!(syn::parse_str::<Style>(input).unwrap(), output);
-    }
-}
-
-impl Parse for Percentage {
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        let n: Number = s.parse()?;
-        if n.suffix == "%" {
-            Ok(Percentage(n.value))
-        } else {
-            Err(syn::Error::new(n.span, "expected percentage"))
-        }
-    }
-}
-
-impl Parse for WhiteSpace {
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        let name: HyphenWord = s.parse()?;
-        if name.try_match("normal") {
-            Ok(WhiteSpace::Normal)
-        } else if name.try_match("pre") {
-            Ok(WhiteSpace::Pre)
-        } else if name.try_match("nowrap") {
-            Ok(WhiteSpace::Nowrap)
-        } else if name.try_match("pre-wrap") {
-            Ok(WhiteSpace::PreWrap)
-        } else if name.try_match("pre-line") {
-            Ok(WhiteSpace::PreLine)
-        } else {
-            Err(name.error())
-        }
-    }
-}
-
-impl Parse for Width21 {
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        syn::custom_keyword!(auto);
-
-        if s.peek(auto) {
-            s.parse::<auto>()?;
-            Ok(Width21::Auto)
-        } else {
-            Ok(Width21::LengthPercentage(s.parse()?))
-        }
-    }
-}
-
-impl Parse for WidthHeight {
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        let fork = s.fork();
-        let name: HyphenWord = fork.parse()?;
-
-        if name.try_match("auto") {
-            s.advance_to(&fork);
-            Ok(WidthHeight::Auto)
-        } else if name.try_match("min-content") {
-            s.advance_to(&fork);
-            Ok(WidthHeight::MinContent)
-        } else if name.try_match("max-content") {
-            s.advance_to(&fork);
-            Ok(WidthHeight::MaxContent)
-        } else if name.try_match("fit-content") {
-            s.advance_to(&fork);
-            let content;
-            syn::parenthesized!(content in s);
-            let lp = content.parse()?;
-            if !content.is_empty() {
-                Err(content.error("trailing tokens"))
-            } else {
-                Ok(WidthHeight::FitContent(lp))
-            }
-        } else {
-            // todo error message
-            Ok(WidthHeight::LengthPercentage(s.parse()?))
-        }
-    }
-}
-
-#[test]
-fn test_width_height() {
-    for (input, output) in vec![
-        ("0", "0"),
-        ("1px", "1px"),
-        ("1\"em\"", "1em"),
-        ("calc(100% - 60px)", "calc(100% - 60px)"),
-    ] {
-        match syn::parse_str::<WidthHeight>(input) {
-            Ok(v) => assert_eq!(&v.to_string(), output),
-            Err(e) => panic!("Error in \"{}\": {}", input, e),
-        }
-    }
-}
-
-impl Parse for LengthPercentage {
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        if s.peek2(Token![%]) {
-            Ok(LengthPercentage::Percentage(s.parse()?))
-        } else {
-            Ok(LengthPercentage::Length(s.parse()?))
-        }
-    }
-}
-
-#[test]
-fn test_length_percentage() {
-    for (input, output) in vec![
-        ("1\"em\"", LengthPercentage::Length(Length::Em(1.0))),
-        ("1.0px", LengthPercentage::Length(Length::Px(1.0))),
-        ("0", LengthPercentage::Length(Length::Zero)),
-    ] {
-        assert_eq!(syn::parse_str::<LengthPercentage>(input).unwrap(), output);
-    }
-}
-
-impl Parse for Resize {
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        let name: HyphenWord = s.parse()?;
-
-        if name.try_match("none") {
-            Ok(Resize::None)
-        } else if name.try_match("both") {
-            Ok(Resize::Both)
-        } else if name.try_match("horizontal") {
-            Ok(Resize::Horizontal)
-        } else if name.try_match("vertical") {
-            Ok(Resize::Vertical)
-        } else {
-            Err(name.error())
-        }
-    }
-}
-
-impl Parse for Shadow {
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        syn::custom_keyword!(inset);
-        let mut inset_val = false;
-        let mut length: Option<ShadowLength> = None;
-        let mut color: Option<Color> = None;
-        // keep trying all three until we're done or there is an error
-        loop {
-            let mut parsed_something = false;
-            // inset (easiest)
-            if s.peek(inset) {
-                let inset_tok = s.parse::<inset>()?;
-                if inset_val {
-                    return Err(syn::Error::new(
-                        inset_tok.span(),
-                        "`inset` must be specified 0 or 1 times",
-                    ));
-                }
-                inset_val = true;
-                parsed_something = true;
-            }
-
-            // color
-            let fork = s.fork();
-            if let Ok(parsed_color) = fork.parse::<Color>() {
-                if color.is_some() {
-                    return Err(s.error("color must be specified 0 or 1 times"));
-                }
-                color = Some(parsed_color);
-                s.advance_to(&fork);
-                parsed_something = true;
-            }
-
-            // length
-            let fork = s.fork();
-            if let Ok(parsed_length) = fork.parse::<ShadowLength>() {
-                if length.is_some() {
-                    return Err(s.error("shadow length must be specified once"));
-                }
-                length = Some(parsed_length);
-                s.advance_to(&fork);
-                parsed_something = true;
-            }
-
-            // if we've failed to parse anything, end the loop.
-            if !parsed_something {
-                break;
-            }
-        }
-        if let Some(length) = length {
-            Ok(Shadow {
-                color,
-                length,
-                inset: inset_val,
-            })
-        } else {
-            Err(s.error("expected color, length, or `inset`"))
-        }
-    }
-}
-
-impl Parse for ShadowLength {
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        let horizontal: Length = s.parse()?;
-        let vertical: Length = s.parse()?;
-
-        // blur
-        let fork = s.fork();
-        let blur = match fork.parse::<Length>() {
-            Ok(blur) => {
-                s.advance_to(&fork);
-                blur
-            }
-            Err(_) => {
-                return Ok(ShadowLength::Offsets {
-                    horizontal,
-                    vertical,
-                });
-            }
-        };
-
-        // spread
-        let fork = s.fork();
-        match fork.parse::<Length>() {
-            Ok(spread) => {
-                s.advance_to(&fork);
-
-                Ok(ShadowLength::OffsetsBlurSpread {
-                    horizontal,
-                    vertical,
-                    blur,
-                    spread,
-                })
-            }
-            Err(_) => Ok(ShadowLength::OffsetsBlur {
-                horizontal,
-                vertical,
-                blur,
-            }),
-        }
-    }
-}
-
-impl Parse for TextAlign {
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        let word: HyphenWord = s.parse()?;
-        if word.try_match("left") {
-            Ok(TextAlign::Left)
-        } else if word.try_match("right") {
-            Ok(TextAlign::Right)
-        } else if word.try_match("center") {
-            Ok(TextAlign::Center)
-        } else if word.try_match("justify") {
-            Ok(TextAlign::Justify)
-        } else {
-            Err(word.error())
-        }
-    }
-}
-
-// color
-// =====
-
-impl Parse for DynamicColor {
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        Ok(if s.peek(syn::token::Brace) {
-            DynamicColor::Dynamic(s.parse()?)
-        } else {
-            DynamicColor::Literal(s.parse()?)
-        })
-    }
-}
-
-impl Parse for Color {
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        if s.peek(Token![#]) {
-            return parse_hex_color(s);
-        }
-        let fn_name: HyphenWord = s.parse()?;
-        if fn_name.try_match("hsl") {
-            parse_hsl_color(s, false)
-        } else if fn_name.try_match("hsla") {
-            parse_hsl_color(s, true)
-        } else {
-            if let Some(name) = fn_name.word.as_ref() {
-                if let Some(color) = Color::from_named(name) {
-                    return Ok(color);
-                }
-            }
-            fn_name.add_expected("named color");
-            Err(fn_name.error())
-        }
-    }
-}
-
-fn parse_hex_color(s: ParseStream) -> syn::Result<Color> {
-    const ERR_MSG: &'static str = "to avoid confusing rust, please enclose hex colors in `\"`";
-    s.parse::<Token![#]>()?;
-    if !(s.peek(syn::LitStr) || s.peek(Ident)) {
-        return Err(s.error(ERR_MSG));
-    }
-    if s.peek(syn::LitStr) {
-        let hex_str: syn::LitStr = s.parse()?;
-        color::parse_hex(&hex_str.value()).ok_or(syn::Error::new(hex_str.span(), ERR_MSG))
-    } else {
-        let hex_str: Ident = s.parse()?;
-        color::parse_hex(&hex_str.to_string()).ok_or(syn::Error::new(hex_str.span(), ERR_MSG))
-    }
-}
-
-fn parse_hsl_color(s: ParseStream, with_alpha: bool) -> syn::Result<Color> {
-    let content;
-    syn::parenthesized!(content in s);
-    let n: Number = content.parse()?;
-    n.empty_suffix()?;
-    let hue = n.value;
-    if hue < 0.0 || hue >= 360.0 {
-        return Err(syn::Error::new(
-            n.span,
-            "hue should be in the range `0 <= hue < 360`",
-        ));
-    }
-    content.parse::<Token![,]>()?;
-    let n: Number = content.parse()?;
-    if n.suffix != "%" {
-        return Err(syn::Error::new(
-            n.span,
-            "saturation should be a percentage (followed by `%`)",
-        ));
-    }
-    let sat = n.value;
-    if sat < 0.0 || sat > 100.0 {
-        return Err(syn::Error::new(
-            n.span,
-            "saturation should be in the range `0 <= sat < 100`",
-        ));
-    }
-    content.parse::<Token![,]>()?;
-    let n: Number = content.parse()?;
-    if n.suffix != "%" {
-        return Err(syn::Error::new(
-            n.span,
-            "saturation should be a percentage (followed by `%`)",
-        ));
-    }
-    let light = n.value;
-    if light < 0.0 || light > 100.0 {
-        return Err(syn::Error::new(
-            n.span,
-            "lightness should be in the range `0 <= light < 100`",
-        ));
-    }
-    // since we parse content in parentheses, we can assume no trailing characers
-    if !with_alpha {
-        return if content.is_empty() {
-            Ok(Color::HSL(hue, sat, light))
-        } else {
-            Err(content.error("trailing characters"))
-        };
-    }
-    // we are a hsla
-    content.parse::<Token![,]>()?;
-    let n: Number = content.parse()?;
-    n.empty_suffix()?;
-    let alpha = n.value;
-    if alpha < 0.0 || alpha > 1.0 {
-        return Err(syn::Error::new(
-            n.span,
-            "alpha should be in the range `0 <= alpha < 1`",
-        ));
-    }
-    if content.is_empty() {
-        Ok(Color::HSLA(hue, sat, light, alpha))
-    } else {
-        Err(content.error("unexpected trailing characters"))
-    }
-}
-
-#[test]
-fn test_color() {
-    for (input, output) in vec![
-        ("#ffffffff", Color::HexRGBA(255, 255, 255, 255)),
-        ("#ffffff", Color::HexRGB(255, 255, 255)),
-        ("#fff", Color::HexRGB(255, 255, 255)),
-        ("#\"fff\"", Color::HexRGB(255, 255, 255)),
-        ("hsl(100, 50%, 50%)", Color::HSL(100.0, 50.0, 50.0)),
-        ("hsla(60, 0%, 0%, 0.2)", Color::HSLA(60.0, 0.0, 0.0, 0.2)),
-        ("black", Color::Black),
-        ("yellow", Color::Yellow),
-    ] {
-        match syn::parse_str::<Color>(input) {
-            Ok(c) => assert_eq!(c, output),
-            Err(e) => panic!("error parsing color {}: {}", input, e),
-        }
-    }
-}
-
-// Util
-// ====
-
-impl<T> Parse for NonemptyCommaList<T>
-where
-    T: Parse,
-{
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        let punctuated = Punctuated::<T, Token![,]>::parse_separated_nonempty(s)?;
-        let mut iter = punctuated.into_iter();
-        let first = iter.next().unwrap();
-        Ok(Self {
-            first,
-            rest: iter.collect(),
-        })
-    }
-}
-
-impl<T> Parse for SingleOrDouble<T>
-where
-    T: Parse,
-{
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        let first = T::parse(s)?;
-        let fork = s.fork();
-        Ok(match T::parse(&fork) {
-            Ok(second) => {
-                s.advance_to(&fork);
-                SingleOrDouble::Double {
-                    vert: first,
-                    horiz: second,
-                }
-            }
-            Err(_) => SingleOrDouble::Single(first),
-        })
-    }
-}
-
-/// Either a float or an int, converted in either case to f64.
-///
-/// A trailing percent (`%`) character will be consumed if the number has no suffix. This is valid
-/// according to the CSS tokeniser spec.
-///
-/// TODO This only works for floats for now. Although JS only supports floats, integer literals are
-/// used in css.
-#[derive(Debug)]
-struct Number {
-    value: f64,
-    suffix: String,
-    span: Span,
-}
-
-impl Number {
-    fn empty_suffix(&self) -> syn::Result<()> {
-        if self.suffix != "" {
-            Err(syn::Error::new(
-                self.span,
-                "unexpected characters after number",
-            ))
-        } else {
-            Ok(())
-        }
-    }
-
-    #[cfg(test)]
-    fn check_value(&self, value: f64, suffix: &str) -> bool {
-        self.value == value && self.suffix == suffix
-    }
-}
-
-impl Parse for Number {
-    fn parse(s: ParseStream) -> syn::Result<Number> {
-        let lookahead = s.lookahead1();
-        let (value, mut span, mut suffix) = if lookahead.peek(syn::LitFloat) {
-            let tok = s.parse::<syn::LitFloat>()?;
-            let num = tok.base10_parse()?;
-            (num, tok.span(), tok.suffix().to_string())
-        } else if lookahead.peek(syn::LitInt) {
-            let tok = s.parse::<syn::LitInt>()?;
-            // u32 chosen because it can be safely converted into f64
-            let num = tok.base10_parse::<u32>()?;
-            (num.into(), tok.span(), tok.suffix().to_string())
-        } else {
-            return Err(lookahead.error());
-        };
-        if suffix.is_empty() {
-            // look for a `%` for the suffix
-            if s.peek(Token![%]) {
-                let tok = s.parse::<Token![%]>()?;
-                if let Some(extra_span) = span.join(tok.span) {
-                    span = extra_span;
-                }
-                suffix.push('%');
-            // work-around using literal strings because the lexer can't support suffixes beginning
-            // with `e` for floats: https://github.com/rust-lang/rust/issues/67544
-            } else if s.peek(syn::LitStr) {
-                let tok = s.parse::<syn::LitStr>()?;
-                if let Some(extra_span) = span.join(tok.span()) {
-                    span = extra_span;
-                }
-                suffix.push_str(&tok.value());
-            }
-        }
-        Ok(Number {
-            value,
-            suffix,
-            span,
-        })
-    }
-}
-
-#[test]
-fn test_number() {
-    for (input, value, suffix) in vec![
-        ("200", 200.0, ""),
-        ("200.0", 200.0, ""),
-        ("0", 0.0, ""),
-        ("0in", 0.0, "in"),
-    ] {
-        assert!(syn::parse_str::<Number>(input)
-            .unwrap()
-            .check_value(value, suffix),)
-    }
-}
-
-/// Something like `word-separated-hyphens`
-#[derive(Debug)]
-struct HyphenWord {
-    pub span: Span,
-    pub word: Option<String>,
-    /// List of tried matches - for building error.
-    tried: TryList,
-}
-
-impl HyphenWord {
-    pub fn new(span: Span, word: String) -> Self {
-        HyphenWord {
-            span,
-            word: Some(word),
-            tried: TryList::new(),
-        }
-    }
-
-    /// This allows HyphenWords to be empty. In this case the token cursor will not advance and the
-    /// returned word will be blank.
-    pub fn new_no_word(span: Span) -> Self {
-        HyphenWord {
-            span,
-            word: None,
-            tried: TryList::new(),
-        }
-    }
-
-    pub fn try_match(&self, other: &str) -> bool {
-        if Some(other) == self.word.as_ref().map(|s| s.as_str()) {
-            true
-        } else {
-            self.tried.add_literal(other);
-            false
-        }
-    }
-
-    pub fn add_expected(&self, ty: &str) {
-        self.tried.add(ty);
-    }
-
-    /// Panics if there were no calls to `try_match` before calling this function.
-    pub fn error(&self) -> syn::Error {
-        self.tried.to_error(self.span)
-    }
-
-    /// This is cheaper than peek-specific
-    pub fn peek(s: ParseStream) -> bool {
-        s.peek(Ident)
-    }
-
-    /// Peek the next HyphenWord without advancing the parser.
-    pub fn peek_specific(s: ParseStream) -> Option<String> {
-        let fork = s.fork();
-        match HyphenWord::parse(&fork) {
-            Ok(hw) => Some(hw.word.unwrap()),
-            Err(_) => None,
-        }
-    }
-}
-
-impl Parse for HyphenWord {
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        let fork = s.fork();
-        let first = match fork.call(Ident::parse_any) {
-            Ok(v) => {
-                s.advance_to(&fork);
-                v
-            }
-            Err(_) => return Ok(HyphenWord::new_no_word(s.cursor().span())),
-        };
-        let mut word = first.to_string();
-        let mut span = first.span();
-        // This is potentially unbounded. Probably not be a problem but making a note anyway.
-        while s.peek(Token![-]) {
-            let hyphen = s.parse::<Token![-]>()?;
-            if let Some(joined) = span.join(hyphen.span) {
-                span = joined;
-            }
-            let part = s.call(Ident::parse_any)?;
-            write!(word, "-{}", part).unwrap();
-            if let Some(joined) = span.join(part.span()) {
-                span = joined;
-            }
-        }
-        Ok(HyphenWord::new(span, word))
-    }
-}
-
-#[test]
-fn test_hyphen_word() {
-    let word: HyphenWord = syn::parse_str("first-second-third").unwrap();
-    assert_eq!(word.word, Some("first-second-third".to_string()));
-    assert!(syn::parse_str::<HyphenWord>("first-second-").is_err());
-    assert!(syn::parse_str::<HyphenWord>("a a").is_err());
-}
-
-/// Keeps track of a list of tokens that have been tried.
-#[derive(Debug)]
-pub struct TryList(RefCell<BTreeSet<String>>);
-
-impl TryList {
-    pub fn new() -> Self {
-        TryList(RefCell::new(BTreeSet::new()))
-    }
-
-    /// Same as add, but with quotes
-    pub fn add_literal(&self, lit: &str) {
-        self.add(format!("`{}`", lit));
-    }
-
-    pub fn add(&self, ty: impl Into<String>) {
-        self.0.borrow_mut().insert(ty.into());
-    }
-
-    fn to_error(&self, span: Span) -> syn::Error {
-        let tried = self.0.borrow();
-        let mut iter = tried.iter();
-        let start = iter.next().unwrap().to_owned();
-        let list = iter.fold(start, |mut acc, itm| {
-            write!(acc, ", {}", itm).unwrap();
-            acc
-        });
-        let error_msg = format!("expected one of {}", list);
-        syn::Error::new(span, error_msg)
-    }
-}
-
-/// Whether we are at the end of a rule. Either the stream will be empty, or there will be a
-/// semi-colon.
-fn finished_rule(s: ParseStream) -> bool {
-    s.is_empty() || s.peek(Token![;])
-}
-
-// Parsing integers
-
-#[derive(Debug, PartialEq)]
-struct Integer<T> {
-    value: T,
-}
-
-impl<T> Integer<T> {
-    fn into_inner(self) -> T {
-        self.value
-    }
-}
-
-impl<T> Parse for Integer<T>
-where
-    T: str::FromStr + fmt::Display + PartialOrd<T>,
-    <T as str::FromStr>::Err: fmt::Display,
-{
-    fn parse(s: ParseStream) -> syn::Result<Self> {
-        Ok(Integer {
-            value: integer(s, ..)?,
-        })
-    }
-}
-
-/// Parse an integer, with an optional allowed range.
-fn integer<T, R>(s: ParseStream, range: R) -> syn::Result<T>
-where
-    R: RangeBounds<T> + fmt::Debug,
-    T: str::FromStr + fmt::Display + PartialOrd<T>,
-    <T as str::FromStr>::Err: fmt::Display,
-{
-    let fixed = s.parse::<syn::LitInt>()?;
-    let span = fixed.span();
-    if fixed.suffix().is_empty() {
-        let fixed = fixed.base10_parse()?;
-        if range.contains(&fixed) {
-            Ok(fixed)
-        } else {
-            Err(syn::Error::new(
-                span,
-                format!(
-                    "expected a number in the range {:?}, found {}",
-                    range, fixed
-                ),
-            ))
-        }
-    } else {
-        Err(syn::Error::new(span, "the number should not have a suffix"))
-    }
-}
-
-#[test]
-fn test_parse_integer() {
-    let x: Integer<u8> = syn::parse_str("123").unwrap();
-    assert_eq!(x.into_inner(), 123);
-    let x: syn::Result<Integer<u8>> = syn::parse_str("256");
-    assert!(x.is_err());
-}
-
-// tests
-
-#[test]
-fn downstream_bug1() {
-    let s: Styles = syn::parse_str(
-        "display: flex;
-        flex-direction: column;
-        flex-grow: 1;
-        flex-shrink: 0;",
-    )
-    .unwrap();
-    assert_eq!(
-        s.rules,
-        vec![
-            Style::Display(Display::Flex),
-            Style::FlexDirection(FlexDirection::Column),
-            Style::FlexGrow(1.0),
-            Style::FlexShrink(0.0)
-        ]
-    )
-}
-
-#[test]
-#[ignore]
-fn inline_logic() {
-    todo!()
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    /// Use if you want to test that something parses, but not if it looks the same when
-    /// stringified. Example "border: 1px" -> "border:1px" but we still might want to check that
-    /// the former parses.
-    fn parse(input: &str) -> Style {
-        syn::parse_str(input).unwrap()
-    }
-
-    /// This function can be used to quickly write tests to check that a parse and a stringify are
-    /// opposites.
-    fn round_trip_style(input: &str) {
-        assert_eq!(&parse(input).to_string(), input);
-    }
-
-    #[test]
-    fn border_bottom_left_radius() {
-        round_trip_style("border-bottom-left-radius:30% 3px");
-    }
-
-    #[test]
-    fn border_bottom_right_radius() {
-        round_trip_style("border-bottom-right-radius:0 0");
-    }
-
-    #[test]
-    fn border_collapse() {
-        round_trip_style("border-collapse:collapse");
-    }
-
-    #[test]
-    fn border_width() {
-        round_trip_style("border-width:1px");
-        round_trip_style("border-width:0 2px 50pt 0");
-    }
-}

+ 3 - 3
packages/core/Cargo.toml

@@ -22,9 +22,7 @@ longest-increasing-subsequence = "0.1.0"
 # internall used
 log = { version = "0.4", features = ["release_max_level_off"] }
 
-futures-util = { version = "0.3.15", default-features = false, features = [
-    "std",
-] }
+futures-util = { version = "0.3.15", default-features = false }
 
 smallvec = "1.6.1"
 
@@ -39,6 +37,8 @@ indexmap = "1.7.0"
 
 # Serialize the Edits for use in Webview/Liveview instances
 serde = { version = "1", features = ["derive"], optional = true }
+
+# todo: I want to get rid of this
 backtrace = "0.3.63"
 
 [dev-dependencies]

+ 5 - 0
packages/core/architecture.md

@@ -201,3 +201,8 @@ Open questions:
     - react says no - they are continuous
     - but if we received both - then we don't need to diff, do we? run as many as we can and then finally diff?
 
+
+
+## Render functions
+
+One main issue of components is type eras

+ 2 - 2
packages/core/src/component.rs

@@ -5,12 +5,12 @@
 //! if the type supports PartialEq. The Properties trait is used by the rsx! and html! macros to generate the type-safe builder
 //! that ensures compile-time required and optional fields on cx.
 
-use crate::innerlude::{Context, Element, LazyNodes, NodeLink};
+use crate::innerlude::{Context, Element, LazyNodes, VPortal};
 
 pub struct FragmentProps(Element);
 pub struct FragmentBuilder<const BUILT: bool>(Element);
 impl FragmentBuilder<false> {
-    pub fn children(self, children: Option<NodeLink>) -> FragmentBuilder<true> {
+    pub fn children(self, children: Option<VPortal>) -> FragmentBuilder<true> {
         FragmentBuilder(children)
     }
 }

+ 109 - 94
packages/core/src/diff.rs

@@ -198,12 +198,13 @@ impl<'bump> DiffStack<'bump> {
         }
     }
 
-    fn push_subtree(&mut self) {
-        self.nodes_created_stack.push(0);
-        self.instructions.push(DiffInstruction::Mount {
-            and: MountType::Append,
-        });
-    }
+    // todo: subtrees
+    // fn push_subtree(&mut self) {
+    //     self.nodes_created_stack.push(0);
+    //     self.instructions.push(DiffInstruction::Mount {
+    //         and: MountType::Append,
+    //     });
+    // }
 
     fn push_nodes_created(&mut self, count: usize) {
         self.nodes_created_stack.push(count);
@@ -289,7 +290,7 @@ impl<'bump> DiffState<'bump> {
                 1
             }
 
-            VNode::Linked(linked) => {
+            VNode::Portal(linked) => {
                 let node = unsafe { &*linked.node };
                 let node: &VNode = unsafe { std::mem::transmute(node) };
                 self.push_all_nodes(node)
@@ -357,8 +358,8 @@ impl<'bump> DiffState<'bump> {
             VNode::Placeholder(anchor) => self.create_anchor_node(anchor, node),
             VNode::Element(element) => self.create_element_node(element, node),
             VNode::Fragment(frag) => self.create_fragment_node(frag),
-            VNode::Component(component) => self.create_component_node(component),
-            VNode::Linked(linked) => self.create_linked_node(linked),
+            VNode::Component(component) => self.create_component_node(*component),
+            VNode::Portal(linked) => self.create_linked_node(linked),
         }
     }
 
@@ -422,14 +423,18 @@ impl<'bump> DiffState<'bump> {
             self.mutations.set_attribute(attr, real_id.as_u64());
         }
 
-        if !children.is_empty() && children.len() == 1 {
-            if let VNode::Text(vtext) = children[0] {
-                self.mutations.set_text(vtext.text, real_id.as_u64());
-                return;
-            }
-        }
+        // todo: the settext optimization
 
-        self.stack.create_children(children, MountType::Append);
+        // if children.len() == 1 {
+        //     if let VNode::Text(vtext) = children[0] {
+        //         self.mutations.set_text(vtext.text, real_id.as_u64());
+        //         return;
+        //     }
+        // }
+
+        if !children.is_empty() {
+            self.stack.create_children(children, MountType::Append);
+        }
     }
 
     fn create_fragment_node(&mut self, frag: &'bump VFragment<'bump>) {
@@ -454,8 +459,6 @@ impl<'bump> DiffState<'bump> {
             self.scopes
                 .new_with_key(fc_ptr, caller, parent_scope, container, height, subtree);
 
-        log::debug!("container for scope {:?} is {:?}", new_idx, container);
-
         // Actually initialize the caller's slot with the right address
         vcomponent.associated_scope.set(Some(new_idx));
 
@@ -463,18 +466,12 @@ impl<'bump> DiffState<'bump> {
             let cur_scope = self.scopes.get_scope(&parent_idx).unwrap();
             let extended = unsafe { std::mem::transmute(vcomponent) };
             cur_scope.items.borrow_mut().borrowed_props.push(extended);
+        } else {
+            // the props are currently bump allocated but we need to move them to the heap
         }
 
-        // TODO:
-        //  add noderefs to current noderef list Noderefs
-        //  add effects to current effect list Effects
-        let new_component = self.scopes.get_scope(&new_idx).unwrap();
-
-        log::debug!(
-            "initializing component {:?} with height {:?}",
-            new_idx,
-            height + 1
-        );
+        // TODO: add noderefs to current noderef list Noderefs
+        let _new_component = self.scopes.get_scope(&new_idx).unwrap();
 
         // Run the scope for one iteration to initialize it
         if self.scopes.run_scope(&new_idx) {
@@ -482,16 +479,17 @@ impl<'bump> DiffState<'bump> {
             let nextnode = self.scopes.fin_head(&new_idx);
             self.stack.create_component(new_idx, nextnode);
 
-            if new_component.is_subtree_root.get() {
-                self.stack.push_subtree();
-            }
+            // todo: subtrees
+            // if new_component.is_subtree_root.get() {
+            //     self.stack.push_subtree();
+            // }
         }
 
         // Finally, insert this scope as a seen node.
         self.seen_scopes.insert(new_idx);
     }
 
-    fn create_linked_node(&mut self, link: &'bump NodeLink) {
+    fn create_linked_node(&mut self, link: &'bump VPortal) {
         if link.scope_id.get().is_none() {
             if let Some(cur_scope) = self.stack.current_scope() {
                 link.scope_id.set(Some(cur_scope));
@@ -513,17 +511,17 @@ impl<'bump> DiffState<'bump> {
                 self.diff_text_nodes(old, new, old_node, new_node);
             }
             (Component(old), Component(new)) => {
-                self.diff_component_nodes(old_node, new_node, old, new)
+                self.diff_component_nodes(old_node, new_node, *old, *new)
             }
             (Fragment(old), Fragment(new)) => self.diff_fragment_nodes(old, new),
             (Placeholder(old), Placeholder(new)) => new.dom_id.set(old.dom_id.get()),
             (Element(old), Element(new)) => self.diff_element_nodes(old, new, old_node, new_node),
-            (Linked(old), Linked(new)) => self.diff_linked_nodes(old, new),
+            (Portal(old), Portal(new)) => self.diff_linked_nodes(old, new),
 
             // Anything else is just a basic replace and create
             (
-                Linked(_) | Component(_) | Fragment(_) | Text(_) | Element(_) | Placeholder(_),
-                Linked(_) | Component(_) | Fragment(_) | Text(_) | Element(_) | Placeholder(_),
+                Portal(_) | Component(_) | Fragment(_) | Text(_) | Element(_) | Placeholder(_),
+                Portal(_) | Component(_) | Fragment(_) | Text(_) | Element(_) | Placeholder(_),
             ) => self
                 .stack
                 .create_node(new_node, MountType::Replace { old: old_node }),
@@ -636,60 +634,76 @@ impl<'bump> DiffState<'bump> {
             }
         }
 
-        match (old.children.len(), new.children.len()) {
-            (0, 0) => {}
-            (1, 1) => {
-                let old1 = &old.children[0];
-                let new1 = &new.children[0];
-
-                match (old1, new1) {
-                    (VNode::Text(old_text), VNode::Text(new_text)) => {
-                        if old_text.text != new_text.text {
-                            self.mutations.set_text(new_text.text, root.as_u64());
-                        }
-                    }
-                    (VNode::Text(_old_text), _) => {
-                        self.stack.element_stack.push(root);
-                        self.stack.instructions.push(DiffInstruction::PopElement);
-                        self.stack.create_node(new1, MountType::Append);
-                    }
-                    (_, VNode::Text(new_text)) => {
-                        self.remove_nodes([old1], false);
-                        self.mutations.set_text(new_text.text, root.as_u64());
-                    }
-                    _ => {
-                        self.stack.element_stack.push(root);
-                        self.stack.instructions.push(DiffInstruction::PopElement);
-                        self.diff_children(old.children, new.children);
-                    }
-                }
-            }
-            (0, 1) => {
-                if let VNode::Text(text) = &new.children[0] {
-                    self.mutations.set_text(text.text, root.as_u64());
-                } else {
-                    self.stack.element_stack.push(root);
-                    self.stack.instructions.push(DiffInstruction::PopElement);
-                }
-            }
-            (0, _) => {
-                self.mutations.edits.push(PushRoot {
-                    root: root.as_u64(),
-                });
-                self.stack.element_stack.push(root);
-                self.stack.instructions.push(DiffInstruction::PopElement);
-                self.stack.create_children(new.children, MountType::Append);
-            }
-            (_, 0) => {
-                self.remove_nodes(old.children, false);
-                self.mutations.set_text("", root.as_u64());
-            }
-            (_, _) => {
-                self.stack.element_stack.push(root);
-                self.stack.instructions.push(DiffInstruction::PopElement);
-                self.diff_children(old.children, new.children);
-            }
+        if old.children.is_empty() && !new.children.is_empty() {
+            self.mutations.edits.push(PushRoot {
+                root: root.as_u64(),
+            });
+            self.stack.element_stack.push(root);
+            self.stack.instructions.push(DiffInstruction::PopElement);
+            self.stack.create_children(new.children, MountType::Append);
+        } else {
+            self.stack.element_stack.push(root);
+            self.stack.instructions.push(DiffInstruction::PopElement);
+            self.diff_children(old.children, new.children);
         }
+
+        // todo: this is for the "settext" optimization
+        // it works, but i'm not sure if it's the direction we want to take
+
+        // match (old.children.len(), new.children.len()) {
+        //     (0, 0) => {}
+        //     (1, 1) => {
+        //         let old1 = &old.children[0];
+        //         let new1 = &new.children[0];
+
+        //         match (old1, new1) {
+        //             (VNode::Text(old_text), VNode::Text(new_text)) => {
+        //                 if old_text.text != new_text.text {
+        //                     self.mutations.set_text(new_text.text, root.as_u64());
+        //                 }
+        //             }
+        //             (VNode::Text(_old_text), _) => {
+        //                 self.stack.element_stack.push(root);
+        //                 self.stack.instructions.push(DiffInstruction::PopElement);
+        //                 self.stack.create_node(new1, MountType::Append);
+        //             }
+        //             (_, VNode::Text(new_text)) => {
+        //                 self.remove_nodes([old1], false);
+        //                 self.mutations.set_text(new_text.text, root.as_u64());
+        //             }
+        //             _ => {
+        //                 self.stack.element_stack.push(root);
+        //                 self.stack.instructions.push(DiffInstruction::PopElement);
+        //                 self.diff_children(old.children, new.children);
+        //             }
+        //         }
+        //     }
+        //     (0, 1) => {
+        //         if let VNode::Text(text) = &new.children[0] {
+        //             self.mutations.set_text(text.text, root.as_u64());
+        //         } else {
+        //             self.stack.element_stack.push(root);
+        //             self.stack.instructions.push(DiffInstruction::PopElement);
+        //         }
+        //     }
+        //     (0, _) => {
+        //         self.mutations.edits.push(PushRoot {
+        //             root: root.as_u64(),
+        //         });
+        //         self.stack.element_stack.push(root);
+        //         self.stack.instructions.push(DiffInstruction::PopElement);
+        //         self.stack.create_children(new.children, MountType::Append);
+        //     }
+        //     (_, 0) => {
+        //         self.remove_nodes(old.children, false);
+        //         self.mutations.set_text("", root.as_u64());
+        //     }
+        //     (_, _) => {
+        //         self.stack.element_stack.push(root);
+        //         self.stack.instructions.push(DiffInstruction::PopElement);
+        //         self.diff_children(old.children, new.children);
+        //     }
+        // }
     }
 
     fn diff_component_nodes(
@@ -721,6 +735,7 @@ impl<'bump> DiffState<'bump> {
                     .get_scope_mut(&scope_addr)
                     .unwrap_or_else(|| panic!("could not find {:?}", scope_addr))
             };
+
             scope.caller = unsafe { std::mem::transmute(new.caller) };
 
             // React doesn't automatically memoize, but we do.
@@ -754,7 +769,7 @@ impl<'bump> DiffState<'bump> {
         self.diff_children(old.children, new.children);
     }
 
-    fn diff_linked_nodes(&mut self, old: &'bump NodeLink, new: &'bump NodeLink) {
+    fn diff_linked_nodes(&mut self, old: &'bump VPortal, new: &'bump VPortal) {
         if !std::ptr::eq(old.node, new.node) {
             // if the ptrs are the same then theyr're the same
             let old: &VNode = unsafe { std::mem::transmute(&*old.node) };
@@ -1207,7 +1222,7 @@ impl<'bump> DiffState<'bump> {
                 VNode::Text(t) => break t.dom_id.get(),
                 VNode::Element(t) => break t.dom_id.get(),
                 VNode::Placeholder(t) => break t.dom_id.get(),
-                VNode::Linked(l) => {
+                VNode::Portal(l) => {
                     let node: &VNode = unsafe { std::mem::transmute(&*l.node) };
                     self.find_last_element(node);
                 }
@@ -1235,7 +1250,7 @@ impl<'bump> DiffState<'bump> {
                     let scope_id = el.associated_scope.get().unwrap();
                     search_node = Some(self.scopes.root_node(&scope_id));
                 }
-                VNode::Linked(link) => {
+                VNode::Portal(link) => {
                     let node = unsafe { std::mem::transmute(&*link.node) };
                     search_node = Some(node);
                 }
@@ -1281,7 +1296,7 @@ impl<'bump> DiffState<'bump> {
                 self.scopes.try_remove(&scope_id).unwrap();
             }
 
-            VNode::Linked(l) => {
+            VNode::Portal(l) => {
                 let node: &'bump VNode<'bump> = unsafe { std::mem::transmute(&*l.node) };
                 self.replace_node(node, nodes_created);
             }
@@ -1330,7 +1345,7 @@ impl<'bump> DiffState<'bump> {
                     self.remove_nodes(f.children, gen_muts);
                 }
 
-                VNode::Linked(l) => {
+                VNode::Portal(l) => {
                     let node = unsafe { std::mem::transmute(&*l.node) };
                     self.remove_nodes(Some(node), gen_muts);
                 }

+ 2 - 2
packages/core/src/lib.rs

@@ -31,14 +31,14 @@ pub(crate) mod innerlude {
     pub use crate::scopearena::*;
     pub use crate::virtual_dom::*;
 
-    pub type Element = Option<NodeLink>;
+    pub type Element = Option<VPortal>;
     pub type FC<P> = for<'a> fn(Context<'a>, &'a P) -> Element;
 }
 
 pub use crate::innerlude::{
     Attribute, Context, DioxusElement, DomEdit, Element, ElementId, EventPriority, IntoVNode,
     LazyNodes, Listener, MountType, Mutations, NodeFactory, Properties, SchedulerMsg, ScopeId,
-    UserEvent, VElement, VFragment, VNode, VPlaceholder, VSuspended, VirtualDom, FC,
+    UserEvent, VElement, VFragment, VNode, VirtualDom, FC,
 };
 
 pub mod prelude {

+ 48 - 62
packages/core/src/nodes.rs

@@ -129,7 +129,7 @@ pub enum VNode<'src> {
     ///
     /// let node: NodeLink = vdom.render_vnode(rsx!( "hello" ));
     /// ```
-    Linked(NodeLink),
+    Portal(VPortal),
 }
 
 impl<'src> VNode<'src> {
@@ -139,10 +139,9 @@ impl<'src> VNode<'src> {
             VNode::Element(el) => el.key,
             VNode::Component(c) => c.key,
             VNode::Fragment(f) => f.key,
-
             VNode::Text(_t) => None,
             VNode::Placeholder(_f) => None,
-            VNode::Linked(_c) => None,
+            VNode::Portal(_c) => None,
         }
     }
 
@@ -161,8 +160,7 @@ impl<'src> VNode<'src> {
             VNode::Text(el) => el.dom_id.get(),
             VNode::Element(el) => el.dom_id.get(),
             VNode::Placeholder(el) => el.dom_id.get(),
-
-            VNode::Linked(_) => None,
+            VNode::Portal(_) => None,
             VNode::Fragment(_) => None,
             VNode::Component(_) => None,
         }
@@ -171,7 +169,6 @@ impl<'src> VNode<'src> {
     pub(crate) fn children(&self) -> &[VNode<'src>] {
         match &self {
             VNode::Fragment(f) => f.children,
-            VNode::Component(_c) => todo!("children are not accessible through this"),
             _ => &[],
         }
     }
@@ -187,7 +184,7 @@ impl<'src> VNode<'src> {
                 children: f.children,
                 key: f.key,
             }),
-            VNode::Linked(c) => VNode::Linked(NodeLink {
+            VNode::Portal(c) => VNode::Portal(VPortal {
                 scope_id: c.scope_id.clone(),
                 link_idx: c.link_idx.clone(),
                 node: c.node,
@@ -204,15 +201,13 @@ impl Debug for VNode<'_> {
                 .field("name", &el.tag_name)
                 .field("key", &el.key)
                 .finish(),
-
             VNode::Text(t) => write!(s, "VNode::VText {{ text: {} }}", t.text),
             VNode::Placeholder(_) => write!(s, "VNode::VAnchor"),
-
             VNode::Fragment(frag) => {
                 write!(s, "VNode::VFragment {{ children: {:?} }}", frag.children)
             }
             VNode::Component(comp) => write!(s, "VNode::VComponent {{ fc: {:?}}}", comp.user_fc),
-            VNode::Linked(c) => write!(s, "VNode::VCached {{ scope_id: {:?} }}", c.scope_id.get()),
+            VNode::Portal(c) => write!(s, "VNode::VCached {{ scope_id: {:?} }}", c.scope_id.get()),
         }
     }
 }
@@ -348,6 +343,32 @@ pub struct Listener<'bump> {
         RefCell<Option<BumpBox<'bump, dyn FnMut(std::sync::Arc<dyn Any + Send + Sync>) + 'bump>>>,
 }
 
+/// A cached node is a "pointer" to a "rendered" node in a particular scope
+///
+/// It does not provide direct access to the node, so it doesn't carry any lifetime information with it
+///
+/// It is used during the diffing/rendering process as a runtime key into an existing set of nodes. The "render" key
+/// is essentially a unique key to guarantee safe usage of the Node.
+///
+/// Linked VNodes can only be made through the [`Context::render`] method
+///
+/// Typically, NodeLinks are found *not* in a VNode. When NodeLinks are in a VNode, the NodeLink was passed into
+/// an `rsx!` call.
+///
+/// todo: remove the raw pointer and use runtime checks instead
+#[derive(Debug)]
+pub struct VPortal {
+    pub(crate) link_idx: Cell<usize>,
+    pub(crate) scope_id: Cell<Option<ScopeId>>,
+    pub(crate) node: *const VNode<'static>,
+}
+
+impl PartialEq for VPortal {
+    fn eq(&self, other: &Self) -> bool {
+        self.node == other.node
+    }
+}
+
 /// Virtual Components for custom user-defined components
 /// Only supports the functional syntax
 pub struct VComponent<'src> {
@@ -366,45 +387,14 @@ pub struct VComponent<'src> {
     pub(crate) bump_props: *const (),
 
     // during the "teardown" process we'll take the caller out so it can be dropped properly
-    // pub(crate) caller: Option<VCompCaller<'src>>,
     pub(crate) caller: &'src dyn Fn(&'src Scope) -> Element,
 
     pub(crate) comparator: Option<&'src dyn Fn(&VComponent) -> bool>,
 
+    // todo: re-add this
     pub(crate) drop_props: RefCell<Option<BumpBox<'src, dyn FnMut()>>>,
 }
 
-pub struct VSuspended {
-    pub task_id: usize,
-    pub scope: Cell<Option<ScopeId>>,
-    pub dom_id: Cell<Option<ElementId>>,
-    pub parent: Cell<Option<ElementId>>,
-}
-
-/// A cached node is a "pointer" to a "rendered" node in a particular scope
-///
-/// It does not provide direct access to the node, so it doesn't carry any lifetime information with it
-///
-/// It is used during the diffing/rendering process as a runtime key into an existing set of nodes. The "render" key
-/// is essentially a unique key to guarantee safe usage of the Node.
-///
-/// Linked VNodes can only be made through the [`Context::render`] method
-///
-/// Typically, NodeLinks are found *not* in a VNode. When NodeLinks are in a VNode, the NodeLink was passed into
-/// an `rsx!` call.
-#[derive(Debug)]
-pub struct NodeLink {
-    pub(crate) link_idx: Cell<usize>,
-    pub(crate) scope_id: Cell<Option<ScopeId>>,
-    pub(crate) node: *const VNode<'static>,
-}
-
-impl PartialEq for NodeLink {
-    fn eq(&self, other: &Self) -> bool {
-        self.node == other.node
-    }
-}
-
 /// This struct provides an ergonomic API to quickly build VNodes.
 ///
 /// NodeFactory is used to build VNodes in the component's memory space.
@@ -624,8 +614,8 @@ impl<'a> NodeFactory<'a> {
         callback: BumpBox<'a, dyn FnMut(Arc<dyn Any + Send + Sync>) + 'a>,
     ) -> Listener<'a> {
         Listener {
-            mounted_node: Cell::new(None),
             event,
+            mounted_node: Cell::new(None),
             callback: RefCell::new(Some(callback)),
         }
     }
@@ -634,15 +624,14 @@ impl<'a> NodeFactory<'a> {
         self,
         node_iter: impl IntoIterator<Item = impl IntoVNode<'a> + 'c> + 'b,
     ) -> VNode<'a> {
-        let bump = self.bump;
-        let mut nodes = bumpalo::collections::Vec::new_in(bump);
+        let mut nodes = bumpalo::collections::Vec::new_in(self.bump);
 
         for node in node_iter {
             nodes.push(node.into_vnode(self));
         }
 
         if nodes.is_empty() {
-            nodes.push(VNode::Placeholder(bump.alloc(VPlaceholder {
+            nodes.push(VNode::Placeholder(self.bump.alloc(VPlaceholder {
                 dom_id: empty_cell(),
             })));
         }
@@ -657,26 +646,23 @@ impl<'a> NodeFactory<'a> {
         self,
         node_iter: impl IntoIterator<Item = impl IntoVNode<'a> + 'c> + 'b,
     ) -> VNode<'a> {
-        let bump = self.bump;
-        let mut nodes = bumpalo::collections::Vec::new_in(bump);
+        let mut nodes = bumpalo::collections::Vec::new_in(self.bump);
 
         for node in node_iter {
             nodes.push(node.into_vnode(self));
         }
 
         if nodes.is_empty() {
-            nodes.push(VNode::Placeholder(bump.alloc(VPlaceholder {
+            nodes.push(VNode::Placeholder(self.bump.alloc(VPlaceholder {
                 dom_id: empty_cell(),
             })));
         }
 
         let children = nodes.into_bump_slice();
 
-        // todo: add a backtrace
         if cfg!(debug_assertions) && children.len() > 1 && children.last().unwrap().key().is_none()
         {
-            use backtrace::Backtrace;
-            let bt = Backtrace::new();
+            // todo: make the backtrace prettier or remove it altogether
             log::error!(
                 r#"
                 Warning: Each child in an array or iterator should have a unique "key" prop.
@@ -685,7 +671,7 @@ impl<'a> NodeFactory<'a> {
                 -------------
                 {:?}
                 "#,
-                bt
+                backtrace::Backtrace::new()
             );
         }
 
@@ -740,7 +726,7 @@ impl<'a> NodeFactory<'a> {
             key: None,
         });
         let ptr = self.bump.alloc(frag) as *const _;
-        Some(NodeLink {
+        Some(VPortal {
             link_idx: Default::default(),
             scope_id: Default::default(),
             node: unsafe { std::mem::transmute(ptr) },
@@ -847,10 +833,10 @@ impl IntoVNode<'_> for Arguments<'_> {
 }
 
 // called cx.render from a helper function
-impl IntoVNode<'_> for Option<NodeLink> {
+impl IntoVNode<'_> for Option<VPortal> {
     fn into_vnode(self, _cx: NodeFactory) -> VNode {
         match self {
-            Some(node) => VNode::Linked(node),
+            Some(node) => VNode::Portal(node),
             None => {
                 todo!()
             }
@@ -860,10 +846,10 @@ impl IntoVNode<'_> for Option<NodeLink> {
 
 // essentially passing elements through props
 // just build a new element in place
-impl IntoVNode<'_> for &Option<NodeLink> {
+impl IntoVNode<'_> for &Option<VPortal> {
     fn into_vnode(self, _cx: NodeFactory) -> VNode {
         match self {
-            Some(node) => VNode::Linked(NodeLink {
+            Some(node) => VNode::Portal(VPortal {
                 link_idx: node.link_idx.clone(),
                 scope_id: node.scope_id.clone(),
                 node: node.node,
@@ -876,15 +862,15 @@ impl IntoVNode<'_> for &Option<NodeLink> {
     }
 }
 
-impl IntoVNode<'_> for NodeLink {
+impl IntoVNode<'_> for VPortal {
     fn into_vnode(self, _cx: NodeFactory) -> VNode {
-        VNode::Linked(self)
+        VNode::Portal(self)
     }
 }
 
-impl IntoVNode<'_> for &NodeLink {
+impl IntoVNode<'_> for &VPortal {
     fn into_vnode(self, _cx: NodeFactory) -> VNode {
-        VNode::Linked(NodeLink {
+        VNode::Portal(VPortal {
             link_idx: self.link_idx.clone(),
             scope_id: self.scope_id.clone(),
             node: self.node,

+ 44 - 103
packages/core/src/scope.rs

@@ -43,6 +43,7 @@ pub type Context<'a> = &'a Scope;
 /// use case they might have.
 pub struct Scope {
     pub(crate) parent_scope: Option<*mut Scope>,
+
     pub(crate) container: ElementId,
 
     pub(crate) our_arena_idx: ScopeId,
@@ -61,7 +62,9 @@ pub struct Scope {
 
     pub(crate) items: RefCell<SelfReferentialItems<'static>>,
 
-    pub(crate) hooks: HookList,
+    pub(crate) hook_arena: Bump,
+    pub(crate) hook_vals: RefCell<SmallVec<[*mut dyn Any; 5]>>,
+    pub(crate) hook_idx: Cell<usize>,
 
     pub(crate) shared_contexts: RefCell<HashMap<TypeId, Rc<dyn Any>>>,
 
@@ -100,7 +103,9 @@ impl Scope {
     ///
     /// assert_eq!(base.subtree(), 0);
     /// ```
-    pub fn subtree(&self) -> u32 {
+    ///
+    /// todo: enable
+    pub(crate) fn _subtree(&self) -> u32 {
         self.subtree.get()
     }
 
@@ -119,14 +124,13 @@ impl Scope {
     ///     rsx!(cx, div { "Subtree {id}"})
     /// };
     /// ```
-    pub fn create_subtree(&self) -> Option<u32> {
+    ///
+    /// todo: enable subtree
+    pub(crate) fn _create_subtree(&self) -> Option<u32> {
         if self.is_subtree_root.get() {
             None
         } else {
             todo!()
-            // let cur = self.subtree().get();
-            // self.shared.cur_subtree.set(cur + 1);
-            // Some(cur)
         }
     }
 
@@ -165,6 +169,7 @@ impl Scope {
     /// assert_eq!(base.parent(), None);
     /// ```
     pub fn parent(&self) -> Option<ScopeId> {
+        // safety: the pointer to our parent is *always* valid thanks to the bump arena
         self.parent_scope.map(|p| unsafe { &*p }.our_arena_idx)
     }
 
@@ -189,11 +194,8 @@ impl Scope {
     ///
     /// ## Notice: you should prefer using prepare_update and get_scope_id
     pub fn schedule_update(&self) -> Rc<dyn Fn() + 'static> {
-        // pub fn schedule_update(&self) -> Rc<dyn Fn() + 'static> {
-        let chan = self.sender.clone();
-        let id = self.scope_id();
+        let (chan, id) = (self.sender.clone(), self.scope_id());
         Rc::new(move || {
-            // log::debug!("set on channel an update for scope {:?}", id);
             let _ = chan.unbounded_send(SchedulerMsg::Immediate(id));
         })
     }
@@ -281,7 +283,11 @@ impl Scope {
         }
     }
 
-    /// Pushes the future onto the poll queue to be polled
+    /// Pushes the future onto the poll queue to be polled after the component renders.
+    ///
+    ///
+    ///
+    ///
     /// The future is forcibly dropped if the component is not ready by the next render
     pub fn push_task<'src, F: Future<Output = ()>>(
         &'src self,
@@ -292,7 +298,7 @@ impl Scope {
         F: 'src,
     {
         self.sender
-            .unbounded_send(SchedulerMsg::TaskPushed(self.our_arena_idx))
+            .unbounded_send(SchedulerMsg::NewTask(self.our_arena_idx))
             .unwrap();
 
         // allocate the future
@@ -326,7 +332,7 @@ impl Scope {
     ///     cx.render(lazy_tree)
     /// }
     ///```
-    pub fn render<'src>(&'src self, rsx: Option<LazyNodes<'src, '_>>) -> Option<NodeLink> {
+    pub fn render<'src>(&'src self, rsx: Option<LazyNodes<'src, '_>>) -> Option<VPortal> {
         let frame = self.wip_frame();
         let bump = &frame.bump;
         let factory = NodeFactory { bump };
@@ -336,7 +342,7 @@ impl Scope {
         let node_ptr = node as *mut _;
         let node_ptr = unsafe { std::mem::transmute(node_ptr) };
 
-        let link = NodeLink {
+        let link = VPortal {
             scope_id: Cell::new(Some(self.our_arena_idx)),
             link_idx: Cell::new(0),
             node: node_ptr,
@@ -371,24 +377,35 @@ impl Scope {
         initializer: impl FnOnce(usize) -> State,
         runner: impl FnOnce(&'src mut State) -> Output,
     ) -> Output {
-        if self.hooks.at_end() {
-            self.hooks.push_hook(initializer(self.hooks.len()));
+        let mut vals = self.hook_vals.borrow_mut();
+        let hook_len = vals.len();
+        let cur_idx = self.hook_idx.get();
+
+        if cur_idx >= hook_len {
+            let val = self.hook_arena.alloc(initializer(hook_len));
+            vals.push(val);
         }
 
-        const HOOK_ERR_MSG: &str = r###"
-Unable to retrieve the hook that was initialized at this index.
-Consult the `rules of hooks` to understand how to use hooks properly.
+        let state = vals
+            .get(cur_idx)
+            .and_then(|inn| {
+                self.hook_idx.set(cur_idx + 1);
+                let raw_box = unsafe { &mut **inn };
+                raw_box.downcast_mut::<State>()
+            })
+            .expect(
+                r###"
+                Unable to retrieve the hook that was initialized at this index.
+                Consult the `rules of hooks` to understand how to use hooks properly.
 
-You likely used the hook in a conditional. Hooks rely on consistent ordering between renders.
-Functions prefixed with "use" should never be called conditionally.
-"###;
+                You likely used the hook in a conditional. Hooks rely on consistent ordering between renders.
+                Functions prefixed with "use" should never be called conditionally.
+                "###,
+            );
 
-        runner(self.hooks.next::<State>().expect(HOOK_ERR_MSG))
+        runner(state)
     }
-}
 
-// Important internal methods
-impl Scope {
     /// The "work in progress frame" represents the frame that is currently being worked on.
     pub(crate) fn wip_frame(&self) -> &BumpFrame {
         match self.generation.get() & 1 == 0 {
@@ -449,11 +466,7 @@ impl BumpFrame {
         Self { bump, nodes }
     }
 
-    pub fn _allocated_bytes(&self) -> usize {
-        self.bump.allocated_bytes()
-    }
-
-    pub fn assign_nodelink(&self, node: &NodeLink) {
+    pub fn assign_nodelink(&self, node: &VPortal) {
         let mut nodes = self.nodes.borrow_mut();
 
         let len = nodes.len();
@@ -463,78 +476,6 @@ impl BumpFrame {
     }
 }
 
-/// An abstraction over internally stored data using a hook-based memory layout.
-///
-/// Hooks are allocated using Boxes and then our stored references are given out.
-///
-/// It's unsafe to "reset" the hooklist, but it is safe to add hooks into it.
-///
-/// Todo: this could use its very own bump arena, but that might be a tad overkill
-#[derive(Default)]
-pub(crate) struct HookList {
-    arena: Bump,
-    vals: RefCell<SmallVec<[*mut dyn Any; 5]>>,
-    idx: Cell<usize>,
-}
-
-impl HookList {
-    pub fn new(capacity: usize) -> Self {
-        Self {
-            arena: Bump::with_capacity(capacity),
-            ..Default::default()
-        }
-    }
-
-    pub(crate) fn next<T: 'static>(&self) -> Option<&mut T> {
-        self.vals.borrow().get(self.idx.get()).and_then(|inn| {
-            self.idx.set(self.idx.get() + 1);
-            let raw_box = unsafe { &mut **inn };
-            raw_box.downcast_mut::<T>()
-        })
-    }
-
-    /// This resets the internal iterator count
-    /// It's okay that we've given out each hook, but now we have the opportunity to give it out again
-    /// Therefore, resetting is considered unsafe
-    ///
-    /// This should only be ran by Dioxus itself before "running scope".
-    /// Dioxus knows how to descend through the tree to prevent mutable aliasing.
-    pub(crate) unsafe fn reset(&self) {
-        self.idx.set(0);
-    }
-
-    pub(crate) fn push_hook<T: 'static>(&self, new: T) {
-        let val = self.arena.alloc(new);
-        self.vals.borrow_mut().push(val)
-    }
-
-    pub(crate) fn len(&self) -> usize {
-        self.vals.borrow().len()
-    }
-
-    pub(crate) fn cur_idx(&self) -> usize {
-        self.idx.get()
-    }
-
-    pub(crate) fn at_end(&self) -> bool {
-        self.cur_idx() >= self.len()
-    }
-
-    pub fn clear(&mut self) {
-        self.vals.borrow_mut().drain(..).for_each(|state| {
-            let as_mut = unsafe { &mut *state };
-            let boxed = unsafe { bumpalo::boxed::Box::from_raw(as_mut) };
-            drop(boxed);
-        });
-    }
-
-    /// Get the ammount of memory a hooklist uses
-    /// Used in heuristics
-    pub fn _get_hook_arena_size(&self) -> usize {
-        self.arena.allocated_bytes()
-    }
-}
-
 #[test]
 fn sizeof() {
     dbg!(std::mem::size_of::<Scope>());

+ 19 - 3
packages/core/src/scopearena.rs

@@ -180,7 +180,6 @@ impl ScopeArena {
                 caller,
                 generation: 0.into(),
 
-                hooks: HookList::new(hook_capacity),
                 shared_contexts: Default::default(),
 
                 items: RefCell::new(SelfReferentialItems {
@@ -188,6 +187,10 @@ impl ScopeArena {
                     borrowed_props: Default::default(),
                     tasks: Default::default(),
                 }),
+
+                hook_arena: Bump::new(),
+                hook_vals: RefCell::new(smallvec::SmallVec::with_capacity(hook_capacity)),
+                hook_idx: Default::default(),
             });
 
             let any_item = self.scopes.borrow_mut().insert(new_scope_id, scope);
@@ -208,7 +211,14 @@ impl ScopeArena {
         let scope = unsafe { &mut *self.scopes.borrow_mut().remove(id).unwrap() };
 
         // we're just reusing scopes so we need to clear it out
-        scope.hooks.clear();
+        scope.hook_vals.get_mut().drain(..).for_each(|state| {
+            let as_mut = unsafe { &mut *state };
+            let boxed = unsafe { bumpalo::boxed::Box::from_raw(as_mut) };
+            drop(boxed);
+        });
+        scope.hook_idx.set(0);
+        scope.hook_arena.reset();
+
         scope.shared_contexts.get_mut().clear();
         scope.parent_scope = None;
         scope.generation.set(0);
@@ -310,7 +320,13 @@ impl ScopeArena {
         // Safety:
         // - We dropped the listeners, so no more &mut T can be used while these are held
         // - All children nodes that rely on &mut T are replaced with a new reference
-        unsafe { scope.hooks.reset() };
+        scope.hook_vals.get_mut().drain(..).for_each(|state| {
+            let as_mut = unsafe { &mut *state };
+            let boxed = unsafe { bumpalo::boxed::Box::from_raw(as_mut) };
+            drop(boxed);
+        });
+        scope.hook_idx.set(0);
+        scope.hook_arena.reset();
 
         // Safety:
         // - We've dropped all references to the wip bump frame with "ensure_drop_safety"

+ 5 - 8
packages/core/src/virtual_dom.rs

@@ -8,10 +8,7 @@ use futures_util::{Future, StreamExt};
 use fxhash::FxHashSet;
 use indexmap::IndexSet;
 use smallvec::SmallVec;
-use std::pin::Pin;
-use std::sync::Arc;
-use std::task::Poll;
-use std::{any::Any, collections::VecDeque};
+use std::{any::Any, collections::VecDeque, pin::Pin, sync::Arc, task::Poll};
 
 /// A virtual node system that progresses user events and diffs UI trees.
 ///
@@ -286,7 +283,7 @@ impl VirtualDom {
             if let Some(msg) = self.pending_messages.pop_back() {
                 match msg {
                     // just keep looping, the task is now saved but we should actually poll it
-                    SchedulerMsg::TaskPushed(id) => {
+                    SchedulerMsg::NewTask(id) => {
                         self.scopes.pending_futures.borrow_mut().insert(id);
                     }
                     SchedulerMsg::UiEvent(event) => {
@@ -546,7 +543,7 @@ pub enum SchedulerMsg {
     Immediate(ScopeId),
 
     // an async task pushed from an event handler (or just spawned)
-    TaskPushed(ScopeId),
+    NewTask(ScopeId),
 }
 
 /// User Events are events that are shuttled from the renderer into the VirtualDom trhough the scheduler channel.
@@ -675,9 +672,9 @@ impl<'a> Future for PollTasks<'a> {
                 // I think the futures neeed to be pinned using bumpbox or something
                 // right now, they're bump allocated so this shouldn't matter anyway - they're not going to move
                 let task_mut = task.as_mut();
-                let unpinned = unsafe { Pin::new_unchecked(task_mut) };
+                let pinned = unsafe { Pin::new_unchecked(task_mut) };
 
-                if unpinned.poll(cx).is_ready() {
+                if pinned.poll(cx).is_ready() {
                     all_pending = false
                 } else {
                     unfinished_tasks.push(task);

+ 1 - 1
packages/core/tests/diffing.rs

@@ -5,7 +5,7 @@
 //!
 //! It does not validated that component lifecycles work properly. This is done in another test file.
 
-use dioxus::{prelude::*, DomEdit, VSuspended};
+use dioxus::{prelude::*, DomEdit};
 use dioxus_core as dioxus;
 use dioxus_core_macro::*;
 use dioxus_html as dioxus_elements;

+ 1 - 1
packages/ssr/src/lib.rs

@@ -158,7 +158,7 @@ impl<'a> TextRenderer<'a, '_> {
                 }
                 write!(f, "<!-- -->")?;
             }
-            VNode::Linked(link) => {
+            VNode::Portal(link) => {
                 todo!();
             }
             VNode::Element(el) => {