1use fugue_bytes::endian::Endian;
2
3use std::fmt;
4use std::str::FromStr;
5
6use thiserror::Error;
7
8#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
9#[derive(serde::Deserialize, serde::Serialize)]
10pub struct ArchitectureDef {
11 processor: String,
12 endian: Endian,
13 bits: usize,
14 variant: String,
15}
16
17#[derive(Debug, Error)]
18pub enum ArchDefParseError {
19 #[error("could not parse processor name")]
20 ParseProcessor,
21 #[error("could not parse endian")]
22 ParseEndian,
23 #[error("could not parse bitness")]
24 ParseBits,
25 #[error("could not parse processor variant")]
26 ParseVariant,
27 #[error("could not parse architecture definition: incorrect format")]
28 ParseFormat,
29}
30
31impl FromStr for ArchitectureDef {
32 type Err = ArchDefParseError;
33
34 fn from_str(s: &str) -> Result<Self, Self::Err> {
35 let parts = s.splitn(4, ':').collect::<Vec<_>>();
36 if !matches!(parts.len(), 3 | 4) {
37 return Err(ArchDefParseError::ParseFormat);
38 }
39
40 let processor = parts[0];
41 let endian = match parts[1] {
42 "le" | "LE" => Endian::Little,
43 "be" | "BE" => Endian::Big,
44 _ => return Err(ArchDefParseError::ParseEndian),
45 };
46 let bits = parts[2]
47 .parse::<usize>()
48 .map_err(|_| ArchDefParseError::ParseBits)?;
49
50 Ok(ArchitectureDef::new(
51 processor,
52 endian,
53 bits,
54 *parts.get(3).unwrap_or(&"default"),
55 ))
56 }
57}
58
59impl fmt::Display for ArchitectureDef {
60 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61 write!(
62 f,
63 "processor: {}, endian: {}, bits: {}, variant: {}",
64 self.processor,
65 if self.endian.is_big() { "big" } else { "little" },
66 self.bits,
67 self.variant,
68 )
69 }
70}
71
72impl ArchitectureDef {
73 pub fn new<P, V>(processor: P, endian: Endian, bits: usize, variant: V) -> Self
74 where P: Into<String>,
75 V: Into<String> {
76 Self {
77 processor: processor.into(),
78 endian,
79 bits,
80 variant: variant.into(),
81 }
82 }
83
84 pub fn is_little(&self) -> bool {
85 self.endian.is_little()
86 }
87
88 pub fn is_big(&self) -> bool {
89 self.endian.is_big()
90 }
91
92 pub fn endian(&self) -> Endian {
93 self.endian
94 }
95
96 pub fn bits(&self) -> usize {
97 self.bits
98 }
99
100 pub fn processor(&self) -> &str {
101 &self.processor
102 }
103
104 pub fn variant(&self) -> &str {
105 &self.variant
106 }
107}