// Scope evaluation — scope_match and hierarchy traversal.
// Reference: cedar-policy-core/src/evaluator.rs
///|
/// Check whether a scope constraint matches the given entity variable.
pub fn[S : EntityStore] scope_match(
sc : @ast.ScopeConstraint,
uid : @ast.EntityUID,
store : S,
) -> Bool {
match sc {
@ast.ScopeConstraint::All => true
@ast.ScopeConstraint::Eq(euid) => uid == euid
@ast.ScopeConstraint::In(parent) => is_descendant(uid, parent, store)
@ast.ScopeConstraint::InSet(uids) => uids.contains(uid)
@ast.ScopeConstraint::Is(ty) => uid.type_ == ty.0
@ast.ScopeConstraint::IsIn(ty, parent) =>
uid.type_ == ty.0 && is_descendant(uid, parent, store)
}
}
///|
/// Check if `uid` is equal to or a descendant of `ancestor` in the entity hierarchy.
/// Uses BFS to traverse parent chains.
pub fn[S : EntityStore] is_descendant(
uid : @ast.EntityUID,
ancestor : @ast.EntityUID,
store : S,
) -> Bool {
if uid == ancestor {
return true
}
let queue : Array[@ast.EntityUID] = [uid]
let visited : Array[@ast.EntityUID] = []
let mut pos = 0
for ; pos < queue.length(); {
let current = queue[pos]
pos = pos + 1
// Skip if already visited
if visited.contains(current) {
continue
}
visited.push(current)
match store.get_entity(current) {
Some(entity) =>
for parent in entity.parents {
if parent == ancestor {
return true
}
queue.push(parent)
}
None => continue
}
}
false
}