lief 1.0.0

Official Rust bindings for LIEF
use lief_ffi as ffi;

use crate::common::{FromFFI, into_optional};
use crate::declare_fwd_iterator;
use std::marker::PhantomData;

use super::{Category, Class, DeclOpt, Protocol};

/// This structure is the main interface to inspect Objective-C metadata
///
/// It can be accessed using the function [`crate::macho::Binary::objc_metadata`]
pub struct Metadata<'a> {
    ptr: cxx::UniquePtr<ffi::ObjC_Metadata>,
    _owner: PhantomData<&'a ()>,
}

impl FromFFI<ffi::ObjC_Metadata> for Metadata<'_> {
    fn from_ffi(info: cxx::UniquePtr<ffi::ObjC_Metadata>) -> Self {
        Self {
            ptr: info,
            _owner: PhantomData,
        }
    }
}

impl Metadata<'_> {
    /// Return an iterator over the different Objective-C classes (`@interface`)
    pub fn classes(&self) -> Classes<'_> {
        Classes::new(self.ptr.classes())
    }

    /// Return an iterator over the Objective-C protocols declared in this binary (`@protocol`).
    pub fn protocols(&self) -> Protocols<'_> {
        Protocols::new(self.ptr.protocols())
    }

    /// Return an iterator over the Objective-C categories declared in this binary
    /// (e.g. `@interface NSString (MyAdditions)`).
    pub fn categories(&self) -> Categories<'_> {
        Categories::new(self.ptr.categories())
    }

    /// Try to find the Objective-C class with the given **mangled** name
    pub fn class_by_name(&self, name: &str) -> Option<Class<'_>> {
        cxx::let_cxx_string!(__cxx_s = name);
        into_optional(self.ptr.get_class(&__cxx_s))
    }

    /// Try to find the Objective-C protocol with the given **mangled** name
    pub fn protocol_by_name(&self, name: &str) -> Option<Protocol<'_>> {
        cxx::let_cxx_string!(__cxx_s = name);
        into_optional(self.ptr.get_protocol(&__cxx_s))
    }

    /// Generate a header-like string of all the Objective-C metadata identified in the
    /// binary.
    pub fn to_decl(&self) -> String {
        self.ptr.to_decl().to_string()
    }

    /// Same behavior as [`Metadata::to_decl`] but with an additional
    /// [`DeclOpt`] parameter to customize the output
    pub fn to_decl_with_opt(&self, opt: &DeclOpt) -> String {
        self.ptr.to_decl_with_opt(&opt.to_ffi()).to_string()
    }
}

declare_fwd_iterator!(
    Classes,
    Class<'a>,
    ffi::ObjC_Class,
    ffi::ObjC_Metadata,
    ffi::ObjC_Metadata_it_classes
);

declare_fwd_iterator!(
    Protocols,
    Protocol<'a>,
    ffi::ObjC_Protocol,
    ffi::ObjC_Metadata,
    ffi::ObjC_Metadata_it_protocols
);

declare_fwd_iterator!(
    Categories,
    Category<'a>,
    ffi::ObjC_Category,
    ffi::ObjC_Metadata,
    ffi::ObjC_Metadata_it_categories
);