use std::fmt::{
self,
Debug,
Display,
Formatter,
};
use std::str::FromStr;
use hiero_sdk_proto::services;
use crate::entity_id::{
Checksum,
ValidateChecksums,
};
use crate::ledger_id::RefLedgerId;
use crate::{
Client,
EntityId,
Error,
FromProtobuf,
ToProtobuf,
};
#[derive(Hash, PartialEq, Eq, Clone, Copy)]
pub struct FileId {
pub shard: u64,
pub realm: u64,
pub num: u64,
pub checksum: Option<Checksum>,
}
impl FileId {
#[deprecated(note = "use `get_address_book_file_id_for` instead")]
pub const ADDRESS_BOOK: Self = Self::new(0, 0, 102);
#[deprecated(note = "use `get_fee_schedule_file_id_for` instead")]
pub const FEE_SCHEDULE: Self = Self::new(0, 0, 111);
#[deprecated(note = "use `get_exchange_rates_file_id_for` instead")]
pub const EXCHANGE_RATES: Self = Self::new(0, 0, 112);
pub const fn new(shard: u64, realm: u64, num: u64) -> Self {
Self { shard, realm, num, checksum: None }
}
pub fn get_address_book_file_id_for(realm: u64, shard: u64) -> Self {
let address_book_num = 102;
Self::new(shard, realm, address_book_num)
}
pub fn get_fee_schedule_file_id_for(realm: u64, shard: u64) -> Self {
let fee_schedule_num = 111;
Self::new(shard, realm, fee_schedule_num)
}
pub fn get_exchange_rates_file_id_for(realm: u64, shard: u64) -> Self {
let exchange_rates_num = 112;
Self::new(shard, realm, exchange_rates_num)
}
pub fn from_bytes(bytes: &[u8]) -> crate::Result<Self> {
FromProtobuf::from_bytes(bytes)
}
pub fn from_solidity_address(address: &str) -> crate::Result<Self> {
let EntityId { shard, realm, num, checksum } = EntityId::from_solidity_address(address)?;
Ok(Self { shard, realm, num, checksum })
}
#[must_use]
pub fn to_bytes(&self) -> Vec<u8> {
ToProtobuf::to_bytes(self)
}
pub fn to_solidity_address(&self) -> crate::Result<String> {
EntityId { shard: self.shard, realm: self.realm, num: self.num, checksum: None }
.to_solidity_address()
}
#[must_use]
pub fn to_string_with_checksum(&self, client: &Client) -> String {
EntityId::to_string_with_checksum(self.to_string(), client)
}
pub fn validate_checksum(&self, client: &Client) -> Result<(), Error> {
EntityId::validate_checksum(self.shard, self.realm, self.num, self.checksum, client)
}
}
impl ValidateChecksums for FileId {
fn validate_checksums(&self, ledger_id: &RefLedgerId) -> Result<(), Error> {
EntityId::validate_checksum_for_ledger_id(
self.shard,
self.realm,
self.num,
self.checksum,
ledger_id,
)
}
}
impl Debug for FileId {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "\"{self}\"")
}
}
impl Display for FileId {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{}.{}.{}", self.shard, self.realm, self.num)
}
}
impl FromProtobuf<services::FileId> for FileId {
fn from_protobuf(pb: services::FileId) -> crate::Result<Self> {
Ok(Self {
num: pb.file_num as u64,
shard: pb.shard_num as u64,
realm: pb.realm_num as u64,
checksum: None,
})
}
}
impl ToProtobuf for FileId {
type Protobuf = services::FileId;
fn to_protobuf(&self) -> Self::Protobuf {
services::FileId {
file_num: self.num as i64,
realm_num: self.realm as i64,
shard_num: self.shard as i64,
}
}
}
impl From<u64> for FileId {
fn from(num: u64) -> Self {
Self { num, shard: 0, realm: 0, checksum: None }
}
}
impl FromStr for FileId {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
EntityId::from_str(s).map(Self::from)
}
}
impl From<EntityId> for FileId {
fn from(value: EntityId) -> Self {
let EntityId { shard, realm, num, checksum } = value;
Self { shard, realm, num, checksum }
}
}
#[cfg(test)]
mod tests {
use crate::FileId;
#[test]
fn should_serialize_from_string() {
assert_eq!("0.0.5005", "0.0.5005".parse::<FileId>().unwrap().to_string());
}
#[test]
fn from_bytes() {
assert_eq!(
"0.0.5005",
FileId::from_bytes(&FileId::new(0, 0, 5005).to_bytes()).unwrap().to_string()
);
}
#[test]
fn from_solidity_address() {
assert_eq!(
"0.0.5005",
FileId::from_solidity_address("000000000000000000000000000000000000138D")
.unwrap()
.to_string()
);
}
#[test]
fn to_solidity_address() {
assert_eq!(
"000000000000000000000000000000000000138d",
FileId::new(0, 0, 5005).to_solidity_address().unwrap()
);
}
}