use ic_platform::candid::contract::Principal;
use thiserror::Error as ThisError;
#[derive(Clone, Debug, Eq, PartialEq, ThisError)]
#[error("invalid SNS root principal: {input}")]
pub struct SnsLookupError {
pub input: String,
}
#[derive(Clone, Debug, Eq, PartialEq)]
enum SnsLookupTarget {
Id(usize),
Root(Principal),
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct SnsLookupRequest {
pub network: String,
pub source_endpoint: String,
pub now_unix_secs: u64,
input: String,
target: SnsLookupTarget,
}
impl SnsLookupRequest {
pub fn new(
network: impl Into<String>,
source_endpoint: impl Into<String>,
now_unix_secs: u64,
input: impl Into<String>,
) -> Result<Self, SnsLookupError> {
let input = input.into();
let target = match input.parse::<usize>() {
Ok(id) => SnsLookupTarget::Id(id),
Err(_) => {
SnsLookupTarget::Root(Principal::from_text(&input).map_err(|_| SnsLookupError {
input: input.clone(),
})?)
}
};
Ok(Self {
network: network.into(),
source_endpoint: source_endpoint.into(),
now_unix_secs,
input,
target,
})
}
#[must_use]
pub fn input(&self) -> &str {
&self.input
}
#[must_use]
pub const fn id(&self) -> Option<usize> {
match self.target {
SnsLookupTarget::Id(id) => Some(id),
SnsLookupTarget::Root(_) => None,
}
}
#[must_use]
pub const fn root_canister_id(&self) -> Option<&Principal> {
match &self.target {
SnsLookupTarget::Root(root) => Some(root),
SnsLookupTarget::Id(_) => None,
}
}
}
#[cfg(test)]
mod tests;