inline-css-macros 0.0.2

Macros for the inline-css crate
Documentation
// Copyright (C) 2023 Benjamin Stürz
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
use crate::*;
use quote::quote;
use proc_macro2::TokenStream;

impl ToTokens for CSS {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let rules = &self.0;
        let s = quote! {
            inline_css::CSS(vec![#(#rules),*])
        };
        tokens.extend(s)
    }
}

impl ToTokens for Rule {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let selector = &self.selector;
        let declarations = &self.declarations.0;
        let s = quote! {
            inline_css::Rule {
                selector: #selector,
                declarations: vec![#(#declarations),*],
            }
        };
        tokens.extend(s)
    }
}

impl ToTokens for Selector {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let s = match self {
            Self::Any(_) => quote! { inline_css::Selector::Any },
            Self::Simple { ident, class, id } => {
                let ident = ident.as_ref().map_or(
                    quote! { None },
                    |i| quote! { Some(#i) },
                );
                let class = class.as_ref().map_or(
                    quote! { None },
                    |(_, i)| quote! { Some(#i) },
                );
                let id = id.as_ref().map_or(
                    quote! { None },
                    |(_, i)| quote! { Some(#i) },
                );
                quote! {
                    inline_css::Selector::Simple {
                        ty: #ident,
                        class: #class,
                        id: #id,
                    }
                }
            },
            Self::Colon { ident, arg, .. } => {
                let arg = if let Some((_, arg)) = arg {
                    quote! { Some(#arg) }
                } else {
                    quote! { None }
                };
                quote! {
                    inline_css::Selector::Colon {
                        name: #ident,
                        arg: #arg,
                    }
                }
            },
            Self::Sub { left, right } => {
                quote! {
                    inline_css::Selector::Sub {
                        left: Box::new(#left),
                        right: Box::new(#right),
                    }
                }
            },
            Self::Gt { left, right, .. } => {
                quote! {
                    inline_css::Selector::Gt {
                        left: Box::new(#left),
                        right: Box::new(#right),
                    }
                }
            },
            Self::Plus { left, right, .. } => {
                quote! {
                    inline_css::Selector::Plus {
                        left: Box::new(#left),
                        right: Box::new(#right),
                    }
                }
            },
            Self::Tilde { left, right, .. } => {
                quote! {
                    inline_css::Selector::Tilde {
                        left: Box::new(#left),
                        right: Box::new(#right),
                    }
                }
            },
            Self::Comma { left, right, .. } => {
                quote! {
                    inline_css::Selector::Comma {
                        left: Box::new(#left),
                        right: Box::new(#right),
                    }
                }
            },
        };
        tokens.extend(s)
    }
}

impl ToTokens for Declaration {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let ident = &self.ident;
        let value = &self.value;
        let s = quote! {
            inline_css::Declaration {
                name: #ident,
                value: vec![#(#value),*],
            }
        };
        tokens.extend(s)
    }
}

impl ToTokens for Value {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let s = match self {
            Self::ColorCode { value, .. } => quote! { inline_css::Value::ColorCode(#value) },
            Self::Ident(name) => quote! { inline_css::Value::Ident(#name) },
            Self::Int(i) => {
                let value: i32 = i.base10_parse().unwrap_or_else(|e| {
                    panic!("Failed to parse {i}: {e}")
                });
                let suffix = match i.suffix() {
                    "m" => "em",
                    sfx => sfx,
                };
                quote! {
                    inline_css::Value::Int(#value, #suffix.to_string())
                }
            },
            Self::Float(f) => {
                let value: f32 = f.base10_parse().unwrap();
                let suffix = match f.suffix() {
                    "m" => "em",
                    sfx => sfx,
                };
                quote! {
                    inline_css::Value::Float(#value, #suffix.to_string())
                }
            },
            Self::IntPerc(i, _) => quote! { inline_css::Value::Int(#i, "%".to_string()) },
            Self::FloatPerc(f, _) => quote! { inline_css::Value::Float(#f, "%".to_string()) },
            Self::Function { ident, args, .. } => {
                let args = args.0.iter();
                quote! {
                    inline_css::Value::Function {
                        name: #ident,
                        args: vec![#(#args),*],
                    }
                }
            },
            Self::Block(b) => {
                quote! {
                    #[allow(unused_braces)]
                    Into::<inline_css::Value>::into(#b)
                }
            },
        };
        tokens.extend(s)
    }
}

impl ToTokens for CSSIdent {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let mut s = String::new();
        for seg in &self.0 {
            match seg {
                CSSIdentSegment::Ident(i) => s.push_str(&i.to_string()),
                CSSIdentSegment::Minus(_) => s.push('-'),
            }
        }
        let s = quote! { #s.to_string() };
        tokens.extend(s)
    }
}