<commit_before>use super::{
    child_properties::ChildProperties, imports::Imports, info_base::InfoBase,
    signatures::Signatures, *,
};
use crate::{
    config::gobjects::{GObject, GStatus},
    env::Env,
    library::{self, FunctionKind},
    nameutil::*,
    traits::*,
};
use log::info;
use std::{borrow::Cow, ops::Deref};

/// The location of an item within the object
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum LocationInObject {
    Impl,
    Ext,
    ExtManual,
    Builder,
}

#[derive(Debug, Default)]
pub struct Info {
    pub base: InfoBase,
    pub c_type: String,
    pub c_class_type: Option<String>,
    pub get_type: String,
    pub is_interface: bool,
    pub is_fundamental: bool,
    pub supertypes: Vec<general::StatusedTypeId>,
    pub final_type: bool,
    pub generate_trait: bool,
    pub trait_name: String,
    pub has_constructors: bool,
    pub has_functions: bool,
    pub signals: Vec<signals::Info>,
    pub notify_signals: Vec<signals::Info>,
    pub properties: Vec<properties::Property>,
    pub builder_properties: Vec<(Vec<properties::Property>, TypeId)>,
    pub builder_postprocess: Option<String>,
    pub child_properties: ChildProperties,
    pub signatures: Signatures,
    /// Specific to fundamental types
    pub ref_fn: Option<String>,
    /// Specific to fundamental types
    pub unref_fn: Option<String>,
}

impl Info {
    pub fn has_signals(&self) -> bool {
        self.signals.iter().any(|s| s.trampoline.is_ok())
            || self.notify_signals.iter().any(|s| s.trampoline.is_ok())
    }

    /// Whether we should generate an impl block for this object
    /// We don't generate an impl block if the type doesn't have any of the followings:
    /// - Constructors / Functions / Builder properties (no build function)
    /// - Is a final type & doesn't have either methods / properties / child properties / signals
    pub fn should_generate_impl_block(&self) -> bool {
        self.has_constructors
            || has_builder_properties(&self.builder_properties)
            || !(self.need_generate_trait()
                && self.methods().is_empty()
                && self.properties.is_empty()
                && self.child_properties.is_empty()
                && self.signals.is_empty())
            || self.has_functions
    }

    pub fn need_generate_inherent(&self) -> bool {
        self.has_constructors
            || self.has_functions
            || !self.need_generate_trait()
            || has_builder_properties(&self.builder_properties)
    }

    pub fn need_generate_trait(&self) -> bool {
        self.generate_trait
    }

    pub fn has_action_signals(&self) -> bool {
        self.signals.iter().any(|s| s.action_emit_name.is_some())
    }

    /// Returns the location of the function within this object
    pub fn function_location(&self, fn_info: &functions::Info) -> LocationInObject {
        if self.final_type
            || matches!(
                fn_info.kind,
                FunctionKind::Constructor | FunctionKind::Function
            )
        {
            LocationInObject::Impl
        } else if fn_info.status == GStatus::Generate {
            LocationInObject::Ext
        } else {
            LocationInObject::ExtManual
        }
    }

    /// Generate doc name based on function location within this object
    /// See also [`Self::function_location()`].
    /// Returns `(item/crate path including type name, just the type name)`
    pub fn generate_doc_link_info(
        &self,
        fn_info: &functions::Info,
    ) -> (Cow<'_, str>, Cow<'_, str>) {
        match self.function_location(fn_info) {
            LocationInObject::Impl => (self.name.as_str().into(), self.name.as_str().into()),
            LocationInObject::ExtManual => {
                let trait_name = format!("{}Manual", self.trait_name);
                (format!("prelude::{}", trait_name).into(), trait_name.into())
            }
            LocationInObject::Ext => (
                format!("prelude::{}", self.trait_name).into(),
                self.trait_name.as_str().into(),<commit_msg>docs: Never use ExtManual trait with GObject<commit_after>use super::{
    child_properties::ChildProperties, imports::Imports, info_base::InfoBase,
    signatures::Signatures, *,
};
use crate::{
    config::gobjects::{GObject, GStatus},
    env::Env,
    library::{self, FunctionKind},
    nameutil::*,
    traits::*,
};
use log::info;
use std::{borrow::Cow, ops::Deref};

/// The location of an item within the object
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum LocationInObject {
    Impl,
    Ext,
    ExtManual,
    Builder,
}

#[derive(Debug, Default)]
pub struct Info {
    pub base: InfoBase,
    pub c_type: String,
    pub c_class_type: Option<String>,
    pub get_type: String,
    pub is_interface: bool,
    pub is_fundamental: bool,
    pub supertypes: Vec<general::StatusedTypeId>,
    pub final_type: bool,
    pub generate_trait: bool,
    pub trait_name: String,
    pub has_constructors: bool,
    pub has_functions: bool,
    pub signals: Vec<signals::Info>,
    pub notify_signals: Vec<signals::Info>,
    pub properties: Vec<properties::Property>,
    pub builder_properties: Vec<(Vec<properties::Property>, TypeId)>,
    pub builder_postprocess: Option<String>,
    pub child_properties: ChildProperties,
    pub signatures: Signatures,
    /// Specific to fundamental types
    pub ref_fn: Option<String>,
    /// Specific to fundamental types
    pub unref_fn: Option<String>,
}

impl Info {
    pub fn has_signals(&self) -> bool {
        self.signals.iter().any(|s| s.trampoline.is_ok())
            || self.notify_signals.iter().any(|s| s.trampoline.is_ok())
    }

    /// Whether we should generate an impl block for this object
    /// We don't generate an impl block if the type doesn't have any of the followings:
    /// - Constructors / Functions / Builder properties (no build function)
    /// - Is a final type & doesn't have either methods / properties / child properties / signals
    pub fn should_generate_impl_block(&self) -> bool {
        self.has_constructors
            || has_builder_properties(&self.builder_properties)
            || !(self.need_generate_trait()
                && self.methods().is_empty()
                && self.properties.is_empty()
                && self.child_properties.is_empty()
                && self.signals.is_empty())
            || self.has_functions
    }

    pub fn need_generate_inherent(&self) -> bool {
        self.has_constructors
            || self.has_functions
            || !self.need_generate_trait()
            || has_builder_properties(&self.builder_properties)
    }

    pub fn need_generate_trait(&self) -> bool {
        self.generate_trait
    }

    pub fn has_action_signals(&self) -> bool {
        self.signals.iter().any(|s| s.action_emit_name.is_some())
    }

    /// Returns the location of the function within this object
    pub fn function_location(&self, fn_info: &functions::Info) -> LocationInObject {
        if self.final_type
            || matches!(
                fn_info.kind,
                FunctionKind::Constructor | FunctionKind::Function
            )
        {
            LocationInObject::Impl
        } else if fn_info.status == GStatus::Generate || self.full_name == "GObject.Object" {
            LocationInObject::Ext
        } else {
            LocationInObject::ExtManual
        }
    }

    /// Generate doc name based on function location within this object
    /// See also [`Self::function_location()`].
    /// Returns `(item/crate path including type name, just the type name)`
    pub fn generate_doc_link_info(
        &self,
        fn_info: &functions::Info,
    ) -> (Cow<'_, str>, Cow<'_, str>) {
        match self.function_location(fn_info) {
            LocationInObject::Impl => (self.name.as_str().into(), self.name.as_str().into()),
            LocationInObject::ExtManual => {
                let trait_name = format!("{}Manual", self.trait_name);
                (format!("prelude::{}", trait_name).into(), trait_name.into())
            }
            LocationInObject::Ext => (
                format!("prelude::{}", self.trait_name).into(),
                self.trait_name.as_str().into(),
{'fraction_non_alphanumeric': 0.1264673847270967, 'fraction_numerical': 0.0, 'mean_word_length': 2.5883630047763786, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 47, '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': '5653627', 'n_tokens_mistral': 2398, 'n_tokens_neox': 2391, 'n_words': 569}