stellar-xdr 28.0.0

Stellar XDR types, encoding, and decoding.
Documentation
#![cfg(all(feature = "std", feature = "serde"))]

use stellar_xdr::{BytesM, Hash, StringM, VecM};

use stellar_xdr::{AccountId, ContractEvent, ContractEventType, Int128Parts};

use std::str::FromStr;

#[test]
fn test_serde_ser() -> Result<(), Box<dyn std::error::Error>> {
    assert_eq!(
        serde_json::to_string(&<_ as TryInto<VecM<u8>>>::try_into("hello world")?)?,
        "[104,101,108,108,111,32,119,111,114,108,100]"
    );
    assert_eq!(
        serde_json::to_string(&<_ as TryInto<BytesM>>::try_into("hello world")?)?,
        "\"68656c6c6f20776f726c64\""
    );
    assert_eq!(
        serde_json::to_string(&<_ as TryInto<StringM>>::try_into("hello world")?)?,
        "\"hello world\""
    );
    assert_eq!(
        serde_json::to_string(&<_ as Into<Hash>>::into(
            *b"01234567890123456789013456789012"
        ))?,
        "\"3031323334353637383930313233343536373839303133343536373839303132\""
    );
    assert_eq!(
        serde_json::to_string(&AccountId::from_str(
            "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWHF"
        )?)?,
        "\"GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWHF\""
    );
    Ok(())
}

#[test]
fn test_serde_der() -> Result<(), Box<dyn std::error::Error>> {
    let v: VecM<u8> = serde_json::from_str("[104,101,108,108,111,32,119,111,114,108,100]")?;
    assert_eq!(v, <_ as TryInto<VecM<u8>>>::try_into("hello world")?);

    let v: BytesM = serde_json::from_str("\"68656c6c6f20776f726c64\"")?;
    assert_eq!(v, <_ as TryInto<BytesM>>::try_into("hello world")?);

    let v: StringM = serde_json::from_str("\"hello world\"")?;
    assert_eq!(v, <_ as TryInto<StringM>>::try_into("hello world")?,);

    let v: Hash = serde_json::from_str(
        "\"3031323334353637383930313233343536373839303133343536373839303132\"",
    )?;
    assert_eq!(
        v,
        <_ as Into<Hash>>::into(*b"01234567890123456789013456789012"),
    );

    assert_eq!(
        AccountId::from_str("GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWHF")?,
        serde_json::from_str("\"GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWHF\"")?,
    );

    Ok(())
}

#[test]
fn test_structs_that_ser_to_string_and_dual_der() -> Result<(), Box<dyn std::error::Error>> {
    assert_eq!(
        serde_json::to_string(&Int128Parts { hi: 1, lo: 2 })?,
        "\"18446744073709551618\"",
    );
    assert_eq!(
        serde_json::from_str::<Int128Parts>("\"18446744073709551618\"")?,
        Int128Parts { hi: 1, lo: 2 },
    );
    assert_eq!(
        serde_json::from_str::<Int128Parts>(r#"{"hi":1,"lo":2}"#)?,
        Int128Parts { hi: 1, lo: 2 },
    );
    Ok(())
}

#[test]
fn test_serde_type_field_uses_sep51_json_key() -> Result<(), Box<dyn std::error::Error>> {
    let event = ContractEvent {
        type_: ContractEventType::Contract,
        ..Default::default()
    };

    // The SEP-51 JSON uses the key `type`, not the previously escaped `type_`.
    let json = r#"{"ext":"v0","contract_id":null,"type":"contract","body":{"v0":{"topics":[],"data":{"bool":false}}}}"#;
    // The legacy JSON that older versions of this crate emitted, using `type_`.
    let legacy_json = r#"{"ext":"v0","contract_id":null,"type_":"contract","body":{"v0":{"topics":[],"data":{"bool":false}}}}"#;

    // Serializes with the SEP-51 key `type`.
    assert_eq!(serde_json::to_string(&event)?, json);

    // Deserializes from the SEP-51 key `type`.
    assert_eq!(serde_json::from_str::<ContractEvent>(json)?, event);

    // The legacy escaped key `type_` is still accepted via a serde alias.
    assert_eq!(serde_json::from_str::<ContractEvent>(legacy_json)?, event);

    Ok(())
}