zpl-forge 0.2.1

A fast, memory-safe ZPL (Zebra Programming Language) parser and renderer.
Documentation
use nom::{
    Parser,
    bytes::complete::{tag, take_till},
    combinator::{cut, map_res},
};

use super::{Res, Span, param, parse_u32};
use crate::ast::cmd;

/// ^GIC - Custom Image Color
/// Format: ^GIC<width>,<height>,<base64>
/// All parameters are mandatory.
pub fn cmd_gic(input: Span) -> Res<cmd::Command> {
    let (input, _) = tag("^GIC").parse(input)?;

    let (input, width) = cut(parse_u32).parse(input)?;

    let (input, height) = cut(map_res(param(parse_u32), |opt| {
        opt.ok_or("height is mandatory")
    }))
    .parse(input)?;

    let (input, _) = cut(tag(",")).parse(input)?;

    let (input, data) = cut(map_res(take_till(|c| c == '^'), |s: &str| {
        let trimmed = s.trim();
        if trimmed.is_empty() {
            Err("base64 data is mandatory")
        } else {
            Ok(trimmed.to_owned())
        }
    }))
    .parse(input)?;

    Ok((
        input,
        cmd::Command::CustomImage {
            width,
            height,
            data,
        },
    ))
}

/// ^GTC - Custom Text Color
/// Format: ^GTC<hex_color>
pub fn cmd_gtc(input: Span) -> Res<cmd::Command> {
    let (input, _) = tag("^GTC").parse(input)?;
    let (input, color) = take_till(|c| c == '^').parse(input)?;

    Ok((
        input,
        cmd::Command::GraphicTextColor {
            color: color.trim().to_owned(),
        },
    ))
}

/// ^GLC - Custom Line Color
/// Format: ^GLC<hex_color>
pub fn cmd_glc(input: Span) -> Res<cmd::Command> {
    let (input, _) = tag("^GLC").parse(input)?;
    let (input, color) = take_till(|c| c == '^').parse(input)?;

    Ok((
        input,
        cmd::Command::GraphicLineColor {
            color: color.trim().to_owned(),
        },
    ))
}

/// ^IFC - If Condition
/// Format: ^IFC<variable>,<value>
pub fn cmd_ifc(input: Span) -> Res<cmd::Command> {
    let (input, _) = tag("^IFC").parse(input)?;
    let (input, variable) = cut(map_res(take_till(|c| c == ',' || c == '^'), |s: &str| {
        let trimmed = s.trim();
        if trimmed.is_empty() {
            Err("variable is mandatory")
        } else {
            Ok(trimmed.to_owned())
        }
    }))
    .parse(input)?;
    let (input, _) = cut(tag(",")).parse(input)?;
    let (input, value) = cut(map_res(
        take_till(|c| c == '^'),
        |s: &str| -> Result<String, &'static str> { Ok(s.trim().to_owned()) },
    ))
    .parse(input)?;

    Ok((input, cmd::Command::IfCondition { variable, value }))
}