use std::fmt;
use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error as _};
use crate::base58::DecodeBase58Error;
pub const SIGNATURE_BYTES: usize = 64;
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct SignatureBytes([u8; SIGNATURE_BYTES]);
impl SignatureBytes {
#[must_use]
pub const fn new(bytes: [u8; SIGNATURE_BYTES]) -> Self {
Self(bytes)
}
#[must_use]
pub const fn into_array(self) -> [u8; SIGNATURE_BYTES] {
self.0
}
#[must_use]
pub const fn as_array(&self) -> &[u8; SIGNATURE_BYTES] {
&self.0
}
pub fn from_base58(value: &str) -> Result<Self, DecodeBase58Error> {
let decoded =
bs58::decode(value)
.into_vec()
.map_err(|error| DecodeBase58Error::InvalidBase58 {
message: error.to_string(),
})?;
let bytes: [u8; SIGNATURE_BYTES] =
decoded
.try_into()
.map_err(|decoded: Vec<u8>| DecodeBase58Error::WrongLength {
expected: SIGNATURE_BYTES,
actual: decoded.len(),
})?;
Ok(Self(bytes))
}
#[must_use]
pub fn to_base58(self) -> String {
bs58::encode(self.0).into_string()
}
}
impl From<[u8; SIGNATURE_BYTES]> for SignatureBytes {
fn from(value: [u8; SIGNATURE_BYTES]) -> Self {
Self::new(value)
}
}
impl From<SignatureBytes> for [u8; SIGNATURE_BYTES] {
fn from(value: SignatureBytes) -> Self {
value.into_array()
}
}
impl fmt::Display for SignatureBytes {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.to_base58())
}
}
impl Serialize for SignatureBytes {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_bytes(&self.0)
}
}
impl<'de> Deserialize<'de> for SignatureBytes {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let bytes = Vec::<u8>::deserialize(deserializer)?;
let signature: [u8; SIGNATURE_BYTES] = bytes
.try_into()
.map_err(|bytes: Vec<u8>| D::Error::invalid_length(bytes.len(), &"64 bytes"))?;
Ok(Self::new(signature))
}
}
#[cfg(feature = "solana-compat")]
impl SignatureBytes {
#[must_use]
pub fn from_solana(value: solana_signature::Signature) -> Self {
Self::new(value.into())
}
#[must_use]
pub fn to_solana(self) -> solana_signature::Signature {
solana_signature::Signature::from(self.into_array())
}
}
#[cfg(feature = "solana-compat")]
impl From<solana_signature::Signature> for SignatureBytes {
fn from(value: solana_signature::Signature) -> Self {
Self::from_solana(value)
}
}
#[cfg(feature = "solana-compat")]
impl From<SignatureBytes> for solana_signature::Signature {
fn from(value: SignatureBytes) -> Self {
value.to_solana()
}
}