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 #[inline]
84 pub fn as_ptr(&self) -> *mut HV {
85 self.0.as_ptr()
86 }
87}
88
89pub struct HvIter<'a> {
91 perl: &'a Perl,
92 hv: NonNull<HV>,
93 _marker: ::core::marker::PhantomData<&'a HV>,
95}
96
97impl<'a> Iterator for HvIter<'a> {
98 type Item = (&'a [u8], Sv);
99
100 fn next(&mut self) -> Option<Self::Item> {
101 let mut key_ptr: *mut ::core::ffi::c_char = ::core::ptr::null_mut();
102 let mut keylen: libperl_sys::I32 = 0;
103 let val = unsafe {
104 crate::thx_call!(
105 self.perl,
106 Perl_hv_iternextsv,
107 self.hv.as_ptr(),
108 &mut key_ptr,
109 &mut keylen,
110 )
111 };
112 if val.is_null() {
113 return None;
114 }
115 let key = unsafe {
116 ::core::slice::from_raw_parts(key_ptr as *const u8, keylen as usize)
117 };
118 let sv = unsafe { Sv::from_raw_unchecked(val) };
119 Some((key, sv))
120 }
121}