ockam_abac 0.80.0

Attribute based authorization control
use either::Either;
use minicbor::decode::{self, Decoder};
use minicbor::encode::{self, Encoder, Write};
use minicbor::{CborLen, Decode, Encode};
use ockam_core::compat::string::{String, ToString};
use serde::{Serialize, Serializer};
use str_buf::StrBuf;
use strum::{AsRefStr, Display, EnumIter, EnumString};

macro_rules! define {
    ($t:ident) => {
        #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
        pub struct $t(Either<String, StrBuf<{ Self::MAX_INLINE_SIZE }>>);

        impl $t {
            pub const MAX_INLINE_SIZE: usize = 24;

            pub const fn inline(s: &str) -> Option<Self> {
                if let Ok(s) = StrBuf::from_str_checked(s) {
                    Some(Self(Either::Right(s)))
                } else {
                    None
                }
            }

            pub const fn assert_inline(s: &str) -> Self {
                Self(Either::Right(StrBuf::from_str(s)))
            }

            pub fn new(s: &str) -> Self {
                if s.len() <= Self::MAX_INLINE_SIZE {
                    return Self::assert_inline(s);
                }
                Self(Either::Left(s.to_string()))
            }

            pub fn as_str(&self) -> &str {
                &self.0
            }

            pub fn to_string(&self) -> String {
                self.as_str().to_string()
            }
        }

        impl From<&str> for $t {
            fn from(s: &str) -> Self {
                Self::new(s)
            }
        }

        impl From<String> for $t {
            fn from(s: String) -> Self {
                if s.len() <= Self::MAX_INLINE_SIZE {
                    return Self::assert_inline(&s);
                }
                Self(Either::Left(s))
            }
        }

        impl core::fmt::Display for $t {
            fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
                f.write_str(&self.0)
            }
        }

        impl<C> Encode<C> for $t {
            fn encode<W>(
                &self,
                e: &mut Encoder<W>,
                _: &mut C,
            ) -> Result<(), encode::Error<W::Error>>
            where
                W: Write,
            {
                e.str(self.as_str())?.ok()
            }
        }

        impl<C> CborLen<C> for $t {
            fn cbor_len(&self, ctx: &mut C) -> usize {
                self.as_str().cbor_len(ctx)
            }
        }

        impl<'a, C> Decode<'a, C> for $t {
            fn decode(d: &mut Decoder<'a>, _: &mut C) -> Result<$t, decode::Error> {
                let s = d.str()?;
                Ok($t::new(s))
            }
        }

        impl Serialize for $t {
            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
            where
                S: Serializer,
            {
                serializer.serialize_str(self.as_str())
            }
        }
    };
}

define!(Subject);
define!(ResourceName);

#[derive(
    Clone, Debug, Encode, Decode, CborLen, PartialEq, Eq, EnumString, Display, EnumIter, AsRefStr,
)]
#[cbor(index_only)]
pub enum Action {
    #[n(1)]
    #[strum(serialize = "handle_message")]
    HandleMessage,
}

impl Serialize for Action {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        serializer.serialize_str(self.as_ref())
    }
}