#![allow(
clippy::module_name_repetitions,
clippy::too_many_lines,
clippy::too_many_arguments,
clippy::map_unwrap_or,
clippy::option_if_let_else,
clippy::elidable_lifetime_names,
clippy::items_after_statements,
clippy::needless_pass_by_value,
clippy::single_match_else,
clippy::manual_let_else,
clippy::match_same_arms,
clippy::missing_const_for_fn,
clippy::single_char_pattern,
clippy::naive_bytecount,
clippy::expect_used,
clippy::redundant_pub_crate,
clippy::used_underscore_binding,
clippy::redundant_field_names,
clippy::struct_field_names,
clippy::redundant_else,
clippy::similar_names
)]
use super::Edge;
pub(crate) struct ChildCursor<'a> {
pub(crate) edges: &'a [&'a Edge],
pub(crate) consumed: Vec<bool>,
}
impl<'a> ChildCursor<'a> {
pub(crate) fn new(edges: &'a [&'a Edge]) -> Self {
Self {
edges,
consumed: vec![false; edges.len()],
}
}
pub(crate) fn take_field(&mut self, field_name: &str) -> Option<&'a Edge> {
for (i, edge) in self.edges.iter().enumerate() {
if !self.consumed[i] && edge.kind.as_ref() == field_name {
self.consumed[i] = true;
return Some(edge);
}
}
None
}
pub(crate) fn has_field(&self, field_name: &str) -> bool {
self.peek_field(field_name).is_some()
}
pub(crate) fn peek_field(&self, field_name: &str) -> Option<&'a Edge> {
self.edges
.iter()
.enumerate()
.find(|(i, edge)| !self.consumed[*i] && edge.kind.as_ref() == field_name)
.map(|(_, edge)| *edge)
}
#[cfg(test)]
pub(crate) fn has_matching(&self, predicate: impl Fn(&Edge) -> bool) -> bool {
self.edges
.iter()
.enumerate()
.any(|(i, edge)| !self.consumed[i] && predicate(edge))
}
pub(crate) fn take_matching(&mut self, predicate: impl Fn(&Edge) -> bool) -> Option<&'a Edge> {
for (i, edge) in self.edges.iter().enumerate() {
if !self.consumed[i] && predicate(edge) {
self.consumed[i] = true;
return Some(edge);
}
}
None
}
}
thread_local! {
pub(crate) static EMIT_DEPTH: std::cell::Cell<usize> = const { std::cell::Cell::new(0) };
pub(crate) static EMIT_MU_FRAMES: std::cell::RefCell<std::collections::HashSet<(String, String, usize)>> =
std::cell::RefCell::new(std::collections::HashSet::new());
pub(crate) static EMIT_FIELD_CONTEXT: std::cell::RefCell<Option<String>> =
const { std::cell::RefCell::new(None) };
pub(crate) static EMIT_PTRACE_BUDGET: std::cell::RefCell<std::collections::HashMap<String, usize>> =
std::cell::RefCell::new(std::collections::HashMap::new());
pub(crate) static EMIT_PTRACE_BUDGET_OWNER: std::cell::RefCell<Option<panproto_gat::Name>> =
const { std::cell::RefCell::new(None) };
}
pub(crate) struct PtraceBudgetGuard {
prev_budget: std::collections::HashMap<String, usize>,
prev_owner: Option<panproto_gat::Name>,
}
impl Drop for PtraceBudgetGuard {
fn drop(&mut self) {
EMIT_PTRACE_BUDGET.with(|b| *b.borrow_mut() = std::mem::take(&mut self.prev_budget));
EMIT_PTRACE_BUDGET_OWNER.with(|o| *o.borrow_mut() = self.prev_owner.take());
}
}
pub(crate) fn enter_ptrace_budget(
owner: &panproto_gat::Name,
budget: std::collections::HashMap<String, usize>,
) -> Option<PtraceBudgetGuard> {
if is_ptrace_budget_owner(owner) {
return None;
}
let prev_budget = EMIT_PTRACE_BUDGET.with(|b| std::mem::replace(&mut *b.borrow_mut(), budget));
let prev_owner = EMIT_PTRACE_BUDGET_OWNER.with(|o| o.borrow_mut().replace(owner.clone()));
Some(PtraceBudgetGuard {
prev_budget,
prev_owner,
})
}
pub(crate) fn is_ptrace_budget_owner(vertex_id: &panproto_gat::Name) -> bool {
EMIT_PTRACE_BUDGET_OWNER
.with(|o| {
o.borrow()
.as_ref()
.map(|n| n.as_str() == vertex_id.as_str())
})
.unwrap_or(false)
}
pub(crate) fn ptrace_budget_allows(literal: &str) -> bool {
EMIT_PTRACE_BUDGET.with(|b| b.borrow().get(literal).is_none_or(|&rem| rem > 0))
}
pub(crate) fn ptrace_budget_consume(literal: &str) {
EMIT_PTRACE_BUDGET.with(|b| {
if let Some(rem) = b.borrow_mut().get_mut(literal) {
*rem = rem.saturating_sub(1);
}
});
}
pub(crate) fn snapshot_ptrace_budget() -> std::collections::HashMap<String, usize> {
EMIT_PTRACE_BUDGET.with(|b| b.borrow().clone())
}
pub(crate) fn restore_ptrace_budget(snap: std::collections::HashMap<String, usize>) {
EMIT_PTRACE_BUDGET.with(|b| *b.borrow_mut() = snap);
}
pub(crate) struct FieldContextGuard(Option<String>);
impl Drop for FieldContextGuard {
fn drop(&mut self) {
EMIT_FIELD_CONTEXT.with(|f| *f.borrow_mut() = self.0.take());
}
}
pub(crate) fn push_field_context(name: &str) -> FieldContextGuard {
let prev = EMIT_FIELD_CONTEXT.with(|f| f.borrow_mut().replace(name.to_owned()));
FieldContextGuard(prev)
}
pub(crate) fn clear_field_context() -> FieldContextGuard {
let prev = EMIT_FIELD_CONTEXT.with(|f| f.borrow_mut().take());
FieldContextGuard(prev)
}
pub(crate) fn current_field_context() -> Option<String> {
EMIT_FIELD_CONTEXT.with(|f| f.borrow().clone())
}