<commit_before>use crate::{
    analysis::{
        function_parameters::{async_param_to_remove, CParameter},
        functions::{find_function, find_index_to_ignore, finish_function_name},
        imports::Imports,
        out_parameters::use_function_return_for_result,
        rust_type::{bounds_rust_type, rust_type, rust_type_with_scope},
    },
    consts::TYPE_PARAMETERS_START,
    env::Env,
    library::{
        Class, Concurrency, Function, Fundamental, Nullable, ParameterDirection, Type, TypeId,
    },
    traits::IntoString,
};
use std::{collections::vec_deque::VecDeque, slice::Iter};

#[derive(Clone, Eq, Debug, PartialEq)]
pub enum BoundType {
    NoWrapper,
    // lifetime
    IsA(Option<char>),
    // lifetime <- shouldn't be used but just in case...
    AsRef(Option<char>),
}

impl BoundType {
    pub fn need_isa(&self) -> bool {
        match *self {
            BoundType::IsA(_) => true,
            _ => false,
        }
    }
}

#[derive(Clone, Eq, Debug, PartialEq)]
pub struct Bound {
    pub bound_type: BoundType,
    pub parameter_name: String,
    pub alias: char,
    pub type_str: String,
    pub info_for_next_type: bool,
    pub callback_modified: bool,
}

#[derive(Clone, Debug)]
pub struct Bounds {
    unused: VecDeque<char>,
    used: Vec<Bound>,
    unused_lifetimes: VecDeque<char>,
    lifetimes: Vec<char>,
}

impl Default for Bounds {
    fn default() -> Bounds {
        Bounds {
            unused: (TYPE_PARAMETERS_START as u8..)
                .take_while(|x| *x <= b'Z')
                .map(|x| x as char)
                .collect(),
            used: Vec::new(),
            unused_lifetimes: "abcdefg".chars().collect(),
            lifetimes: Vec::new(),
        }
    }
}

#[derive(Debug, Clone)]
pub struct CallbackInfo {
    pub callback_type: String,
    pub success_parameters: String,
    pub error_parameters: String,
    pub bound_name: char,
}

impl Bounds {
    pub fn add_for_parameter(
        &mut self,
        env: &Env,
        func: &Function,
        par: &CParameter,
        r#async: bool,
        concurrency: Concurrency,
    ) -> (Option<String>, Option<CallbackInfo>) {
        let type_name = bounds_rust_type(env, par.typ);
        if (r#async && async_param_to_remove(&par.name)) || type_name.is_err() {
            return (None, None);
        }
        let mut type_string = type_name.into_string();
        let mut callback_info = None;
        let mut ret = None;
        let mut need_is_into_check = false;
        if !par.instance_parameter && par.direction != ParameterDirection::Out {
            if let Some(bound_type) = Bounds::type_for(env, par.typ, par.nullable) {
                ret = Some(Bounds::get_to_glib_extra(&bound_type));
                if r#async && par.name == "callback" {
                    let func_name = func.c_identifier.as_ref().unwrap();
                    let finish_func_name = finish_function_name(func_name);
                    if let Some(function) = find_function(env, &finish_func_name) {
                        let mut out_parameters = find_out_parameters(env, function);
                        if use_function_return_for_result(env, function.ret.typ) {
                            out_parameters
                                .insert(0, rust_type(env, function.ret.typ).into_string());
                        }
                        let parameters = format_out_parameters(&out_parameters);
                        let error_type = find_error_type(env, function);
                        type_string = format!(
                            "FnOnce(Result<{}, {}>) + Send + 'static",
                            parameters, error_type
                        );
                        let bound_name = *self.unused.front().unwrap();
                        callback_info = Some(CallbackInfo {
                            callback_type: type_string.clone(),
                            success_parameters: parameters,
                            error_parameters: error_type,
                            bound_name,
                        });
                    }
                } else if par.c_type == "GDestroyNotify" || env.library.type_(par.typ).is_function()
                {<commit_msg>Fix missing callback parameter handling<commit_after>use crate::{
    analysis::{
        function_parameters::{async_param_to_remove, CParameter},
        functions::{find_function, find_index_to_ignore, finish_function_name},
        imports::Imports,
        out_parameters::use_function_return_for_result,
        rust_type::{bounds_rust_type, rust_type, rust_type_with_scope},
    },
    consts::TYPE_PARAMETERS_START,
    env::Env,
    library::{
        Class, Concurrency, Function, Fundamental, Nullable, ParameterDirection, Type, TypeId,
    },
    traits::IntoString,
};
use std::{collections::vec_deque::VecDeque, slice::Iter};

#[derive(Clone, Eq, Debug, PartialEq)]
pub enum BoundType {
    NoWrapper,
    // lifetime
    IsA(Option<char>),
    // lifetime <- shouldn't be used but just in case...
    AsRef(Option<char>),
}

impl BoundType {
    pub fn need_isa(&self) -> bool {
        match *self {
            BoundType::IsA(_) => true,
            _ => false,
        }
    }
}

#[derive(Clone, Eq, Debug, PartialEq)]
pub struct Bound {
    pub bound_type: BoundType,
    pub parameter_name: String,
    pub alias: char,
    pub type_str: String,
    pub info_for_next_type: bool,
    pub callback_modified: bool,
}

#[derive(Clone, Debug)]
pub struct Bounds {
    unused: VecDeque<char>,
    used: Vec<Bound>,
    unused_lifetimes: VecDeque<char>,
    lifetimes: Vec<char>,
}

impl Default for Bounds {
    fn default() -> Bounds {
        Bounds {
            unused: (TYPE_PARAMETERS_START as u8..)
                .take_while(|x| *x <= b'Z')
                .map(|x| x as char)
                .collect(),
            used: Vec::new(),
            unused_lifetimes: "abcdefg".chars().collect(),
            lifetimes: Vec::new(),
        }
    }
}

#[derive(Debug, Clone)]
pub struct CallbackInfo {
    pub callback_type: String,
    pub success_parameters: String,
    pub error_parameters: String,
    pub bound_name: char,
}

impl Bounds {
    pub fn add_for_parameter(
        &mut self,
        env: &Env,
        func: &Function,
        par: &CParameter,
        r#async: bool,
        concurrency: Concurrency,
    ) -> (Option<String>, Option<CallbackInfo>) {
        let type_name = bounds_rust_type(env, par.typ);
        if (r#async && async_param_to_remove(&par.name)) || type_name.is_err() {
            return (None, None);
        }
        let mut type_string = type_name.into_string();
        let mut callback_info = None;
        let mut ret = None;
        let mut need_is_into_check = false;
        if !par.instance_parameter && par.direction != ParameterDirection::Out {
            if let Some(bound_type) = Bounds::type_for(env, par.typ, par.nullable) {
                ret = Some(Bounds::get_to_glib_extra(&bound_type));
                if r#async && (par.name == "callback" || par.name.ends_with("_callback")) {
                    let func_name = func.c_identifier.as_ref().unwrap();
                    let finish_func_name = finish_function_name(func_name);
                    if let Some(function) = find_function(env, &finish_func_name) {
                        let mut out_parameters = find_out_parameters(env, function);
                        if use_function_return_for_result(env, function.ret.typ) {
                            out_parameters
                                .insert(0, rust_type(env, function.ret.typ).into_string());
                        }
                        let parameters = format_out_parameters(&out_parameters);
                        let error_type = find_error_type(env, function);
                        type_string = format!(
                            "FnOnce(Result<{}, {}>) + Send + 'static",
                            parameters, error_type
                        );
                        let bound_name = *self.unused.front().unwrap();
                        callback_info = Some(CallbackInfo {
                            callback_type: type_string.clone(),
                            success_parameters: parameters,
                            error_parameters: error_type,
                            bound_name,
                        });
                    }
                } else if par.c_type == "GDestroyNotify" || env.library.type_(par.typ).is_function()
                {
{'fraction_non_alphanumeric': 0.1115930137146876, 'fraction_numerical': 0.00046887820888524205, 'mean_word_length': 1.914929962418859, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 31, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5288046', 'n_tokens_mistral': 2442, 'n_tokens_neox': 2425, 'n_words': 515}