use crate::xdr::*;
#[derive(WriteXDR, Debug)]
pub(crate) struct ContractExn<E: WriteXDR> {
selector: u64,
exn: E,
}
impl<E: WriteXDR + crate::exn::Exn> ContractExn<E> {
#[cfg_attr(not(target_arch = "riscv32"), track_caller)]
pub(crate) fn new(exn: E) -> Self {
Self {
selector: E::SELECTOR,
exn,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::exn::{Exn, LibraryExn};
use crate::internal::encode_xdr;
#[derive(Debug, Clone, PartialEq, ReadXDR, WriteXDR, thiserror::Error)]
#[repr(i32)]
enum TestExn {
#[error("boom")]
Boom = 1,
#[error("data")]
Data(u32) = 2,
}
impl Exn for TestExn {
const SELECTOR: u64 = 0xFFFF_FFFF_FFFF_FFFF; }
#[test]
fn contract_exn_writes_selector_then_payload() {
let exn = ContractExn::new(TestExn::Boom);
let buf = encode_xdr(&exn).unwrap();
let mut reader = cxs::buf_reader::BufReader::new(buf.as_ref());
let selector: u64 = ReadXDR::read_xdr(&mut reader).unwrap();
let decoded: TestExn = ReadXDR::read_xdr(&mut reader).unwrap();
assert_eq!(selector, 0xFFFF_FFFF_FFFF_FFFF);
assert_eq!(decoded, TestExn::Boom);
}
#[test]
fn contract_exn_writes_library_selector_then_payload() {
let exn = ContractExn::new(LibraryExn::NonNegativeIntOverflow);
let buf = encode_xdr(&exn).unwrap();
let mut reader = cxs::buf_reader::BufReader::new(buf.as_ref());
let selector: u64 = ReadXDR::read_xdr(&mut reader).unwrap();
let decoded: LibraryExn = ReadXDR::read_xdr(&mut reader).unwrap();
assert_eq!(selector, LibraryExn::SELECTOR);
assert_eq!(decoded, LibraryExn::NonNegativeIntOverflow);
}
#[test]
fn contract_exn_by_reference_encodes_identically_to_owned() {
let exn = TestExn::Data(0xDEAD_BEEF);
let by_ref = encode_xdr(&ContractExn::new(&exn)).unwrap();
let owned = encode_xdr(&ContractExn::new(exn.clone())).unwrap();
assert_eq!(by_ref, owned);
let mut reader = cxs::buf_reader::BufReader::new(by_ref.as_ref());
let selector: u64 = ReadXDR::read_xdr(&mut reader).unwrap();
let decoded: TestExn = ReadXDR::read_xdr(&mut reader).unwrap();
assert_eq!(selector, TestExn::SELECTOR);
assert_eq!(decoded, exn);
}
#[test]
fn selector_can_be_decoded_without_knowing_payload_type() {
let exn = ContractExn::new(TestExn::Boom);
let buf = encode_xdr(&exn).unwrap();
let mut reader = cxs::buf_reader::BufReader::new(buf.as_ref());
let selector: u64 = ReadXDR::read_xdr(&mut reader).unwrap();
assert_eq!(selector, TestExn::SELECTOR);
}
}