use crate::ported::builtin::bin_typeset;
use crate::ported::mem::{queue_signals, unqueue_signals};
use crate::ported::options::optlookup;
use crate::ported::params::{
deleteparamtable, endparamscope, locallevel, newparamtable, printparamnode, startparamscope,
};
use crate::ported::utils::{zerr, zwarn, zwarnnam};
use crate::ported::zsh_h::{
eprog, features, funcwrap, hashnode, hashtable, isset, module, options, param, HashTable,
MAX_OPS, OPT_ISSET, PM_AUTOLOAD, PM_DECLARED, PM_HIDE, PM_NAMEREF, PM_NORESTORE, PM_READONLY,
PM_REMOVABLE, PM_RESTRICTED, PM_RO_BY_DESIGN, PM_SPECIAL, PM_UNSET, WARNCREATEGLOBAL,
};
use std::sync::atomic::Ordering;
use std::sync::{Mutex, OnceLock};
#[derive(Debug, Clone, Copy)]
#[allow(non_camel_case_types)]
pub struct gsu_closure {
pub kind: u8, pub g: usize, }
#[allow(unused_variables)]
pub fn makeprivate(hn: *mut param, flags: i32) {
if hn.is_null() {
return;
}
let pm_level = unsafe { (*hn).level };
let cur_local = locallevel.load(Ordering::Relaxed);
if pm_level != cur_local {
return;
}
let pm_flags = unsafe { (*hn).node.flags };
let pm_ename = unsafe { (*hn).ename.is_some() };
let has_old = unsafe { (*hn).old.is_some() };
let pm_special = (pm_flags & PM_SPECIAL as i32) != 0;
let pm_removable = (pm_flags & PM_REMOVABLE as i32) != 0;
let pm_norestore = (pm_flags & PM_NORESTORE as i32) != 0;
let outer_cond = pm_ename
|| pm_norestore
|| (has_old
&& (
true
));
if outer_cond {
if pm_special && !pm_removable {
zerr(
&format!("can't change scope of existing param: {}", unsafe {
(*hn).node.nam.clone()
}), );
}
MAKEPRIVATE_ERROR.store(1, Ordering::Relaxed); return; }
let name = unsafe { (*hn).node.nam.clone() };
if let Ok(mut p) = PRIVATE_PARAMS.lock() {
p.insert(name);
}
unsafe {
(*hn).node.flags |= (PM_HIDE | PM_SPECIAL | PM_REMOVABLE | PM_RO_BY_DESIGN) as i32;
}
unsafe {
(*hn).level -= 1;
}
}
pub fn is_private(pm: *const param) -> i32 {
if pm.is_null() {
return 0;
}
let name = unsafe { (*pm).node.nam.clone() };
if PRIVATE_PARAMS
.lock()
.map(|p| p.contains(&name))
.unwrap_or(false)
{
1 } else {
0 }
}
pub fn bin_private(
nam: &str,
args: &[String], ops_in: &options,
func: i32,
) -> i32 {
let mut ops_local = ops_in.clone();
let ops = &mut ops_local;
let mut assigns: Vec<(String, String)> = Vec::new();
let assigns = &mut assigns;
let mut from_typeset: i32 = 1; let ofake = FAKELEVEL.load(Ordering::Relaxed); let hasargs = !assigns.is_empty(); MAKEPRIVATE_ERROR.store(0, Ordering::Relaxed);
if !OPT_ISSET(ops, b'P') {
FAKELEVEL.store(0, Ordering::Relaxed); from_typeset = bin_typeset(nam, args, ops, func); FAKELEVEL.store(ofake, Ordering::Relaxed); return from_typeset; }
if OPT_ISSET(ops, b'T') {
zwarn("bad option: -T"); return 1; }
let locallevel2 = locallevel.load(Ordering::Relaxed);
if locallevel2 == 0 {
let warn = isset(WARNCREATEGLOBAL);
if warn {
zwarnnam(nam, "invalid local scope, using globals"); }
return bin_typeset("private", args, ops, func); }
if !(OPT_ISSET(ops, b'm') || OPT_ISSET(ops, b'+')) {
ops.ind[b'g' as usize] = 2; }
if OPT_ISSET(ops, b'p') || OPT_ISSET(ops, b'm') || (!hasargs && OPT_ISSET(ops, b'+'))
{
return bin_typeset("private", args, ops, func); }
queue_signals(); FAKELEVEL.store(locallevel2, Ordering::Relaxed); let mut paramscope_buf = newparamtable(17, "private_scope").unwrap_or_else(|| {
Box::new(hashtable {
hsize: 0,
ct: 0,
nodes: Vec::new(),
tmpdata: 0,
hash: None,
emptytable: None,
filltable: None,
cmpnodes: None,
addnode: None,
getnode: None,
getnode2: None,
removenode: None,
disablenode: None,
enablenode: None,
freenode: None,
printnode: None,
scantab: None,
})
});
startparamscope(&mut paramscope_buf); from_typeset = bin_typeset("private", args, ops, func); endparamscope(); FAKELEVEL.store(ofake, Ordering::Relaxed); unqueue_signals();
let mpe = MAKEPRIVATE_ERROR.load(Ordering::Relaxed);
mpe | from_typeset }
pub fn setfn_error(pm: *mut param) {
if pm.is_null() {
return;
}
unsafe {
(*pm).node.flags |= PM_UNSET as i32;
} let name = unsafe { (*pm).node.nam.clone() };
zerr(&format!(
"{}: attempt to assign private in nested scope",
name
)); }
pub fn pps_getfn(pm: *mut param) -> String {
if pm.is_null() {
return String::new();
}
let pm_level = unsafe { (*pm).level };
if locallevel.load(Ordering::Relaxed) >= pm_level {
unsafe { (*pm).u_str.clone().unwrap_or_default() }
} else {
String::new() }
}
pub fn pps_setfn(pm: *mut param, x: &str) {
if pm.is_null() {
return;
}
let pm_level = unsafe { (*pm).level };
if locallevel.load(Ordering::Relaxed) == pm_level
|| locallevel.load(Ordering::Relaxed) > private_wraplevel.load(Ordering::Relaxed)
{
unsafe {
(*pm).u_str = Some(x.to_string());
} } else {
setfn_error(pm); }
}
pub fn pps_unsetfn(pm: *mut param, explicit: i32) {
if pm.is_null() {
return;
}
let pm_level = unsafe { (*pm).level };
if locallevel.load(Ordering::Relaxed) <= pm_level {
unsafe {
(*pm).u_str = None;
}
}
if explicit != 0 {
unsafe {
(*pm).node.flags |= PM_DECLARED as i32;
} } else {
if let Ok(mut p) = PRIVATE_PARAMS.lock() {
unsafe {
p.remove(&(*pm).node.nam);
}
}
}
}
pub fn ppi_getfn(pm: *mut param) -> i64 {
if pm.is_null() {
return 0;
}
let pm_level = unsafe { (*pm).level };
if locallevel.load(Ordering::Relaxed) >= pm_level {
unsafe { (*pm).u_val } } else {
0 }
}
pub fn ppi_setfn(pm: *mut param, x: i64) {
if pm.is_null() {
return;
}
let pm_level = unsafe { (*pm).level };
if locallevel.load(Ordering::Relaxed) == pm_level
|| locallevel.load(Ordering::Relaxed) > private_wraplevel.load(Ordering::Relaxed)
{
unsafe {
(*pm).u_val = x;
} } else {
setfn_error(pm); }
}
pub fn ppi_unsetfn(pm: *mut param, explicit: i32) {
if pm.is_null() {
return;
}
let pm_level = unsafe { (*pm).level };
if locallevel.load(Ordering::Relaxed) <= pm_level {
unsafe {
(*pm).u_val = 0;
} }
if explicit != 0 {
unsafe {
(*pm).node.flags |= PM_DECLARED as i32;
} } else {
if let Ok(mut p) = PRIVATE_PARAMS.lock() {
unsafe {
p.remove(&(*pm).node.nam);
}
}
}
}
pub fn ppf_getfn(pm: *mut param) -> f64 {
if pm.is_null() {
return 0.0;
}
let pm_level = unsafe { (*pm).level };
if locallevel.load(Ordering::Relaxed) >= pm_level {
unsafe { (*pm).u_dval } } else {
0.0 }
}
pub fn ppf_setfn(pm: *mut param, x: f64) {
if pm.is_null() {
return;
}
let pm_level = unsafe { (*pm).level };
if locallevel.load(Ordering::Relaxed) == pm_level
|| locallevel.load(Ordering::Relaxed) > private_wraplevel.load(Ordering::Relaxed)
{
unsafe {
(*pm).u_dval = x;
} } else {
setfn_error(pm); }
}
pub fn ppf_unsetfn(pm: *mut param, explicit: i32) {
if pm.is_null() {
return;
}
let pm_level = unsafe { (*pm).level };
if locallevel.load(Ordering::Relaxed) <= pm_level {
unsafe {
(*pm).u_dval = 0.0;
} }
if explicit != 0 {
unsafe {
(*pm).node.flags |= PM_DECLARED as i32;
}
} else {
if let Ok(mut p) = PRIVATE_PARAMS.lock() {
unsafe {
p.remove(&(*pm).node.nam);
}
}
}
}
pub fn ppa_getfn(pm: *mut param) -> Vec<String> {
if pm.is_null() {
return Vec::new();
}
let pm_level = unsafe { (*pm).level };
if locallevel.load(Ordering::Relaxed) >= pm_level {
unsafe { (*pm).u_arr.clone().unwrap_or_default() } } else {
Vec::new() }
}
pub fn ppa_setfn(pm: *mut param, x: Vec<String>) {
if pm.is_null() {
return;
}
let pm_level = unsafe { (*pm).level };
if locallevel.load(Ordering::Relaxed) == pm_level
|| locallevel.load(Ordering::Relaxed) > private_wraplevel.load(Ordering::Relaxed)
{
unsafe {
(*pm).u_arr = Some(x);
} } else {
setfn_error(pm); }
}
pub fn ppa_unsetfn(pm: *mut param, explicit: i32) {
if pm.is_null() {
return;
}
let pm_level = unsafe { (*pm).level };
if locallevel.load(Ordering::Relaxed) <= pm_level {
unsafe {
(*pm).u_arr = None;
} }
if explicit != 0 {
unsafe {
(*pm).node.flags |= PM_DECLARED as i32;
}
} else {
if let Ok(mut p) = PRIVATE_PARAMS.lock() {
unsafe {
p.remove(&(*pm).node.nam);
}
}
}
}
#[allow(non_upper_case_globals)]
pub static emptytable: Mutex<Option<HashTable>> = Mutex::new(None);
pub fn pph_getfn(pm: *mut param) -> Option<()> {
if pm.is_null() {
return None;
}
let pm_level = unsafe { (*pm).level };
if locallevel.load(Ordering::Relaxed) >= pm_level {
unsafe { (*pm).u_hash.as_ref().map(|_| ()) } } else {
None }
}
pub fn pph_setfn(
pm: *mut param, x: Option<HashTable>,
) {
if pm.is_null() {
return;
}
let pm_level = unsafe { (*pm).level };
if locallevel.load(Ordering::Relaxed) == pm_level
|| locallevel.load(Ordering::Relaxed) > private_wraplevel.load(Ordering::Relaxed)
{
unsafe {
(*pm).u_hash = x;
} } else {
setfn_error(pm); }
}
pub fn pph_unsetfn(pm: *mut param, explicit: i32) {
if pm.is_null() {
return;
}
let pm_level = unsafe { (*pm).level };
if locallevel.load(Ordering::Relaxed) <= pm_level {
unsafe {
(*pm).u_hash = None;
} }
if explicit != 0 {
unsafe {
(*pm).node.flags |= PM_DECLARED as i32;
}
} else {
if let Ok(mut p) = PRIVATE_PARAMS.lock() {
unsafe {
p.remove(&(*pm).node.nam);
}
}
}
}
pub const PM_WAS_UNSET: u32 = PM_NORESTORE; pub const PM_WAS_RONLY: u32 = PM_RESTRICTED;
pub fn scopeprivate(hn: *mut param, onoff: i32) {
if hn.is_null() {
return;
}
let pm_level = unsafe { (*hn).level };
let local = locallevel.load(Ordering::Relaxed);
if pm_level != local {
return;
} if is_private(hn) == 0 {
return;
} unsafe {
let f = (*hn).node.flags;
if onoff == PM_UNSET as i32 {
if (f & PM_UNSET as i32) != 0 {
(*hn).node.flags |= PM_WAS_UNSET as i32;
} else {
(*hn).node.flags |= PM_UNSET as i32;
}
if (f & PM_READONLY as i32) != 0 {
(*hn).node.flags |= PM_WAS_RONLY as i32;
} else {
(*hn).node.flags |= PM_READONLY as i32;
}
} else {
if (f & PM_WAS_UNSET as i32) != 0 {
(*hn).node.flags |= PM_UNSET as i32;
} else {
(*hn).node.flags &= !(PM_UNSET as i32);
}
if (f & PM_WAS_RONLY as i32) != 0 {
(*hn).node.flags |= PM_READONLY as i32;
} else {
(*hn).node.flags &= !(PM_READONLY as i32);
}
(*hn).node.flags &= !((PM_WAS_UNSET | PM_WAS_RONLY) as i32);
}
}
}
pub static private_wraplevel: std::sync::atomic::AtomicI32 = std::sync::atomic::AtomicI32::new(0);
pub fn wrap_private(
_prog: *const eprog, _w: *const funcwrap,
_name: *mut libc::c_char,
) -> i32 {
let local = locallevel.load(Ordering::Relaxed);
let pwl = private_wraplevel.load(Ordering::Relaxed);
if pwl < local {
let owl = pwl; private_wraplevel.store(local, Ordering::Relaxed); private_wraplevel.store(owl, Ordering::Relaxed); return 0; }
1 }
pub fn getprivatenode(pm: *mut param) -> *mut param {
let mut cur = pm;
if cur.is_null() {
return cur;
}
let pm_flags = unsafe { (*cur).node.flags };
if (pm_flags & PM_AUTOLOAD as i32) != 0 {
} else {
}
while !cur.is_null() {
let cur_level = unsafe { (*cur).level };
let fakelvl = FAKELEVEL.load(Ordering::Relaxed);
let local = locallevel.load(Ordering::Relaxed);
let pwl = private_wraplevel.load(Ordering::Relaxed);
if !(fakelvl == 0 && local > cur_level && is_private(cur) != 0) {
break;
}
if cur_level == pwl + 1 {
break;
} cur = unsafe {
(*cur)
.old
.as_mut()
.map(|b| &mut **b as *mut _)
.unwrap_or(std::ptr::null_mut())
};
}
if !cur.is_null() {
let f = unsafe { (*cur).node.flags };
if (f & PM_NAMEREF as i32) != 0 {
}
}
cur }
pub fn getprivatenode2(pm: *mut param) -> *mut param {
let mut cur = pm;
while !cur.is_null() {
let cur_level = unsafe { (*cur).level };
let fakelvl = FAKELEVEL.load(Ordering::Relaxed);
let local = locallevel.load(Ordering::Relaxed);
if !(fakelvl == 0 && local > cur_level && is_private(cur) != 0) {
break;
}
cur = unsafe {
(*cur)
.old
.as_mut()
.map(|b| &mut **b as *mut _)
.unwrap_or(std::ptr::null_mut())
};
}
cur }
#[allow(unused_variables)]
pub fn printprivatenode(hn: *mut param, printflags: i32) {
let mut cur = hn;
while !cur.is_null() {
let pm_level = unsafe { (*cur).level };
let pm_flags = unsafe { (*cur).node.flags };
let fakelvl = FAKELEVEL.load(Ordering::Relaxed);
let unset_in_fake = fakelvl != 0 && fakelvl > pm_level && (pm_flags & PM_UNSET as i32) != 0;
let cond = (fakelvl == 0 || unset_in_fake)
&& locallevel.load(Ordering::Relaxed) > pm_level
&& is_private(cur) != 0;
if !cond {
break;
}
cur = unsafe {
(*cur)
.old
.as_ref()
.map(|b| b.as_ref() as *const _ as *mut _)
.unwrap_or(std::ptr::null_mut())
};
}
if !cur.is_null() {
let hn: &mut param = unsafe { &mut *cur };
printparamnode(hn, printflags); }
}
#[allow(unused_variables)]
pub fn setup_(m: *const module) -> i32 {
0
}
pub fn features_(m: *const module, features: &mut Vec<String>) -> i32 {
*features = featuresarray(m, module_features());
0
}
pub fn enables_(m: *const module, enables: &mut Option<Vec<i32>>) -> i32 {
handlefeatures(m, module_features(), enables)
}
#[allow(unused_variables)]
pub fn boot_(m: *const module) -> i32 {
if let Some(t) = newparamtable(1, "private") {
if let Ok(mut e) = emptytable.lock() {
*e = Some(t);
}
}
0 }
pub fn cleanup_(m: *const module) -> i32 {
setfeatureenables(m, module_features(), None)
}
#[allow(unused_variables)]
pub fn finish_(m: *const module) -> i32 {
if let Ok(mut e) = emptytable.lock() {
if let Some(t) = e.take() {
deleteparamtable(Some(t));
}
}
0 }
pub static MAKEPRIVATE_ERROR: std::sync::atomic::AtomicI32 = std::sync::atomic::AtomicI32::new(0);
pub static PRIVATE_PARAMS: std::sync::LazyLock<Mutex<std::collections::HashSet<String>>> =
std::sync::LazyLock::new(|| Mutex::new(std::collections::HashSet::new()));
pub static FAKELEVEL: std::sync::atomic::AtomicI32 = std::sync::atomic::AtomicI32::new(0);
static MODULE_FEATURES: OnceLock<Mutex<features>> = OnceLock::new();
fn featuresarray(_m: *const module, _f: &Mutex<features>) -> Vec<String> {
vec!["b:private".to_string()]
}
fn handlefeatures(_m: *const module, _f: &Mutex<features>, enables: &mut Option<Vec<i32>>) -> i32 {
if enables.is_none() {
*enables = Some(vec![1; 1]);
}
0
}
fn setfeatureenables(_m: *const module, _f: &Mutex<features>, _e: Option<&[i32]>) -> i32 {
0
}
fn module_features() -> &'static Mutex<features> {
MODULE_FEATURES.get_or_init(|| {
Mutex::new(features {
bn_list: None,
bn_size: 1,
cd_list: None,
cd_size: 0,
mf_list: None,
mf_size: 0,
pd_list: None,
pd_size: 0,
n_abstract: 0,
})
})
}
#[cfg(test)]
mod tests {
use super::*;
fn empty_ops_pp() -> options {
options {
ind: [0u8; MAX_OPS],
args: Vec::new(),
argscount: 0,
argsalloc: 0,
}
}
#[test]
fn bin_private_no_args_returns_zero() {
let _g = crate::test_util::global_state_lock();
let mut ops = empty_ops_pp();
let mut assigns: Vec<(String, String)> = Vec::new();
assert_eq!(bin_private("private", &[], &ops, 0), 0);
}
#[test]
fn bin_private_scalar_assign() {
let _g = crate::test_util::global_state_lock();
let mut ops = empty_ops_pp();
ops.ind[b'P' as usize] = 1;
let r = bin_private("private", &["foo=bar".to_string()], &ops, 0);
assert_eq!(r, 0);
}
#[test]
fn bin_private_minus_p_minus_t_refused() {
let _g = crate::test_util::global_state_lock();
let mut ops = empty_ops_pp();
ops.ind[b'P' as usize] = 1;
ops.ind[b'T' as usize] = 1;
let mut assigns: Vec<(String, String)> = Vec::new();
assert_eq!(bin_private("private", &[], &ops, 0), 1);
}
#[test]
fn module_loaders_return_zero() {
let _g = crate::test_util::global_state_lock();
let m: *const module = std::ptr::null();
let mut features: Vec<String> = Vec::new();
let mut enables: Option<Vec<i32>> = None;
assert_eq!(setup_(m), 0);
assert_eq!(features_(m, &mut features), 0);
assert_eq!(enables_(m, &mut enables), 0);
assert_eq!(boot_(m), 0);
assert_eq!(cleanup_(m), 0);
assert_eq!(finish_(m), 0);
}
#[test]
fn is_private_on_null_returns_zero() {
let _g = crate::test_util::global_state_lock();
assert_eq!(is_private(std::ptr::null()), 0);
}
#[test]
fn is_private_for_unregistered_param_returns_zero() {
let _g = crate::test_util::global_state_lock();
let pm = param {
node: hashnode {
next: None,
nam: "__not_private__".to_string(),
flags: 0,
},
u_data: 0,
u_arr: None,
u_str: None,
u_val: 0,
u_dval: 0.0,
u_hash: None,
gsu_s: None,
gsu_i: None,
gsu_f: None,
gsu_a: None,
gsu_h: None,
base: 0,
width: 0,
env: None,
ename: None,
old: None,
level: 0,
};
assert_eq!(is_private(&pm as *const _), 0);
}
#[test]
fn bin_private_minus_p_minus_t_currently_passes_through() {
let _g = crate::test_util::global_state_lock();
let mut ops = empty_ops_pp();
ops.ind[b'P' as usize] = 1;
ops.ind[b't' as usize] = 1;
let r = bin_private("private", &["foo=bar".to_string()], &ops, 0);
assert!(r == 0 || r == 1, "got unexpected exit code {}", r);
}
#[test]
fn makeprivate_on_null_is_safe() {
let _g = crate::test_util::global_state_lock();
makeprivate(std::ptr::null_mut(), 0);
}
#[test]
fn setfn_error_on_null_is_safe() {
let _g = crate::test_util::global_state_lock();
setfn_error(std::ptr::null_mut());
}
#[test]
fn pps_getfn_on_null_returns_empty() {
let _g = crate::test_util::global_state_lock();
let r = pps_getfn(std::ptr::null_mut());
assert_eq!(r, "", "pps_getfn(NULL) must return empty");
}
#[test]
fn ppi_getfn_on_null_returns_zero() {
let _g = crate::test_util::global_state_lock();
let r = ppi_getfn(std::ptr::null_mut());
assert_eq!(r, 0, "ppi_getfn(NULL) must return 0");
}
#[test]
fn ppf_getfn_on_null_returns_zero_float() {
let _g = crate::test_util::global_state_lock();
let r = ppf_getfn(std::ptr::null_mut());
assert_eq!(r, 0.0, "ppf_getfn(NULL) must return 0.0");
}
#[test]
fn ppa_getfn_on_null_returns_empty_vec() {
let _g = crate::test_util::global_state_lock();
let r = ppa_getfn(std::ptr::null_mut());
assert!(r.is_empty(), "ppa_getfn(NULL) must yield empty Vec");
}
#[test]
fn all_set_callbacks_accept_null_safely() {
let _g = crate::test_util::global_state_lock();
pps_setfn(std::ptr::null_mut(), "value");
ppi_setfn(std::ptr::null_mut(), 42);
ppf_setfn(std::ptr::null_mut(), 3.14);
ppa_setfn(std::ptr::null_mut(), vec!["a".to_string()]);
}
#[test]
fn all_unset_callbacks_accept_null_safely() {
let _g = crate::test_util::global_state_lock();
pps_unsetfn(std::ptr::null_mut(), 0);
ppi_unsetfn(std::ptr::null_mut(), 0);
ppf_unsetfn(std::ptr::null_mut(), 0);
ppa_unsetfn(std::ptr::null_mut(), 0);
pph_unsetfn(std::ptr::null_mut(), 0);
}
#[test]
fn module_lifecycle_shims_all_return_zero() {
let _g = crate::test_util::global_state_lock();
let m: *const module = std::ptr::null();
assert_eq!(setup_(m), 0);
assert_eq!(boot_(m), 0);
assert_eq!(cleanup_(m), 0);
assert_eq!(finish_(m), 0);
}
#[test]
fn param_private_corpus_is_private_null_returns_zero() {
let _g = crate::test_util::global_state_lock();
assert_eq!(is_private(std::ptr::null()), 0);
}
#[test]
fn param_private_corpus_setfn_error_null_no_panic() {
let _g = crate::test_util::global_state_lock();
setfn_error(std::ptr::null_mut());
}
#[test]
fn param_private_corpus_pps_getfn_null_returns_empty() {
let _g = crate::test_util::global_state_lock();
let s = pps_getfn(std::ptr::null_mut());
assert!(s.is_empty(), "null pm → empty string, got {s:?}");
}
#[test]
fn param_private_corpus_ppi_getfn_null_returns_zero() {
let _g = crate::test_util::global_state_lock();
assert_eq!(ppi_getfn(std::ptr::null_mut()), 0);
}
#[test]
fn pps_setfn_on_null_is_safe() {
let _g = crate::test_util::global_state_lock();
pps_setfn(std::ptr::null_mut(), "anything");
}
#[test]
fn pps_unsetfn_on_null_is_safe() {
let _g = crate::test_util::global_state_lock();
pps_unsetfn(std::ptr::null_mut(), 0);
}
#[test]
fn ppi_setfn_on_null_is_safe() {
let _g = crate::test_util::global_state_lock();
ppi_setfn(std::ptr::null_mut(), 42);
}
#[test]
fn ppi_unsetfn_on_null_is_safe() {
let _g = crate::test_util::global_state_lock();
ppi_unsetfn(std::ptr::null_mut(), 0);
}
#[test]
fn ppf_setfn_on_null_is_safe() {
let _g = crate::test_util::global_state_lock();
ppf_setfn(std::ptr::null_mut(), 3.14);
}
#[test]
fn ppf_unsetfn_on_null_is_safe() {
let _g = crate::test_util::global_state_lock();
ppf_unsetfn(std::ptr::null_mut(), 0);
}
#[test]
fn ppa_setfn_on_null_is_safe() {
let _g = crate::test_util::global_state_lock();
ppa_setfn(std::ptr::null_mut(), vec!["x".to_string()]);
}
#[test]
fn is_private_null_returns_zero_redundant_pin() {
let _g = crate::test_util::global_state_lock();
assert_eq!(is_private(std::ptr::null()), 0);
}
#[test]
fn makeprivate_null_pm_safe() {
let _g = crate::test_util::global_state_lock();
makeprivate(std::ptr::null_mut(), 0);
}
#[test]
fn setfn_error_null_safe() {
let _g = crate::test_util::global_state_lock();
setfn_error(std::ptr::null_mut());
}
#[test]
fn pps_getfn_null_returns_empty() {
let _g = crate::test_util::global_state_lock();
assert_eq!(pps_getfn(std::ptr::null_mut()), "");
}
#[test]
fn ppi_getfn_null_returns_zero() {
let _g = crate::test_util::global_state_lock();
assert_eq!(ppi_getfn(std::ptr::null_mut()), 0);
}
#[test]
fn ppf_getfn_null_returns_zero_float() {
let _g = crate::test_util::global_state_lock();
assert_eq!(ppf_getfn(std::ptr::null_mut()), 0.0);
}
#[test]
fn ppa_getfn_null_returns_empty_vec() {
let _g = crate::test_util::global_state_lock();
let v = ppa_getfn(std::ptr::null_mut());
assert!(v.is_empty());
}
#[test]
fn ppi_setfn_null_safe() {
let _g = crate::test_util::global_state_lock();
ppi_setfn(std::ptr::null_mut(), 42);
}
#[test]
fn ppf_setfn_null_safe() {
let _g = crate::test_util::global_state_lock();
ppf_setfn(std::ptr::null_mut(), 3.14);
}
#[test]
fn ppi_unsetfn_null_safe() {
let _g = crate::test_util::global_state_lock();
ppi_unsetfn(std::ptr::null_mut(), 0);
}
#[test]
fn pps_setfn_null_safe() {
let _g = crate::test_util::global_state_lock();
pps_setfn(std::ptr::null_mut(), "x");
}
#[test]
fn pps_unsetfn_null_safe() {
let _g = crate::test_util::global_state_lock();
pps_unsetfn(std::ptr::null_mut(), 0);
}
#[test]
fn is_private_unregistered_param_returns_zero() {
let _g = crate::test_util::global_state_lock();
use crate::ported::zsh_h::{hashnode, param};
let pm = Box::new(param {
node: hashnode {
next: None,
nam: "zshrs_never_registered_param_xyz".to_string(),
flags: 0,
},
u_data: 0,
u_arr: None,
u_str: None,
u_val: 0,
u_dval: 0.0,
u_hash: None,
gsu_s: None,
gsu_i: None,
gsu_f: None,
gsu_a: None,
gsu_h: None,
base: 0,
width: 0,
env: None,
ename: None,
old: None,
level: 0,
});
let ptr: *const param = Box::into_raw(pm);
let r = is_private(ptr);
unsafe {
drop(Box::from_raw(ptr as *mut param));
}
assert_eq!(r, 0, "unregistered param → not private");
}
#[test]
fn is_private_null_deterministic_full_sweep() {
let _g = crate::test_util::global_state_lock();
for _ in 0..10 {
assert_eq!(is_private(std::ptr::null()), 0);
}
}
#[test]
fn is_private_returns_i32_type() {
let _g = crate::test_util::global_state_lock();
let _: i32 = is_private(std::ptr::null());
}
#[test]
fn pps_getfn_returns_string_type() {
let _g = crate::test_util::global_state_lock();
let _: String = pps_getfn(std::ptr::null_mut());
}
#[test]
fn ppi_getfn_returns_i64_type() {
let _g = crate::test_util::global_state_lock();
let _: i64 = ppi_getfn(std::ptr::null_mut());
}
#[test]
fn ppf_getfn_returns_f64_type() {
let _g = crate::test_util::global_state_lock();
let _: f64 = ppf_getfn(std::ptr::null_mut());
}
#[test]
fn ppa_getfn_returns_vec_string_type() {
let _g = crate::test_util::global_state_lock();
let _: Vec<String> = ppa_getfn(std::ptr::null_mut());
}
#[test]
fn pps_getfn_null_is_deterministic() {
let _g = crate::test_util::global_state_lock();
let first = pps_getfn(std::ptr::null_mut());
for _ in 0..5 {
assert_eq!(pps_getfn(std::ptr::null_mut()), first);
}
}
#[test]
fn ppi_getfn_null_is_deterministic() {
let _g = crate::test_util::global_state_lock();
let first = ppi_getfn(std::ptr::null_mut());
for _ in 0..5 {
assert_eq!(ppi_getfn(std::ptr::null_mut()), first);
}
}
#[test]
fn ppf_getfn_null_bitwise_deterministic() {
let _g = crate::test_util::global_state_lock();
let first = ppf_getfn(std::ptr::null_mut());
for _ in 0..5 {
assert_eq!(ppf_getfn(std::ptr::null_mut()).to_bits(), first.to_bits());
}
}
#[test]
fn ppa_getfn_null_is_deterministic() {
let _g = crate::test_util::global_state_lock();
let first = ppa_getfn(std::ptr::null_mut());
for _ in 0..5 {
assert_eq!(ppa_getfn(std::ptr::null_mut()), first);
}
}
#[test]
fn is_private_returns_i32_type_pin2() {
let _g = crate::test_util::global_state_lock();
let _: i32 = is_private(std::ptr::null());
}
#[test]
fn is_private_null_is_deterministic() {
let _g = crate::test_util::global_state_lock();
let first = is_private(std::ptr::null());
for _ in 0..5 {
assert_eq!(
is_private(std::ptr::null()),
first,
"is_private(null) must be deterministic"
);
}
}
#[test]
fn setfn_error_null_idempotent() {
let _g = crate::test_util::global_state_lock();
for _ in 0..5 {
setfn_error(std::ptr::null_mut());
}
}
#[test]
fn scopeprivate_null_both_onoff_safe() {
let _g = crate::test_util::global_state_lock();
scopeprivate(std::ptr::null_mut(), 0);
scopeprivate(std::ptr::null_mut(), 1);
}
#[test]
fn scopeprivate_idempotent() {
let _g = crate::test_util::global_state_lock();
for _ in 0..10 {
scopeprivate(std::ptr::null_mut(), 0);
}
}
#[test]
fn getprivatenode_null_returns_null_pin() {
let _g = crate::test_util::global_state_lock();
let p = getprivatenode(std::ptr::null_mut());
assert!(p.is_null(), "null in → null out");
}
#[test]
fn getprivatenode2_null_returns_null_pin() {
let _g = crate::test_util::global_state_lock();
let p = getprivatenode2(std::ptr::null_mut());
assert!(p.is_null(), "null in → null out");
}
#[test]
fn getprivatenode_variants_deterministic_on_null() {
let _g = crate::test_util::global_state_lock();
for _ in 0..5 {
assert!(getprivatenode(std::ptr::null_mut()).is_null());
assert!(getprivatenode2(std::ptr::null_mut()).is_null());
}
}
#[test]
fn printprivatenode_null_with_various_flags_safe() {
let _g = crate::test_util::global_state_lock();
for flags in [0i32, 1, -1, i32::MIN, i32::MAX] {
printprivatenode(std::ptr::null_mut(), flags);
}
}
#[test]
fn pph_getfn_returns_option_unit_type() {
let _g = crate::test_util::global_state_lock();
let _: Option<()> = pph_getfn(std::ptr::null_mut());
}
#[test]
fn pps_setfn_null_is_safe() {
let _g = crate::test_util::global_state_lock();
pps_setfn(std::ptr::null_mut(), "");
pps_setfn(std::ptr::null_mut(), "any value");
}
#[test]
fn ppi_setfn_null_is_safe() {
let _g = crate::test_util::global_state_lock();
ppi_setfn(std::ptr::null_mut(), 0);
ppi_setfn(std::ptr::null_mut(), i64::MAX);
ppi_setfn(std::ptr::null_mut(), i64::MIN);
}
#[test]
fn ppf_setfn_null_is_safe() {
let _g = crate::test_util::global_state_lock();
ppf_setfn(std::ptr::null_mut(), 0.0);
ppf_setfn(std::ptr::null_mut(), f64::INFINITY);
ppf_setfn(std::ptr::null_mut(), f64::NAN);
}
#[test]
fn ppa_setfn_null_is_safe() {
let _g = crate::test_util::global_state_lock();
ppa_setfn(std::ptr::null_mut(), vec![]);
ppa_setfn(std::ptr::null_mut(), vec!["a".into(), "b".into()]);
}
#[test]
fn is_private_null_returns_zero() {
let _g = crate::test_util::global_state_lock();
assert_eq!(
is_private(std::ptr::null()),
0,
"null param is not private; got nonzero"
);
}
#[test]
fn is_private_returns_i32_pin_alt() {
let _g = crate::test_util::global_state_lock();
let _: i32 = is_private(std::ptr::null());
}
#[test]
fn pps_getfn_null_returns_string_type() {
let _g = crate::test_util::global_state_lock();
let _: String = pps_getfn(std::ptr::null_mut());
}
#[test]
fn ppi_getfn_null_returns_i64_type() {
let _g = crate::test_util::global_state_lock();
let _: i64 = ppi_getfn(std::ptr::null_mut());
}
#[test]
fn ppf_getfn_null_returns_f64_type() {
let _g = crate::test_util::global_state_lock();
let _: f64 = ppf_getfn(std::ptr::null_mut());
}
#[test]
fn ppa_getfn_null_returns_vec_string_type() {
let _g = crate::test_util::global_state_lock();
let _: Vec<String> = ppa_getfn(std::ptr::null_mut());
}
#[test]
fn all_unsetfn_variants_null_both_explicit_flags_safe() {
let _g = crate::test_util::global_state_lock();
for explicit in [0i32, 1] {
pps_unsetfn(std::ptr::null_mut(), explicit);
ppi_unsetfn(std::ptr::null_mut(), explicit);
ppf_unsetfn(std::ptr::null_mut(), explicit);
ppa_unsetfn(std::ptr::null_mut(), explicit);
pph_unsetfn(std::ptr::null_mut(), explicit);
}
}
#[test]
fn scopeprivate_null_both_onoff_alt_pin() {
let _g = crate::test_util::global_state_lock();
scopeprivate(std::ptr::null_mut(), 0);
scopeprivate(std::ptr::null_mut(), 1);
}
#[test]
fn getprivatenode_null_is_deterministic() {
let _g = crate::test_util::global_state_lock();
for _ in 0..10 {
assert!(getprivatenode(std::ptr::null_mut()).is_null());
}
}
#[test]
fn getprivatenode2_null_is_deterministic() {
let _g = crate::test_util::global_state_lock();
for _ in 0..10 {
assert!(getprivatenode2(std::ptr::null_mut()).is_null());
}
}
#[test]
fn param_private_each_lifecycle_hook_returns_zero_individually() {
let _g = crate::test_util::global_state_lock();
let null = std::ptr::null();
let mut v: Vec<String> = Vec::new();
let mut e: Option<Vec<i32>> = None;
assert_eq!(setup_(null), 0, "c:1005 setup_");
assert_eq!(features_(null, &mut v), 0, "c:1020 features_");
assert_eq!(enables_(null, &mut e), 0, "c:1035 enables_");
assert_eq!(boot_(null), 0, "c:1041 boot_");
assert_eq!(cleanup_(null), 0, "c:1058 cleanup_");
assert_eq!(finish_(null), 0, "c:1064 finish_");
}
}