|
| 1 | +//! A transaction output offset inside the transaction. |
| 2 | +use catalyst_types::conversion::from_saturating; |
| 3 | + |
| 4 | +/// A transaction output offset inside the transaction. |
| 5 | +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] |
| 6 | +pub struct TxnOutputOffset(u16); |
| 7 | + |
| 8 | +impl< |
| 9 | + T: Copy |
| 10 | + + TryInto<u16> |
| 11 | + + std::ops::Sub<Output = T> |
| 12 | + + PartialOrd<T> |
| 13 | + + num_traits::identities::Zero, |
| 14 | + > From<T> for TxnOutputOffset |
| 15 | +{ |
| 16 | + fn from(value: T) -> Self { |
| 17 | + Self(from_saturating(value)) |
| 18 | + } |
| 19 | +} |
| 20 | + |
| 21 | +impl From<TxnOutputOffset> for i16 { |
| 22 | + fn from(val: TxnOutputOffset) -> Self { |
| 23 | + i16::try_from(val.0).unwrap_or(i16::MAX) |
| 24 | + } |
| 25 | +} |
| 26 | + |
| 27 | +impl From<TxnOutputOffset> for usize { |
| 28 | + fn from(value: TxnOutputOffset) -> Self { |
| 29 | + value.0.into() |
| 30 | + } |
| 31 | +} |
| 32 | + |
| 33 | +#[cfg(test)] |
| 34 | +mod tests { |
| 35 | + use super::*; |
| 36 | + |
| 37 | + #[test] |
| 38 | + fn test_from_u8_to_txn_index() { |
| 39 | + let txn_index: TxnOutputOffset = 100u8.into(); // u8 is a valid type for conversion |
| 40 | + assert_eq!(txn_index.0, 100); |
| 41 | + } |
| 42 | + |
| 43 | + #[test] |
| 44 | + fn test_from_u16_to_txn_index() { |
| 45 | + let txn_index: TxnOutputOffset = 500u16.into(); // u16 is valid and within range for `TxnOutputOffset` |
| 46 | + assert_eq!(txn_index.0, 500); |
| 47 | + } |
| 48 | + |
| 49 | + #[test] |
| 50 | + fn test_from_i32_to_txn_index() { |
| 51 | + let txn_index: TxnOutputOffset = 1234i32.into(); // i32 can be converted into `TxnOutputOffset` |
| 52 | + assert_eq!(txn_index.0, 1234); |
| 53 | + } |
| 54 | + |
| 55 | + #[test] |
| 56 | + fn test_from_u32_to_txn_index() { |
| 57 | + let txn_index: TxnOutputOffset = 500_000u32.into(); // u32 is larger but should be saturated to `u16::MAX` |
| 58 | + assert_eq!(txn_index.0, u16::MAX); |
| 59 | + } |
| 60 | + |
| 61 | + #[test] |
| 62 | + fn test_from_large_i32_to_txn_index() { |
| 63 | + let txn_index: TxnOutputOffset = 70000i32.into(); // i32 too large for u16, should saturate to `u16::MAX` |
| 64 | + assert_eq!(txn_index.0, u16::MAX); |
| 65 | + } |
| 66 | + |
| 67 | + #[test] |
| 68 | + fn test_txn_index_to_i16_within_range() { |
| 69 | + let txn_index = TxnOutputOffset(100); |
| 70 | + let result: i16 = txn_index.into(); // Should successfully convert to i16 |
| 71 | + assert_eq!(result, 100); |
| 72 | + } |
| 73 | + |
| 74 | + #[test] |
| 75 | + fn test_txn_index_to_i16_with_saturation() { |
| 76 | + let txn_index = TxnOutputOffset(u16::MAX); // u16::MAX = 65535, which is too large for i16 |
| 77 | + let result: i16 = txn_index.into(); // Should saturate to i16::MAX |
| 78 | + assert_eq!(result, i16::MAX); |
| 79 | + } |
| 80 | + |
| 81 | + #[test] |
| 82 | + fn test_txn_index_to_i16_with_zero() { |
| 83 | + let txn_index = TxnOutputOffset(0); // Should be able to convert to i16 without issue |
| 84 | + let result: i16 = txn_index.into(); |
| 85 | + assert_eq!(result, 0); |
| 86 | + } |
| 87 | +} |
0 commit comments