fuel-types 0.66.3

Atomic types of the FuelVM.
Documentation
#![allow(clippy::arithmetic_side_effects)]

use fuel_types::*;
use rand::{
    Rng,
    RngCore,
    SeedableRng,
    rngs::StdRng,
};

use core::{
    fmt,
    str,
};

macro_rules! check_consistency {
    ($i:ident, $r:expr, $b:expr) => {
        let n = $i::LEN;
        let s = $r.gen_range(0..$b.len() - n);
        let e = $r.gen_range(s + n..$b.len());
        let r = $r.gen_range(1..n - 1);
        let i = &$b[s..s + n];

        let a = $i::from_bytes_ref(i.try_into().unwrap());
        let b = $i::from_bytes_ref_checked(&$b[s..e]).unwrap();
        let c = $i::try_from(i).expect("Memory conversion");

        assert!($i::from_bytes_ref_checked(&i[..i.len() - r]).is_none());

        let e = $i::from_bytes_ref_checked(i).unwrap();

        assert_eq!(e.as_ptr(), i.as_ptr());

        assert_eq!(a, b);
        assert_eq!(*a, c);
        assert_eq!(a, e);
        assert_eq!(a.len(), $i::LEN);
        assert_eq!(b.len(), $i::LEN);
        assert_eq!(c.len(), $i::LEN);
        assert_eq!(e.len(), $i::LEN);
    };
}

#[test]
fn from_slice_unchecked_safety() {
    let rng = &mut StdRng::seed_from_u64(8586);

    let mut bytes = [0u8; 257];
    rng.fill_bytes(&mut bytes);

    for _ in 0..100 {
        check_consistency!(Address, rng, bytes);
        check_consistency!(AssetId, rng, bytes);
        check_consistency!(ContractId, rng, bytes);
        check_consistency!(TxId, rng, bytes);
        check_consistency!(Bytes4, rng, bytes);
        check_consistency!(Bytes8, rng, bytes);
        check_consistency!(Bytes20, rng, bytes);
        check_consistency!(Bytes32, rng, bytes);
        check_consistency!(Nonce, rng, bytes);
        check_consistency!(MessageId, rng, bytes);
        check_consistency!(Salt, rng, bytes);
        check_consistency!(Bytes64, rng, bytes);
    }
}

#[test]
fn hex_encoding() {
    fn encode_decode<T>(t: T)
    where
        T: fmt::LowerHex + fmt::UpperHex + str::FromStr + Eq + fmt::Debug + AsRef<[u8]>,
        <T as str::FromStr>::Err: fmt::Debug,
    {
        let lower = format!("{t:x}");
        let lower_w0 = format!("{t:0x}");
        let lower_alternate = format!("{t:#x}");
        let lower_alternate_w0 = format!("{t:#0x}");
        let upper = format!("{t:X}");
        let upper_w0 = format!("{t:0X}");
        let upper_alternate = format!("{t:#X}");
        let upper_alternate_w0 = format!("{t:#X}");

        assert_ne!(lower, lower_alternate);
        assert_ne!(lower, upper);
        assert_ne!(lower, upper_alternate);
        assert_ne!(lower_alternate, upper);
        assert_ne!(lower_alternate, upper_alternate);
        assert_ne!(upper, upper_alternate);

        assert_eq!(lower, lower_w0);
        assert_eq!(lower_alternate, lower_alternate_w0);
        assert_eq!(upper, upper_w0);
        assert_eq!(upper_alternate, upper_alternate_w0);

        let lower = T::from_str(lower.as_str()).expect("Failed to parse lower");
        let lower_alternate = T::from_str(lower_alternate.as_str())
            .expect("Failed to parse lower alternate");
        let upper = T::from_str(upper.as_str()).expect("Failed to parse upper");
        let upper_alternate = T::from_str(upper_alternate.as_str())
            .expect("Failed to parse upper alternate");

        assert_eq!(t, lower);
        assert_eq!(t, lower_alternate);
        assert_eq!(t, upper);
        assert_eq!(t, upper_alternate);

        let reduced = t.as_ref().iter().fold(0u8, |acc, x| acc ^ x);

        let x = hex::encode([reduced]);
        let y = format!("{t:2x}");

        assert_eq!(x, y);

        let x = format!("{t:0x}").len();
        let y = format!("{t:2x}").len();
        let z = format!("{t:4x}").len();

        assert_eq!(t.as_ref().len() * 2, x);
        assert_eq!(2, y);
        assert_eq!(4, z);
    }

    let rng = &mut StdRng::seed_from_u64(8586);

    encode_decode::<Address>(rng.r#gen());
    encode_decode::<AssetId>(rng.r#gen());
    encode_decode::<ContractId>(rng.r#gen());
    encode_decode::<TxId>(rng.r#gen());
    encode_decode::<Bytes4>(rng.r#gen());
    encode_decode::<Bytes8>(rng.r#gen());
    encode_decode::<Bytes20>(rng.r#gen());
    encode_decode::<Bytes32>(rng.r#gen());
    encode_decode::<Nonce>(rng.r#gen());
    encode_decode::<MessageId>(rng.r#gen());
    encode_decode::<Salt>(rng.r#gen());
    encode_decode::<Bytes64>(rng.r#gen());
}

#[test]
#[cfg(feature = "serde")]
fn test_key_serde() {
    let rng = &mut StdRng::seed_from_u64(8586);
    let adr: Address = rng.r#gen();
    let ast_id: AssetId = rng.r#gen();
    let contract_id: ContractId = rng.r#gen();
    let tx_id: TxId = rng.r#gen();
    let bytes4: Bytes4 = rng.r#gen();
    let bytes8: Bytes8 = rng.r#gen();
    let bytes20: Bytes20 = rng.r#gen();
    let bytes32: Bytes32 = rng.r#gen();
    let nonce: Nonce = rng.r#gen();
    let message_id: MessageId = rng.r#gen();
    let salt: Salt = rng.r#gen();
    let bytes64: Bytes64 = rng.r#gen();

    let adr_t = bincode::serialize(&adr).expect("Failed to serialize Address");
    let adr_t: Address =
        bincode::deserialize(&adr_t).expect("Failed to deserialize Address");
    assert_eq!(adr, adr_t);

    let ast_id_t = bincode::serialize(&ast_id).expect("Failed to serialize AssetId");
    let ast_id_t: AssetId =
        bincode::deserialize(&ast_id_t).expect("Failed to deserialize AssetId");
    assert_eq!(ast_id, ast_id_t);

    let contract_id_t =
        bincode::serialize(&contract_id).expect("Failed to serialize ContractId");
    let contract_id_t: ContractId =
        bincode::deserialize(&contract_id_t).expect("Failed to deserialize ContractId");
    assert_eq!(contract_id, contract_id_t);

    let tx_id_t = bincode::serialize(&tx_id).expect("Failed to serialize TxId");
    let tx_id_t: TxId =
        bincode::deserialize(&tx_id_t).expect("Failed to deserialize TxId");
    assert_eq!(tx_id, tx_id_t);

    let bytes4_t = bincode::serialize(&bytes4).expect("Failed to serialize Bytes4");
    let bytes4_t: Bytes4 =
        bincode::deserialize(&bytes4_t).expect("Failed to deserialize Bytes4");
    assert_eq!(bytes4, bytes4_t);

    let bytes8_t = bincode::serialize(&bytes8).expect("Failed to serialize Bytes8");
    let bytes8_t: Bytes8 =
        bincode::deserialize(&bytes8_t).expect("Failed to deserialize Bytes8");
    assert_eq!(bytes8, bytes8_t);

    let bytes20_t = bincode::serialize(&bytes20).expect("Failed to serialize Bytes20");
    let bytes20_t: Bytes20 =
        bincode::deserialize(&bytes20_t).expect("Failed to deserialize Bytes20");
    assert_eq!(bytes20, bytes20_t);

    let bytes32_t = bincode::serialize(&bytes32).expect("Failed to serialize Bytes32");
    let bytes32_t: Bytes32 =
        bincode::deserialize(&bytes32_t).expect("Failed to deserialize Bytes32");
    assert_eq!(bytes32, bytes32_t);

    let nonce_t = bincode::serialize(&nonce).expect("Failed to serialize Nonce");
    let nonce_t: Nonce =
        bincode::deserialize(&nonce_t).expect("Failed to deserialize Nonce");
    assert_eq!(nonce, nonce_t);

    let message_id_t =
        bincode::serialize(&message_id).expect("Failed to serialize MessageId");
    let message_id_t: MessageId =
        bincode::deserialize(&message_id_t).expect("Failed to deserialize MessageId");
    assert_eq!(message_id, message_id_t);

    let salt_t = bincode::serialize(&salt).expect("Failed to serialize Salt");
    let salt_t: Salt = bincode::deserialize(&salt_t).expect("Failed to deserialize Salt");
    assert_eq!(salt, salt_t);

    let bytes64_t = bincode::serialize(&bytes64).expect("Failed to serialize Bytes64");
    let bytes64_t: Bytes64 =
        bincode::deserialize(&bytes64_t).expect("Failed to deserialize Bytes64");
    assert_eq!(bytes64, bytes64_t);
}

#[test]
#[cfg(feature = "serde")]
fn test_key_types_hex_serialization() {
    let rng = &mut StdRng::seed_from_u64(8586);

    let adr: Address = rng.r#gen();
    let adr_to_string =
        serde_json::to_string(&adr).expect("serde_json::to_string failed on Address");
    assert_eq!(format!("\"{adr}\""), adr_to_string);

    let ast_id: AssetId = rng.r#gen();
    let ast_id_to_string =
        serde_json::to_string(&ast_id).expect("serde_json::to_string failed on AssetId");
    assert_eq!(format!("\"{ast_id}\""), ast_id_to_string);

    let contract_id: ContractId = rng.r#gen();
    let contract_id_to_string = serde_json::to_string(&contract_id)
        .expect("serde_json::to_string failed on ContractId");
    assert_eq!(format!("\"{contract_id}\""), contract_id_to_string);

    let tx_id: TxId = rng.r#gen();
    let tx_id_to_string =
        serde_json::to_string(&tx_id).expect("serde_json::to_string failed on TxId");
    assert_eq!(format!("\"{tx_id}\""), tx_id_to_string);

    let bytes4: Bytes4 = rng.r#gen();
    let bytes4_to_string =
        serde_json::to_string(&bytes4).expect("serde_json::to_string failed on Bytes4");
    assert_eq!(format!("\"{bytes4}\""), bytes4_to_string);

    let bytes8: Bytes8 = rng.r#gen();
    let bytes8_to_string =
        serde_json::to_string(&bytes8).expect("serde_json::to_string failed on Bytes8");
    assert_eq!(format!("\"{bytes8}\""), bytes8_to_string);

    let bytes20: Bytes20 = rng.r#gen();
    let bytes20_to_string =
        serde_json::to_string(&bytes20).expect("serde_json::to_string failed on Bytes20");
    assert_eq!(format!("\"{bytes20}\""), bytes20_to_string);

    let bytes32: Bytes32 = rng.r#gen();
    let bytes32_to_string =
        serde_json::to_string(&bytes32).expect("serde_json::to_string failed on Bytes32");
    assert_eq!(format!("\"{bytes32}\""), bytes32_to_string);

    let message_id: MessageId = rng.r#gen();
    let message_id_to_string = serde_json::to_string(&message_id)
        .expect("serde_json::to_string failed on MessageId");
    assert_eq!(format!("\"{message_id}\""), message_id_to_string);

    let salt: Salt = rng.r#gen();
    let salt_to_string =
        serde_json::to_string(&salt).expect("serde_json::to_string failed on Salt");
    assert_eq!(format!("\"{salt}\""), salt_to_string);

    let bytes64: Bytes64 = rng.r#gen();
    let bytes64_to_string =
        serde_json::to_string(&bytes64).expect("Failed to serialize Bytes64");
    assert_eq!(format!("\"{bytes64}\""), bytes64_to_string);
}