mplusfonts-macros 0.3.4

Procedural macros re-exported in the mplusfonts crate
Documentation
use proc_macro2::TokenStream;
use quote::{ToTokens, quote};
use swash::GlyphId;

use crate::mplus::bitmap::ImageList;

pub struct Glyph {
    pub x_offset: f32,
    pub y_offset: f32,
    pub positions: u8,
    pub bit_depth: u8,
    pub id: GlyphId,
    pub advance_width: f32,
    pub images: ImageList,
}

pub struct GlyphList(pub Vec<Glyph>);

impl ToTokens for GlyphList {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let Self(vec) = self;
        let mut previous_glyph = None;
        for glyph in vec.iter().rev() {
            let Glyph {
                x_offset,
                y_offset,
                positions,
                bit_depth,
                id,
                advance_width: _,
                images,
            } = glyph;

            let next_glyph = match previous_glyph.take() {
                Some((x_offset, y_offset, glyph)) => {
                    let value = next_glyph(x_offset, y_offset, *positions, *bit_depth, glyph);

                    quote!(Some(#value))
                }
                None => quote!(None),
            };
            let glyph = quote! {
                ::mplusfonts::glyph::Glyph {
                    id: #id,
                    images: #images,
                    next: #next_glyph,
                }
            };

            let glyph = previous_glyph.replace((*x_offset, *y_offset, glyph));
            debug_assert!(glyph.is_none(), "expected token stream to be taken");
        }

        let glyph = match previous_glyph {
            Some((x_offset, y_offset, glyph)) => {
                debug_assert_eq!(0.0, x_offset, "expected glyph with no horizontal offset",);
                debug_assert_eq!(0.0, y_offset, "expected glyph with no vertical offset",);

                glyph
            }
            None => quote! {
                ::mplusfonts::glyph::Glyph::NULL
            },
        };

        tokens.extend(glyph);
    }
}

fn next_glyph(
    x_offset: f32,
    y_offset: f32,
    positions: u8,
    bit_depth: u8,
    glyph: impl ToTokens,
) -> impl ToTokens {
    let positions = positions as usize;
    let params = match bit_depth {
        1 => quote!(::embedded_graphics::pixelcolor::BinaryColor, #positions),
        2 => quote!(::embedded_graphics::pixelcolor::Gray2, #positions),
        4 => quote!(::embedded_graphics::pixelcolor::Gray4, #positions),
        8 => quote!(::embedded_graphics::pixelcolor::Gray8, #positions),
        x => panic!("expected one of: `1`, `2`, `4`, `8`; found: `{x}`"),
    };
    let next_glyph = quote! {
        ::mplusfonts::glyph::NextGlyph {
            x_offset: #x_offset,
            y_offset: #y_offset,
            glyph: #glyph,
        }
    };
    let value = quote!(const {
        const DATA: ::mplusfonts::glyph::NextGlyph<#params> = #next_glyph;

        &DATA
    });

    value
}