aarchmrs_types/
instruction_code.rs

1/* Copyright (C) 2025 Ivan Boldyrev
2 *
3 * This document is licensed under the BSD 3-clause license.
4 */
5
6use hex::{FromHex, ToHex};
7
8/// ARM64 instruction with proper byte order and alignment.
9#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
10#[repr(align(4))]
11pub struct InstructionCode(pub [u8; 4]);
12
13impl InstructionCode {
14    #[inline]
15    pub const fn from_u32(value: u32) -> Self {
16        // B2.6.2 Instruction endianness
17        // A64 instructions have a fixed length of 32 bits and are always little-endian.
18        Self(value.to_le_bytes())
19    }
20
21    #[inline]
22    pub const fn unpack(self) -> u32 {
23        u32::from_le_bytes(self.0)
24    }
25}
26
27impl FromHex for InstructionCode {
28    type Error = <[u8; 4] as FromHex>::Error;
29
30    fn from_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, Self::Error> {
31        <[u8; 4]>::from_hex(hex).map(|bytes| Self::from_u32(u32::from_be_bytes(bytes)))
32    }
33}
34
35impl ToHex for InstructionCode {
36    fn encode_hex<T: core::iter::FromIterator<char>>(&self) -> T {
37        <[u8; 4]>::encode_hex(&self.unpack().to_be_bytes())
38    }
39
40    fn encode_hex_upper<T: core::iter::FromIterator<char>>(&self) -> T {
41        <[u8; 4]>::encode_hex_upper(&self.unpack().to_be_bytes())
42    }
43}
44
45#[cfg(test)]
46mod tests {
47    extern crate alloc;
48    use super::*;
49    use alloc::string::String;
50
51    #[test]
52    fn test_from_u32() {
53        assert_eq!(
54            InstructionCode::from_u32(0x12_f3_56_ab),
55            InstructionCode([0xab, 0x56, 0xf3, 0x12]),
56        );
57    }
58
59    #[test]
60    fn test_unpack() {
61        assert_eq!(
62            InstructionCode([0xab, 0x56, 0xf3, 0x12]).unpack(),
63            0x12_f3_56_ab,
64        );
65    }
66
67    #[test]
68    fn test_fromhex() {
69        assert_eq!(
70            InstructionCode::from_hex("12f356ab"),
71            Ok(InstructionCode([0xab, 0x56, 0xf3, 0x12])),
72        );
73    }
74
75    #[test]
76    fn test_encode_hex() {
77        assert_eq!(
78            InstructionCode([0xab, 0x56, 0xf3, 0x12]).encode_hex::<String>(),
79            "12f356ab",
80        );
81    }
82
83    #[test]
84    fn test_encode_hex_upper() {
85        assert_eq!(
86            InstructionCode([0xab, 0x56, 0xf3, 0x12]).encode_hex_upper::<String>(),
87            "12F356AB",
88        );
89    }
90}