flapigen 0.11.0

Tool for connecting libraries written in Rust with other languages
Documentation
use bitflags::bitflags;

use super::{JniForeignMethodSignature, NullAnnotation};
use crate::WRITE_TO_MEM_FAILED_MSG;

bitflags! {
    pub(in crate::java_jni) struct ArgsFormatFlags: u8 {
        const NONE = 0;
        const USE_COMMA_IF_NEED = 1;
        const EXTERNAL = 2;
        const INTERNAL = 4;
        const COMMA_BEFORE = 8;
    }
}

pub(in crate::java_jni) fn args_with_java_types<'a, NI: Iterator<Item = &'a str>>(
    method: &JniForeignMethodSignature,
    arg_name_iter: NI,
    flags: ArgsFormatFlags,
    use_null_annotation: bool,
) -> String {
    use std::fmt::Write;

    assert!(flags.contains(ArgsFormatFlags::INTERNAL) || flags.contains(ArgsFormatFlags::EXTERNAL));

    let mut res = String::new();
    if flags.contains(ArgsFormatFlags::USE_COMMA_IF_NEED) && !method.input.is_empty() {
        res.push_str(", ");
    }
    let external = flags.contains(ArgsFormatFlags::EXTERNAL);

    for (i, (arg, arg_name)) in method.input.iter().zip(arg_name_iter).enumerate() {
        let type_name = match arg.java_converter.as_ref() {
            Some(converter) if flags.contains(ArgsFormatFlags::INTERNAL) => {
                converter.java_transition_type.display()
            }
            _ => arg.as_ref().name.display(),
        };
        let type_arlready_null_anotated =
            type_name.contains("@NonNull") || type_name.contains("@Nullable");
        let annotation = match arg.annotation {
            Some(NullAnnotation::NonNull)
                if external && use_null_annotation && !type_arlready_null_anotated =>
            {
                "@NonNull "
            }
            Some(NullAnnotation::Nullable)
                if external && use_null_annotation && !type_arlready_null_anotated =>
            {
                "@Nullable "
            }
            _ => "",
        };
        if i == (method.input.len() - 1) {
            write!(res, "{annotation}{type_name} {arg_name}")
        } else {
            write!(res, "{annotation}{type_name} {arg_name}, ")
        }
        .expect(WRITE_TO_MEM_FAILED_MSG);
    }
    res
}

pub(in crate::java_jni) fn doc_comments_to_java_comments(
    doc_comments: &[String],
    class_comments: bool,
) -> String {
    use std::fmt::Write;
    let mut comments = String::new();
    for (i, comment) in doc_comments.iter().enumerate() {
        if i != 0 {
            comments.push('\n');
        }
        if !class_comments {
            comments.push_str("    ");
        }
        if i == 0 {
            comments.push_str("/**\n");
            if !class_comments {
                comments.push_str("    ");
            }
        }

        write!(&mut comments, " * {}", comment.trim()).unwrap();

        if i == doc_comments.len() - 1 {
            comments.push('\n');
            if !class_comments {
                comments.push_str("    ");
            }
            comments.push_str(" */");
        }
    }
    comments
}

pub(in crate::java_jni) fn get_null_annotation_imports(
    null_annotation_package: Option<&str>,
    methods_sign: &[JniForeignMethodSignature],
) -> String {
    if let Some(null_annotation_package) = null_annotation_package {
        let mut has_non_null = false;
        let mut has_nullable = false;

        for f_method in methods_sign {
            for arg in f_method
                .input
                .iter()
                .chain(std::iter::once(&f_method.output))
            {
                let mut process_null_annotation = |x: Option<NullAnnotation>| match x {
                    Some(NullAnnotation::NonNull) => has_non_null = true,
                    Some(NullAnnotation::Nullable) => has_nullable = true,
                    _ => {}
                };
                process_null_annotation(arg.annotation);
                if let Some(conv) = arg.java_converter.as_ref() {
                    process_null_annotation(conv.annotation);
                }
                if has_non_null && has_nullable {
                    return format!(
                        "import {package}.NonNull;\nimport {package}.Nullable;",
                        package = null_annotation_package
                    );
                }
            }
        }
        if has_non_null {
            return format!(
                "import {package}.NonNull;",
                package = null_annotation_package
            );
        }

        if has_nullable {
            return format!(
                "import {package}.Nullable;",
                package = null_annotation_package
            );
        }
    }

    String::new()
}

pub(in crate::java_jni) fn filter_null_annotation(type_name: &str) -> String {
    type_name.replace("@NonNull", "").replace("@Nullable", "")
}

pub(in crate::java_jni) fn is_primitive_type(type_name: &str) -> bool {
    matches!(
        type_name,
        "void" | "boolean" | "byte" | "short" | "int" | "long" | "float" | "double"
    )
}