use std::fmt;
use std::str::FromStr;
use borsh::{BorshDeserialize, BorshSerialize};
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, BorshSerialize, BorshDeserialize)]
pub struct Pubkey([u8; 32]);
impl fmt::Display for Base58Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Empty => f.write_str("empty base58 string"),
Self::InvalidChar => f.write_str("invalid base58 character"),
Self::InvalidLength => f.write_str("base58 decoded to a length other than 32 bytes"),
}
}
}
impl std::error::Error for Base58Error {}
#[derive(Debug, PartialEq, Eq)]
pub enum Base58Error {
Empty,
InvalidChar,
InvalidLength,
}
impl Pubkey {
pub const fn from_bytes(b: [u8; 32]) -> Self {
Self(b)
}
pub const fn to_bytes(&self) -> [u8; 32] {
self.0
}
pub fn as_bytes(&self) -> &[u8; 32] {
&self.0
}
pub const SYSTEM: Self = Self([0x00; 32]);
pub const MEMO: Self = Self([
0x05, 0x4a, 0x53, 0x5a, 0x99, 0x29, 0x21, 0x06, 0x4d, 0x24, 0xe8, 0x71,
0x60, 0xda, 0x38, 0x7c, 0x7c, 0x35, 0xb5, 0xdd, 0xbc, 0x92, 0xbb, 0x81,
0xe4, 0x1f, 0xa8, 0x40, 0x41, 0x05, 0x44, 0x8d,
]);
pub const SAS: Self = Self([
0x0f, 0x5e, 0x9e, 0xd5, 0x37, 0x1e, 0x2c, 0x70, 0x89, 0x8c, 0xa9, 0xfd,
0x0e, 0x77, 0xc0, 0x06, 0x5c, 0xab, 0x5d, 0xa0, 0x2e, 0x56, 0x67, 0x8b,
0x27, 0x13, 0x38, 0x2a, 0xf3, 0x74, 0x59, 0xb7,
]);
}
impl fmt::Display for Pubkey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&bs58::encode(self.0).into_string())
}
}
impl fmt::Debug for Pubkey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("Pubkey").field(&bs58::encode(self.0).into_string()).finish()
}
}
impl FromStr for Pubkey {
type Err = Base58Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s.is_empty() {
return Err(Base58Error::Empty);
}
let bytes = bs58::decode(s).into_vec().map_err(|_| Base58Error::InvalidChar)?;
if bytes.len() != 32 {
return Err(Base58Error::InvalidLength);
}
let mut arr = [0u8; 32];
arr.copy_from_slice(&bytes);
Ok(Self(arr))
}
}
impl From<[u8; 32]> for Pubkey {
fn from(b: [u8; 32]) -> Self {
Self(b)
}
}
impl From<Pubkey> for [u8; 32] {
fn from(pk: Pubkey) -> Self {
pk.0
}
}
impl AsRef<[u8; 32]> for Pubkey {
fn as_ref(&self) -> &[u8; 32] {
&self.0
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn system_constant_is_all_zero() {
assert_eq!(Pubkey::SYSTEM.to_bytes(), [0x00; 32]);
assert_eq!(Pubkey::SYSTEM.to_string(), "11111111111111111111111111111111");
}
}