1use std::fmt::{Display, Formatter};
2
3use thiserror::Error;
4
5#[derive(Debug, Clone, PartialEq, Eq)]
6pub struct TargetTriple {
7 pub architecture: Architecture,
8 pub chain: Chain,
9 pub version: Version,
10}
11
12impl TargetTriple {
13 pub fn new(architecture: Architecture, chain: Chain, version: Version) -> Self {
14 Self {
15 architecture,
16 chain,
17 version,
18 }
19 }
20 pub fn parse(s: &str) -> Result<Self, InvalidTriple> {
21 let mut triple = s.split('-');
22
23 let arch = Architecture::parse(triple.next().ok_or(InvalidTriple::InvalidFormat(s))?)?;
24 let chain = Chain::parse(triple.next().ok_or(InvalidTriple::InvalidFormat(s))?)?;
25 let version = Version::parse(
26 arch,
27 chain,
28 triple.next().ok_or(InvalidTriple::InvalidFormat(s))?,
29 )?;
30
31 if triple.next().is_none() {
32 Ok(Self::new(arch, chain, version))
33 } else {
34 Err(InvalidTriple::InvalidFormat(s))
35 }
36 }
37}
38
39impl Display for TargetTriple {
40 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
41 write!(f, "{}-{}-{}", self.architecture, self.chain, self.version)
42 }
43}
44
45#[derive(Debug, Clone, Copy, PartialEq, Eq)]
46pub enum Architecture {
47 Evm,
48}
49
50impl Architecture {
51 fn parse(s: &str) -> Result<Self, InvalidTriple> {
52 match s {
53 "evm" => Ok(Self::Evm),
54 _ => Err(InvalidTriple::ArchitectureNotSupported),
55 }
56 }
57}
58
59impl Display for Architecture {
60 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
61 match self {
62 Self::Evm => write!(f, "evm"),
63 }
64 }
65}
66
67#[derive(Debug, Clone, Copy, PartialEq, Eq)]
68pub enum Chain {
69 Ethereum,
70}
71
72impl Chain {
73 fn parse(s: &str) -> Result<Self, InvalidTriple> {
74 match s {
75 "ethereum" => Ok(Chain::Ethereum),
76 _ => Err(InvalidTriple::ChainNotSupported),
77 }
78 }
79}
80
81impl Display for Chain {
82 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
83 match self {
84 Chain::Ethereum => write!(f, "ethereum"),
85 }
86 }
87}
88
89#[derive(Debug, Clone, Copy, PartialEq, Eq)]
90pub enum Version {
91 EvmVersion(EvmVersion),
92}
93
94impl Version {
95 fn parse(arch: Architecture, chain: Chain, s: &str) -> Result<Self, InvalidTriple> {
96 match (arch, chain) {
97 (Architecture::Evm, Chain::Ethereum) => {
98 let evm_version = match s {
99 "frontier" => EvmVersion::Frontier,
100 "homestead" => EvmVersion::Homestead,
101 "byzantium" => EvmVersion::Byzantium,
102 "constantinople" => EvmVersion::Constantinople,
103 "istanbul" => EvmVersion::Istanbul,
104 "london" => EvmVersion::London,
105 _ => return Err(InvalidTriple::VersionNotSupported),
106 };
107 Ok(Self::EvmVersion(evm_version))
108 }
109 }
110 }
111}
112
113impl Display for Version {
114 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
115 match self {
116 Self::EvmVersion(evm_version) => write!(f, "{}", evm_version),
117 }
118 }
119}
120
121#[derive(Debug, Clone, Copy, PartialEq, Eq)]
122pub enum EvmVersion {
123 Frontier,
124 Homestead,
125 Byzantium,
126 Constantinople,
127 Istanbul,
128 London,
129}
130#[derive(Debug, Clone, Copy, Error)]
131pub enum InvalidTriple<'a> {
132 #[error("the format of triple must be `architecture-chain-version: but got `{0}`")]
133 InvalidFormat(&'a str),
134
135 #[error("given architecture is not supported")]
136 ArchitectureNotSupported,
137
138 #[error("given chain is not supported")]
139 ChainNotSupported,
140
141 #[error("given version is not supported")]
142 VersionNotSupported,
143
144 #[error("given triple consists of invalid combination")]
145 InvalidCombination,
146}
147
148impl Display for EvmVersion {
149 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
150 match self {
151 Self::Frontier => write!(f, "frontier"),
152 Self::Homestead => write!(f, "homestead"),
153 Self::Byzantium => write!(f, "byzantium"),
154 Self::Constantinople => write!(f, "constantinople"),
155 Self::Istanbul => write!(f, "istanbul"),
156 Self::London => write!(f, "london"),
157 }
158 }
159}
160
161#[cfg(test)]
162mod tests {
163 use super::*;
164
165 #[test]
166 fn test() {
167 let target = "evm-ethereum-istanbul";
168 let triple = TargetTriple::parse(target).unwrap();
169
170 assert_eq!(triple.architecture, Architecture::Evm);
171 assert_eq!(triple.chain, Chain::Ethereum);
172 assert_eq!(triple.version, Version::EvmVersion(EvmVersion::Istanbul));
173 }
174}