use candid::Principal;
const CANISTER_ID_HASH_LEN_IN_BYTES: usize = 10;
const HASH_LEN_IN_BYTES: usize = 28;
const TYPE_SELF_AUTH: u8 = 0x02;
pub fn is_canister(id: &Principal) -> bool {
let blob = id.as_slice();
blob.len() == CANISTER_ID_HASH_LEN_IN_BYTES
}
pub fn is_user_principal(id: &Principal) -> bool {
let blob = id.as_slice();
if blob.len() != HASH_LEN_IN_BYTES + 1 {
return false;
}
if blob.last() != Some(&TYPE_SELF_AUTH) {
return false;
}
true
}
#[macro_export]
macro_rules! new_type_principal {
($name:ident, $is_canister:expr) => {
#[derive(
CandidType,
Clone,
Copy,
Debug,
PartialEq,
Eq,
Hash,
PartialOrd,
Ord,
Deserialize,
Serialize,
)]
#[serde(transparent)]
pub struct $name(Principal);
impl From<Principal> for $name {
fn from(principal: Principal) -> Self {
Self::new(principal)
}
}
impl From<$name> for Principal {
fn from(t: $name) -> Self {
t.0
}
}
impl $name {
pub fn new(p: Principal) -> Self {
if $is_canister {
if p != Principal::management_canister() {
assert!(
is_canister(&p),
"{}:{} is not a canister",
stringify!($name),
p.to_text()
);
}
} else {
assert!(
is_user_principal(&p),
"{}: {} is not a user principal",
stringify!($name),
p.to_text()
);
}
Self(p)
}
pub fn as_slice(&self) -> &[u8] {
self.0.as_slice()
}
pub fn from_slice(bytes: &[u8]) -> Self {
Self(Principal::from_slice(bytes))
}
pub fn as_ref(&self) -> &Principal {
&self.0
}
pub fn to_text(&self) -> String {
self.0.to_text()
}
pub fn from_text(text: &str) -> Result<Self, String> {
Principal::from_text(text)
.map(Self::new)
.map_err(|e| format!("{}: {:?}", stringify!($name), e))
}
}
impl Storable for $name {
fn to_bytes(&self) -> std::borrow::Cow<[u8]> {
self.0.as_ref().into()
}
fn from_bytes(bytes: std::borrow::Cow<[u8]>) -> Self {
Self(Principal::from_slice(bytes.as_ref()))
}
const BOUND: Bound = Bound::Bounded {
max_size: 29,
is_fixed_size: false,
};
}
impl PartialEq<Principal> for $name {
fn eq(&self, other: &Principal) -> bool {
self.0 == *other
}
}
impl Display for $name {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0.to_text())
}
}
};
}