alef 0.110.4

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

pub(super) fn literal(field: &FieldDef) -> Option<String> {
    render(&field.ty, field.typed_default.as_ref()?)
}

fn render(ty: &TypeRef, value: &DefaultValue) -> Option<String> {
    if let TypeRef::Optional(inner) = ty
        && !matches!(value, DefaultValue::None | DefaultValue::Empty)
    {
        return render(inner, value);
    }
    match value {
        DefaultValue::BoolLiteral(value) => Some(value.to_string()),
        DefaultValue::StringLiteral(value) => Some(
            serde_json::to_string(value)
                .ok()?
                .replace('$', "\\$")
                .replace('~', "\\u007e"),
        ),
        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) => Some(format!(
            "{}.{}",
            match ty {
                TypeRef::Named(name) => name.as_str(),
                _ => return None,
            },
            dart_value_identifier(&pascal_to_camel(variant))
        )),
        DefaultValue::ListLiteral(items) => {
            let TypeRef::Vec(element) = ty else { return None };
            let values = items
                .iter()
                .map(|item| render(element, item))
                .collect::<Option<Vec<_>>>()?;
            Some(format!("const [{}]", 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 => "const []",
                TypeRef::Map(_, _) => "const {}",
                TypeRef::Optional(_) => "null",
                _ => return None,
            }
            .into(),
        ),
        _ => None,
    }
}

pub(super) fn frb_literal(field: &FieldDef) -> Option<String> {
    match field.typed_default.as_ref()? {
        DefaultValue::BoolLiteral(value) => Some(value.to_string()),
        DefaultValue::Empty if field.ty == TypeRef::Primitive(PrimitiveType::Bool) => Some("false".into()),
        _ => None,
    }
}

pub(super) fn validate(api: &crate::core::ir::ApiSurface) -> anyhow::Result<()> {
    for owner in &api.types {
        for field in crate::codegen::shared::binding_fields(&owner.fields) {
            if owner.is_constructor_extension(field) {
                anyhow::ensure!(
                    literal(field).is_some(),
                    "Dart cannot render constructor default for {}.{} ({:?})",
                    owner.name,
                    field.name,
                    field.ty
                );
            }
        }
    }
    Ok(())
}