cedarling 0.0.39

The Cedarling: a high-performance local authorization service powered by the Rust Cedar Engine.
Documentation
// This software is available under the Apache-2.0 license.
// See https://www.apache.org/licenses/LICENSE-2.0.txt for full text.
//
// Copyright (c) 2024, Gluu, Inc.

use cedar_policy::{Entity, EntityUid};
use smol_str::{SmolStr, ToSmolStr};
use std::collections::{HashMap, hash_map::Entry};
use url::Origin;

type TypeName = SmolStr;
type TypeId = SmolStr;

/// Stores references to previously built entities.
///
/// Entities are categorized as either:
/// - **Singles**: Unique entities with distinct types.
/// - **Multiples**: Entities of the same type but with different IDs.
#[derive(Default)]
pub(crate) struct BuiltEntities {
    singles: ahash::HashMap<TypeName, TypeId>,
    multiples: ahash::HashMap<TypeName, Vec<TypeId>>,
}

impl FromIterator<EntityUid> for BuiltEntities {
    fn from_iter<T: IntoIterator<Item = EntityUid>>(iter: T) -> Self {
        iter.into_iter().fold(Self::default(), |mut acc, uid| {
            acc.insert(&uid);
            acc
        })
    }
}

impl From<&HashMap<Origin, Entity>> for BuiltEntities {
    fn from(src: &HashMap<Origin, Entity>) -> Self {
        let mut built_entities = BuiltEntities::default();

        for entity in src.values() {
            built_entities.insert(&entity.uid());
        }

        built_entities
    }
}

impl BuiltEntities {
    pub(crate) fn insert(&mut self, uid: &EntityUid) {
        let name = uid.type_name().to_smolstr();
        let id = uid.id().escaped();
        match self.singles.entry(name.clone()) {
            Entry::Occupied(entry) => {
                let exsisting_eid = entry.remove();
                self.multiples
                    .entry(name.clone())
                    .or_default()
                    .extend([exsisting_eid, id]);
            },
            Entry::Vacant(entry) => {
                entry.insert(id);
            },
        }
    }

    pub(crate) fn get_single(&self, type_name: &str) -> Option<&str> {
        self.singles.get(type_name).map(|v| &**v)
    }

    pub(super) fn get_multiple(&self, type_name: &str) -> Option<&[SmolStr]> {
        self.multiples.get(type_name).map(|v| &**v)
    }
}