flutter_rust_bridge_codegen 2.0.0-dev.0

High-level memory-safe binding generator for Flutter/Dart <-> Rust
Documentation
use crate::codegen::generator::acc::Acc;
use crate::codegen::generator::codec::sse::lang::Lang;
use crate::codegen::generator::misc::target::{TargetOrCommon, TargetOrCommonMap};
use crate::codegen::ir::field::IrField;
use crate::codegen::ir::ty::boxed::IrTypeBoxed;
use crate::codegen::ir::ty::IrType;
use crate::utils::file_utils::create_dir_all_and_write;
use itertools::Itertools;
use std::ops::Add;
use std::path::PathBuf;
use strum::IntoEnumIterator;

pub(crate) mod structs_macro;
pub(crate) mod target;
pub(crate) mod text_generator_utils;

/// In WASM, these types belong to the JS scope-local heap, **NOT** the Rust heap and
/// therefore do not implement [Send]. More specifically, these are types wasm-bindgen
/// can't handle yet.
pub fn is_js_value(ty: &IrType) -> bool {
    match ty {
        IrType::GeneralList(_)
        | IrType::StructRef(_)
        | IrType::EnumRef(_)
        | IrType::RustAutoOpaque(_)
        | IrType::RustOpaque(_)
        | IrType::DartOpaque(_)
        | IrType::DartFn(_)
        | IrType::Record(_) => true,
        IrType::Boxed(IrTypeBoxed { inner, .. }) => is_js_value(inner),
        IrType::Delegate(inner) => is_js_value(&inner.get_delegate()),
        IrType::Optional(inner) => is_js_value(&inner.inner),
        IrType::Primitive(_) | IrType::PrimitiveList(_) => false,
        IrType::Dynamic(_) | IrType::Ownership(_) | IrType::Unencodable(_) => unreachable!(),
    }
}

#[derive(Clone)]
pub(crate) struct PathText {
    pub path: PathBuf,
    pub text: String,
}

impl PathText {
    pub(crate) fn new(path: PathBuf, text: String) -> Self {
        Self { path, text }
    }
}

#[derive(Clone)]
pub(crate) struct PathTexts(pub Vec<PathText>);

impl Add for PathTexts {
    type Output = Self;

    fn add(self, rhs: Self) -> Self::Output {
        Self([self.0, rhs.0].concat())
    }
}

impl PathTexts {
    pub(crate) fn new_from_targets(
        path: &TargetOrCommonMap<PathBuf>,
        text: &Acc<Option<String>>,
    ) -> Self {
        Self(
            TargetOrCommon::iter()
                .filter_map(|target| {
                    text[target]
                        .clone()
                        .map(|text_for_target| PathText::new(path[target].clone(), text_for_target))
                })
                .collect_vec(),
        )
    }

    pub(crate) fn write_to_disk(&self) -> anyhow::Result<()> {
        for item in self.0.iter() {
            create_dir_all_and_write(&item.path, &item.text)?;
        }
        Ok(())
    }

    pub(crate) fn paths(&self) -> Vec<PathBuf> {
        self.0.iter().map(|item| item.path.clone()).collect_vec()
    }
}

pub(crate) fn generate_code_header() -> String {
    format!(
        "// This file is automatically generated, so please do not edit it.
// Generated by `flutter_rust_bridge`@ {}.",
        env!("CARGO_PKG_VERSION")
    )
}

pub(crate) enum StructOrRecord {
    Struct,
    Record,
}

impl StructOrRecord {
    pub(crate) fn field_name(
        &self,
        index: usize,
        field: &IrField,
        is_field_named: bool,
        lang: &Lang,
    ) -> String {
        match lang {
            Lang::DartLang(_) => match self {
                StructOrRecord::Struct => field.name.dart_style(),
                StructOrRecord::Record => format!("${}", index + 1),
            },
            Lang::RustLang(_) => match self {
                StructOrRecord::Struct => {
                    if is_field_named {
                        field.name.rust_style().to_owned()
                    } else {
                        format!("{}", index)
                    }
                }
                StructOrRecord::Record => format!("{}", index),
            },
        }
    }
}