b3_utils 0.13.1

Utility functions for building on the Internet Computer
Documentation
use std::{cmp, fmt, hash, mem::size_of, str::FromStr};

use candid::Principal;

use crate::constants::DEFAULT_SUBACCOUNT;

use super::{Subaccount, SubaccountError};

impl Default for Subaccount {
    fn default() -> Self {
        DEFAULT_SUBACCOUNT
    }
}

impl Eq for Subaccount {}

impl cmp::PartialOrd for Subaccount {
    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
        Some(self.cmp(other))
    }
}

impl cmp::Ord for Subaccount {
    fn cmp(&self, other: &Self) -> cmp::Ordering {
        self.0.cmp(&other.0)
    }
}

impl hash::Hash for Subaccount {
    fn hash<H: hash::Hasher>(&self, state: &mut H) {
        self.0.hash(state);
    }
}

impl From<Principal> for Subaccount {
    fn from(principal: Principal) -> Self {
        let mut subaccount = [0; size_of::<Subaccount>()];
        let principal_id = principal.as_slice();

        subaccount[0] = principal_id.len().try_into().unwrap();
        subaccount[1..1 + principal_id.len()].copy_from_slice(principal_id);

        Subaccount(subaccount)
    }
}

impl From<[u8; 32]> for Subaccount {
    fn from(bytes: [u8; 32]) -> Self {
        Subaccount(bytes)
    }
}

impl From<Subaccount> for serde_bytes::ByteBuf {
    fn from(subaccount: Subaccount) -> Self {
        serde_bytes::ByteBuf::from(subaccount.0.to_vec())
    }
}

impl From<&Subaccount> for serde_bytes::ByteBuf {
    fn from(subaccount: &Subaccount) -> Self {
        serde_bytes::ByteBuf::from(subaccount.0.to_vec())
    }
}

impl TryFrom<Vec<u8>> for Subaccount {
    type Error = SubaccountError;

    fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
        if value.len() != 32 {
            return Err(SubaccountError::LengthError(value.len()));
        }

        let mut bytes = [0u8; 32];
        bytes.copy_from_slice(&value);

        Ok(Self(bytes))
    }
}

impl FromStr for Subaccount {
    type Err = SubaccountError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        Ok(Self::from_hex(s)?)
    }
}

impl fmt::Display for Subaccount {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        hex::encode(&self.0).fmt(f)
    }
}

use ic_stable_structures::storable::Bound;

impl ic_stable_structures::Storable for Subaccount {
    fn to_bytes(&self) -> std::borrow::Cow<[u8]> {
        self.0.to_bytes()
    }

    fn from_bytes(bytes: std::borrow::Cow<[u8]>) -> Self {
        Subaccount::from_slice(&bytes).unwrap()
    }

    const BOUND: Bound = Bound::Bounded {
        is_fixed_size: true,
        max_size: 32,
    };
}