alef 0.110.7

Opinionated polyglot binding generator for Rust libraries
Documentation
use crate::core::ir::{DefaultValue, FieldDef, PrimitiveType, TypeRef};

use super::types::zig_enum_default;

pub(super) fn literal(field: &FieldDef, enums: &[crate::core::ir::EnumDef]) -> Option<String> {
    render(&field.ty, field.typed_default.as_ref()?, enums)
}

fn render(ty: &TypeRef, value: &DefaultValue, enums: &[crate::core::ir::EnumDef]) -> Option<String> {
    if let TypeRef::Optional(inner) = ty
        && !matches!(value, DefaultValue::None | DefaultValue::Empty)
    {
        return render(inner, value, enums);
    }
    match value {
        DefaultValue::BoolLiteral(value) => Some(value.to_string()),
        DefaultValue::StringLiteral(value) => Some(format!("\"{}\"", escape_zig_string(value))),
        DefaultValue::IntLiteral(value) => Some(value.to_string()),
        DefaultValue::FloatLiteral(value) => crate::codegen::shared::float_literal_digits(*value),
        DefaultValue::None => Some("null".into()),
        DefaultValue::EnumVariant(variant) => {
            let TypeRef::Named(name) = ty else { return None };
            zig_enum_default(enums.iter().find(|en| en.name == *name)?, variant)
        }
        DefaultValue::ListLiteral(items) => {
            let TypeRef::Vec(element) = ty else { return None };
            let values = items
                .iter()
                .map(|item| render(element, item, enums))
                .collect::<Option<Vec<_>>>()?;
            Some(format!("&.{{{}}}", values.join(", ")))
        }
        DefaultValue::Empty => Some(
            match ty {
                TypeRef::Primitive(PrimitiveType::Bool) => "false",
                TypeRef::Primitive(PrimitiveType::F32 | PrimitiveType::F64) => "0.0",
                TypeRef::Primitive(_) | TypeRef::Duration => "0",
                TypeRef::String | TypeRef::Path => "\"\"",
                TypeRef::Vec(_) | TypeRef::Bytes => "&.{}",
                TypeRef::Optional(_) => "null",
                _ => return None,
            }
            .into(),
        ),
        _ => None,
    }
}

fn escape_zig_string(value: &str) -> String {
    value
        .bytes()
        .map(|byte| match byte {
            b'"' => "\\\"".into(),
            b'\\' => "\\\\".into(),
            b'\n' => "\\n".into(),
            b'\r' => "\\r".into(),
            b'\t' => "\\t".into(),
            b'~' => "\\x7e".into(),
            b' '..=b'~' => char::from(byte).to_string(),
            _ => format!("\\x{byte:02x}"),
        })
        .collect()
}