#![doc(html_root_url = "https://docs.rs/ic-cose-types/latest")]
#![allow(clippy::needless_doctest_main)]
use candid::{utils::ArgumentEncoder, CandidType, Principal};
use ciborium::into_writer;
use serde::Serialize;
use std::{collections::BTreeSet, future::Future};
pub mod cose;
pub mod types;
pub use cose::format_error;
pub static ANONYMOUS: Principal = Principal::anonymous();
pub const MILLISECONDS: u64 = 1_000_000u64;
pub fn to_cbor_bytes(obj: &impl Serialize) -> Vec<u8> {
let mut buf: Vec<u8> = Vec::new();
into_writer(obj, &mut buf).expect("failed to encode in CBOR format");
buf
}
pub fn validate_str(s: &str) -> Result<(), String> {
if s.is_empty() {
return Err("empty string".to_string());
}
if s.len() > 64 {
return Err("string length exceeds the limit 64".to_string());
}
for c in s.chars() {
if !matches!(c, 'a'..='z' | '0'..='9' | '_' ) {
return Err(format!("invalid character: {}", c));
}
}
Ok(())
}
pub fn validate_principals(principals: &BTreeSet<Principal>) -> Result<(), String> {
if principals.is_empty() {
return Err("principals cannot be empty".to_string());
}
if principals.contains(&ANONYMOUS) {
return Err("anonymous user is not allowed".to_string());
}
Ok(())
}
pub type BoxError = Box<dyn std::error::Error + Send + Sync>;
pub trait CanisterCaller: Sized {
fn canister_query<
In: ArgumentEncoder + Send,
Out: CandidType + for<'a> candid::Deserialize<'a>,
>(
&self,
canister: &Principal,
method: &str,
args: In,
) -> impl Future<Output = Result<Out, BoxError>> + Send;
fn canister_update<
In: ArgumentEncoder + Send,
Out: CandidType + for<'a> candid::Deserialize<'a>,
>(
&self,
canister: &Principal,
method: &str,
args: In,
) -> impl Future<Output = Result<Out, BoxError>> + Send;
}