use std::ptr::NonNull;
use libperl_sys::{PADLIST, PADNAME, PADNAMELIST};
#[derive(Clone, Copy)]
#[repr(transparent)]
pub struct PadName(NonNull<PADNAME>);
impl PadName {
#[inline]
pub fn from_raw(p: *const PADNAME) -> Option<Self> {
NonNull::new(p as *mut PADNAME).map(PadName)
}
#[inline]
pub fn as_ptr(&self) -> *mut PADNAME {
self.0.as_ptr()
}
pub fn pv(&self) -> Option<String> {
let pv = unsafe { libperl_sys::PadnamePV(self.as_ptr()) };
if pv.is_null() {
return None;
}
#[cfg(perlapi_ver22)]
let len = unsafe { libperl_sys::PadnameLEN(self.as_ptr()) };
#[cfg(not(perlapi_ver22))]
let len = unsafe { libperl_sys::SvCUR(self.as_ptr() as *const libperl_sys::SV) };
let bytes = unsafe { std::slice::from_raw_parts(pv as *const u8, len as usize) };
Some(String::from_utf8_lossy(bytes).into_owned())
}
pub fn type_stash_name(&self) -> Option<String> {
let stash = unsafe { libperl_sys::PadnameTYPE(self.as_ptr()) };
if stash.is_null() {
return None;
}
let p = unsafe { libperl_sys::HvNAME(stash) };
if p.is_null() {
None
} else {
Some(
unsafe { std::ffi::CStr::from_ptr(p) }
.to_string_lossy()
.into_owned(),
)
}
}
}
pub struct PadNames {
arr: *mut *mut PADNAME,
ix: isize,
max: isize,
}
impl PadNames {
pub(crate) fn from_padlist(pl: *const PADLIST) -> PadNames {
let empty = PadNames {
arr: std::ptr::null_mut(),
ix: 0,
max: -1,
};
if pl.is_null() {
return empty;
}
let pnl: *const PADNAMELIST = unsafe { libperl_sys::PadlistNAMES(pl) };
if pnl.is_null() {
return empty;
}
PadNames {
arr: unsafe { libperl_sys::PadnamelistARRAY(pnl) },
ix: 0,
max: unsafe { libperl_sys::PadnamelistMAX(pnl) as isize },
}
}
}
impl Iterator for PadNames {
type Item = Option<PadName>;
fn next(&mut self) -> Option<Self::Item> {
if self.ix > self.max || self.arr.is_null() {
return None;
}
let p = unsafe { *self.arr.offset(self.ix) };
self.ix += 1;
Some(PadName::from_raw(p))
}
fn size_hint(&self) -> (usize, Option<usize>) {
let r = (self.max + 1 - self.ix).max(0) as usize;
(r, Some(r))
}
}