use std::collections::HashSet;
use std::sync::{OnceLock, RwLock};
use crate::state::AppState;
fn allowed_set() -> &'static RwLock<HashSet<String>> {
static ALLOWED: OnceLock<RwLock<HashSet<String>>> = OnceLock::new();
ALLOWED.get_or_init(|| RwLock::new(HashSet::new()))
}
#[must_use]
pub fn is_allowed(name: &str) -> bool {
allowed_set().read().ok().is_none_or(|s| s.contains(name))
}
pub fn set_allowed_only_selected(app: &AppState) {
if let Some(sel) = app.results.get(app.selected)
&& let Ok(mut w) = allowed_set().write()
{
w.clear();
w.insert(sel.name.clone());
}
}
pub fn set_allowed_ring(app: &AppState, radius: usize) {
let mut ring: HashSet<String> = HashSet::new();
if let Some(sel) = app.results.get(app.selected) {
ring.insert(sel.name.clone());
}
let len = app.results.len();
let mut step = 1usize;
while step <= radius {
if let Some(i) = app.selected.checked_sub(step)
&& let Some(it) = app.results.get(i)
{
ring.insert(it.name.clone());
}
let below = app.selected + step;
if below < len
&& let Some(it) = app.results.get(below)
{
ring.insert(it.name.clone());
}
step += 1;
}
if let Ok(mut w) = allowed_set().write() {
*w = ring;
}
}
#[cfg(test)]
mod tests {
use super::*;
fn item_official(name: &str, repo: &str) -> crate::state::PackageItem {
crate::state::PackageItem {
name: name.to_string(),
version: "1.0".to_string(),
description: format!("{name} desc"),
source: crate::state::Source::Official {
repo: repo.to_string(),
arch: "x86_64".to_string(),
},
popularity: None,
out_of_date: None,
orphaned: false,
}
}
#[test]
fn allowed_only_selected_and_ring() {
let app = crate::state::AppState {
results: vec![
item_official("a", "core"),
item_official("b", "extra"),
item_official("c", "extra"),
item_official("d", "other"),
],
selected: 1,
..Default::default()
};
set_allowed_only_selected(&app);
assert!(is_allowed("b"));
assert!(!is_allowed("a") || !is_allowed("c") || !is_allowed("d"));
set_allowed_ring(&app, 1);
assert!(is_allowed("a") || is_allowed("c"));
}
}