use std::ptr::NonNull;
use libperl_sys::{GP, GV, HEK, SV};
use crate::Cv;
#[derive(Clone, Copy)]
#[repr(transparent)]
pub struct Gv(NonNull<GV>);
impl Gv {
#[inline]
pub unsafe fn from_raw_unchecked(p: *mut GV) -> Self {
debug_assert!(!p.is_null(), "Gv::from_raw_unchecked received a null pointer");
Gv(unsafe { NonNull::new_unchecked(p) })
}
#[inline]
pub fn from_raw(p: *mut GV) -> Option<Self> {
NonNull::new(p).map(Gv)
}
#[inline]
pub fn from_sv(sv: *mut SV) -> Option<Gv> {
if sv.is_null() || !unsafe { libperl_sys::isGV_with_GP(sv) } {
return None;
}
Some(unsafe { Gv::from_raw_unchecked(sv as *mut GV) })
}
#[inline]
pub fn as_ptr(&self) -> *mut GV {
self.0.as_ptr()
}
pub fn name(&self) -> Option<String> {
let hek = unsafe { libperl_sys::GvNAME_HEK(self.as_ptr() as *const SV) };
hek_str(hek)
}
pub fn stash_name(&self) -> Option<String> {
let stash = unsafe { libperl_sys::GvSTASH(self.as_ptr() as *const SV) };
if stash.is_null() {
return None;
}
cstr_opt(unsafe { libperl_sys::HvNAME(stash) })
}
pub fn qualified_name(&self) -> Option<String> {
let name = self.name()?;
Some(match self.stash_name() {
Some(pkg) => format!("{pkg}::{name}"),
None => name,
})
}
#[inline]
fn gp(&self) -> *mut GP {
unsafe { libperl_sys::GvGP(self.as_ptr() as *const _) }
}
#[inline]
pub fn cv(&self) -> Option<Cv> {
if self.gp().is_null() {
return None;
}
Cv::from_raw(unsafe { libperl_sys::GvCV(self.as_ptr() as *const _) })
}
pub fn file(&self) -> Option<String> {
if self.gp().is_null() {
return None;
}
cstr_opt(unsafe { libperl_sys::GvFILE(self.as_ptr() as *const _) })
}
pub fn line(&self) -> Option<u32> {
if self.gp().is_null() {
return None;
}
Some(unsafe { libperl_sys::GvLINE(self.as_ptr() as *const _) })
}
}
fn cstr_opt(p: *const std::os::raw::c_char) -> Option<String> {
if p.is_null() {
None
} else {
Some(
unsafe { std::ffi::CStr::from_ptr(p) }
.to_string_lossy()
.into_owned(),
)
}
}
fn hek_str(hek: *const HEK) -> Option<String> {
if hek.is_null() {
None
} else {
cstr_opt(unsafe { libperl_sys::HEK_KEY(hek) })
}
}