1use std::ptr::NonNull;
5
6use libperl_sys::{HV, SV};
7
8use crate::{Perl, Rv, Sv, sv_refcnt_inc};
9
10#[derive(Clone, Copy)]
11#[repr(transparent)]
12pub struct Hv(NonNull<HV>);
13
14impl Hv {
15 #[inline]
17 pub fn new(perl: &Perl) -> Hv {
18 unsafe {
19 let hv = crate::thx_call!(perl, Perl_newHV,);
20 crate::thx_call!(perl, Perl_sv_2mortal, hv as *mut SV);
21 Hv(NonNull::new(hv).expect("Perl_newHV returned null"))
22 }
23 }
24
25 pub fn store(&self, perl: &Perl, key: &str, val: Sv) {
30 let bytes = key.as_bytes();
31 unsafe {
32 let inc = sv_refcnt_inc(val.as_ptr());
33 crate::thx_call!(
36 perl,
37 Perl_hv_store,
38 self.0.as_ptr(),
39 bytes.as_ptr() as *const ::core::ffi::c_char,
40 bytes.len() as _,
41 inc,
42 0, );
44 }
45 }
46
47 #[inline]
49 pub fn into_rv(self, perl: &Perl) -> Rv<Hv> {
50 unsafe {
51 let rv = crate::thx_call!(perl, Perl_newRV, self.0.as_ptr() as *mut SV);
52 crate::thx_call!(perl, Perl_sv_2mortal, rv);
53 Rv::from_raw_sv(rv)
54 }
55 }
56
57 #[inline]
64 pub unsafe fn from_raw_unchecked(p: *mut HV) -> Hv {
65 debug_assert!(!p.is_null(), "Hv::from_raw_unchecked received a null pointer");
66 Hv(unsafe { NonNull::new_unchecked(p) })
67 }
68
69 #[inline]
77 pub fn iter<'a>(&'a self, perl: &'a Perl) -> HvIter<'a> {
78 unsafe { crate::thx_call!(perl, Perl_hv_iterinit, self.0.as_ptr()); }
79 HvIter { perl, hv: self.0, _marker: ::core::marker::PhantomData }
80 }
81
82 pub fn name(&self) -> Option<String> {
85 let p = unsafe { libperl_sys::HvNAME(self.0.as_ptr()) };
86 if p.is_null() {
87 None
88 } else {
89 Some(
90 unsafe { std::ffi::CStr::from_ptr(p) }
91 .to_string_lossy()
92 .into_owned(),
93 )
94 }
95 }
96
97 #[inline]
99 pub fn as_ptr(&self) -> *mut HV {
100 self.0.as_ptr()
101 }
102}
103
104pub struct HvIter<'a> {
106 perl: &'a Perl,
107 hv: NonNull<HV>,
108 _marker: ::core::marker::PhantomData<&'a HV>,
110}
111
112impl<'a> Iterator for HvIter<'a> {
113 type Item = (&'a [u8], Sv);
114
115 fn next(&mut self) -> Option<Self::Item> {
116 let mut key_ptr: *mut ::core::ffi::c_char = ::core::ptr::null_mut();
117 let mut keylen: libperl_sys::I32 = 0;
118 let val = unsafe {
119 crate::thx_call!(
120 self.perl,
121 Perl_hv_iternextsv,
122 self.hv.as_ptr(),
123 &mut key_ptr,
124 &mut keylen,
125 )
126 };
127 if val.is_null() {
128 return None;
129 }
130 let key = unsafe {
131 ::core::slice::from_raw_parts(key_ptr as *const u8, keylen as usize)
132 };
133 let sv = unsafe { Sv::from_raw_unchecked(val) };
134 Some((key, sv))
135 }
136}