use crate::entities_json_errors::{JsonDeserializationError, JsonSerializationError};
use crate::ParseErrors;
use cedar_policy_core::ast;
use cedar_policy_core::entities::json::err::JsonDeserializationErrorContext;
use cedar_policy_core::FromNormalizedStr;
use ref_cast::RefCast;
use serde::{Deserialize, Serialize};
use smol_str::SmolStr;
use std::convert::Infallible;
use std::str::FromStr;
#[repr(transparent)]
#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, RefCast)]
pub struct EntityId(ast::Eid);
#[doc(hidden)] impl AsRef<ast::Eid> for EntityId {
fn as_ref(&self) -> &ast::Eid {
&self.0
}
}
impl EntityId {
pub fn new(src: impl AsRef<str>) -> Self {
match src.as_ref().parse() {
Ok(eid) => eid,
Err(infallible) => match infallible {},
}
}
pub fn escaped(&self) -> SmolStr {
self.0.escaped()
}
pub fn unescaped(&self) -> &str {
self.as_ref()
}
}
impl FromStr for EntityId {
type Err = Infallible;
fn from_str(eid_str: &str) -> Result<Self, Self::Err> {
Ok(Self(ast::Eid::new(eid_str)))
}
}
impl AsRef<str> for EntityId {
fn as_ref(&self) -> &str {
self.0.as_ref()
}
}
#[repr(transparent)]
#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, RefCast)]
pub struct EntityTypeName(pub(crate) ast::EntityType);
#[doc(hidden)] impl AsRef<ast::EntityType> for EntityTypeName {
fn as_ref(&self) -> &ast::EntityType {
&self.0
}
}
impl EntityTypeName {
pub fn basename(&self) -> &str {
self.0.as_ref().basename_as_ref().as_ref()
}
pub fn namespace_components(&self) -> impl Iterator<Item = &str> {
self.0
.name()
.as_ref()
.namespace_components()
.map(AsRef::as_ref)
}
pub fn namespace(&self) -> String {
self.0.as_ref().as_ref().namespace()
}
}
impl FromStr for EntityTypeName {
type Err = ParseErrors;
fn from_str(namespace_type_str: &str) -> Result<Self, Self::Err> {
ast::Name::from_normalized_str(namespace_type_str)
.map(|name| Self(ast::EntityType::from(name)))
.map_err(Into::into)
}
}
impl std::fmt::Display for EntityTypeName {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
#[doc(hidden)]
impl From<ast::EntityType> for EntityTypeName {
fn from(ty: ast::EntityType) -> Self {
Self(ty)
}
}
#[repr(transparent)]
#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, RefCast)]
pub struct EntityUid(pub(crate) ast::EntityUID);
#[doc(hidden)] impl AsRef<ast::EntityUID> for EntityUid {
fn as_ref(&self) -> &ast::EntityUID {
&self.0
}
}
impl EntityUid {
pub fn type_name(&self) -> &EntityTypeName {
EntityTypeName::ref_cast(self.0.entity_type())
}
pub fn id(&self) -> &EntityId {
EntityId::ref_cast(self.0.eid())
}
pub fn from_type_name_and_id(name: EntityTypeName, id: EntityId) -> Self {
Self(ast::EntityUID::from_components(name.0, id.0, None))
}
#[expect(
clippy::result_large_err,
reason = "don't want to change the signature of a public function to fix this lint"
)]
pub fn from_json(json: serde_json::Value) -> Result<Self, JsonDeserializationError> {
let parsed: cedar_policy_core::entities::EntityUidJson = serde_json::from_value(json)?;
Ok(parsed
.into_euid(&|| JsonDeserializationErrorContext::EntityUid)?
.into())
}
pub fn to_json_value(&self) -> Result<serde_json::Value, JsonSerializationError> {
let json: cedar_policy_core::entities::EntityUidJson = (&self.0).into();
serde_json::to_value(json).map_err(Into::into)
}
}
#[cfg(test)]
impl EntityUid {
pub(crate) fn from_strs(typename: &str, id: &str) -> Self {
Self::from_type_name_and_id(
EntityTypeName::from_str(typename).unwrap(),
EntityId::from_str(id).unwrap(),
)
}
}
impl FromStr for EntityUid {
type Err = ParseErrors;
fn from_str(uid_str: &str) -> Result<Self, Self::Err> {
ast::EntityUID::from_normalized_str(uid_str)
.map(Into::into)
.map_err(Into::into)
}
}
impl std::fmt::Display for EntityUid {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
#[doc(hidden)]
impl From<EntityUid> for ast::EntityUID {
fn from(uid: EntityUid) -> Self {
uid.0
}
}
#[doc(hidden)]
impl From<ast::EntityUID> for EntityUid {
fn from(uid: ast::EntityUID) -> Self {
Self(uid)
}
}
#[repr(transparent)]
#[derive(Debug, PartialEq, Eq, Clone, Hash, PartialOrd, Ord, Serialize, Deserialize, RefCast)]
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
pub struct PolicyId(#[cfg_attr(feature = "wasm", tsify(type = "string"))] ast::PolicyID);
#[doc(hidden)] impl AsRef<ast::PolicyID> for PolicyId {
fn as_ref(&self) -> &ast::PolicyID {
&self.0
}
}
impl PolicyId {
pub fn new(id: impl AsRef<str>) -> Self {
Self(ast::PolicyID::from_string(id.as_ref()))
}
}
impl FromStr for PolicyId {
type Err = Infallible;
fn from_str(id: &str) -> Result<Self, Self::Err> {
Ok(Self(ast::PolicyID::from_string(id)))
}
}
impl std::fmt::Display for PolicyId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl AsRef<str> for PolicyId {
fn as_ref(&self) -> &str {
self.0.as_ref()
}
}
#[doc(hidden)]
impl From<PolicyId> for ast::PolicyID {
fn from(uid: PolicyId) -> Self {
uid.0
}
}
#[repr(transparent)]
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Hash, RefCast, Serialize, Deserialize)]
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
pub struct SlotId(#[cfg_attr(feature = "wasm", tsify(type = "string"))] ast::SlotId);
#[doc(hidden)] impl AsRef<ast::SlotId> for SlotId {
fn as_ref(&self) -> &ast::SlotId {
&self.0
}
}
impl SlotId {
pub fn principal() -> Self {
Self(ast::SlotId::principal())
}
pub fn resource() -> Self {
Self(ast::SlotId::resource())
}
}
impl std::fmt::Display for SlotId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
#[doc(hidden)]
impl From<ast::SlotId> for SlotId {
fn from(a: ast::SlotId) -> Self {
Self(a)
}
}
#[doc(hidden)]
impl From<SlotId> for ast::SlotId {
fn from(s: SlotId) -> Self {
s.0
}
}