1use crate::{ascii_art::*, is_ansi_supported};
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5pub enum Vendor {
6 AMD = 0x1002,
7 ImgTec = 0x1010,
8 Apple = 0x106B,
9 Nvidia = 0x10DE,
10 ARM = 0x13B5,
11 Microsoft = 0x1414,
12 Google = 0x1AE0,
13 Qualcomm = 0x5143,
14 Intel = 0x8086,
15 Unknown = 0xFFFF,
16 VIV = 0x10001,
17 VSI = 0x10002,
18 Kazan = 0x10003,
19 Codeplay = 0x10004,
20 Mesa = 0x10005,
21 Pocl = 0x10006,
22 MobileEye = 0x10007,
23}
24
25const BLOCK: &str = "\x1B[7m \x1B[0m";
26
27impl Vendor {
28 pub fn get_ascii_art(&self) -> Vec<String> {
30 let art: &[&str] = match self {
31 Vendor::AMD => AMD,
32 Vendor::Apple => APPLE,
33 Vendor::ARM => ARM,
34 Vendor::Google => GOOGLE,
35 Vendor::Intel => INTEL,
36 Vendor::Nvidia => NVIDIA,
37 Vendor::Microsoft => MICROSOFT,
38 Vendor::Qualcomm => QUALCOMM,
39 Vendor::Mesa => VULKAN,
40 Vendor::Unknown
41 | Vendor::ImgTec
42 | Vendor::VIV
43 | Vendor::VSI
44 | Vendor::Kazan
45 | Vendor::Codeplay
46 | Vendor::Pocl
47 | Vendor::MobileEye => VULKAN,
48 };
49
50 let style = if is_ansi_supported() {
51 self.get_alternative_style()
52 } else {
53 self.get_style()
54 };
55 let mut modified_art: Vec<String> = art.iter().map(|&line| line.to_string()).collect();
56
57 for (symbol, style) in CHARS.iter().zip(style.iter()) {
58 if !style.is_empty() {
59 modified_art = modified_art
60 .iter()
61 .map(|line| line.replace(*symbol, &format!("{}{}", style, BLOCK)))
62 .collect();
63 }
64 }
65
66 modified_art
67 }
68
69 pub const fn get_style(&self) -> [&str; LUT_SIZE] {
71 match self {
72 Vendor::AMD => AMD_STYLE,
73 Vendor::Apple => APPLE_STYLE,
74 Vendor::ARM => ARM_STYLE,
75 Vendor::Google => GOOGLE_STYLE,
76 Vendor::Intel => INTEL_STYLE,
77 Vendor::Nvidia => NVIDIA_STYLE,
78 Vendor::Microsoft => MICROSOFT_STYLE,
79 Vendor::Qualcomm => QUALCOMM_STYLE,
80 Vendor::Mesa => VULKAN_STYLE,
81 Vendor::Unknown
82 | Vendor::ImgTec
83 | Vendor::VIV
84 | Vendor::VSI
85 | Vendor::Kazan
86 | Vendor::Codeplay
87 | Vendor::Pocl
88 | Vendor::MobileEye => VULKAN_STYLE,
89 }
90 }
91
92 pub const fn name(&self) -> &'static str {
94 match self {
95 Vendor::AMD => "AMD",
96 Vendor::Apple => "Apple",
97 Vendor::ARM => "ARM",
98 Vendor::Codeplay => "Codeplay",
99 Vendor::Google => "Google",
100 Vendor::ImgTec => "ImgTec",
101 Vendor::Intel => "Intel",
102 Vendor::Kazan => "Kazan",
103 Vendor::Mesa => "Mesa",
104 Vendor::MobileEye => "MobileEye",
105 Vendor::Nvidia => "Nvidia",
106 Vendor::Pocl => "Pocl",
107 Vendor::Qualcomm => "Qualcomm",
108 Vendor::Unknown => "Unknown",
109 Vendor::VIV => "VIV",
110 Vendor::VSI => "VSI",
111 Vendor::Microsoft => "Microsoft",
112 }
113 }
114
115 pub fn from_vendor_id(id: u32) -> Option<Self> {
117 match id {
118 0x1002 => Some(Vendor::AMD),
119 0x1010 => Some(Vendor::ImgTec),
120 0x106B => Some(Vendor::Apple),
121 0x10DE => Some(Vendor::Nvidia),
122 0x13B5 => Some(Vendor::ARM),
123 0x1414 => Some(Vendor::Microsoft),
124 0x1AE0 => Some(Vendor::Google),
125 0x5143 => Some(Vendor::Qualcomm),
126 0x8086 => Some(Vendor::Intel),
127 0xFFFF => Some(Vendor::Unknown),
128 0x10001 => Some(Vendor::VIV),
129 0x10002 => Some(Vendor::VSI),
130 0x10003 => Some(Vendor::Kazan),
131 0x10004 => Some(Vendor::Codeplay),
132 0x10005 => Some(Vendor::Mesa),
133 0x10006 => Some(Vendor::Pocl),
134 0x10007 => Some(Vendor::MobileEye),
135 _ => None,
136 }
137 }
138
139 pub const fn get_alternative_style(&self) -> [&str; LUT_SIZE] {
140 match self {
141 Vendor::AMD => AMD_STYLE_ALT,
142 Vendor::Apple => APPLE_STYLE_ALT,
143 Vendor::ARM => ARM_STYLE_ALT,
144 Vendor::Google => GOOGLE_STYLE_ALT,
145 Vendor::Intel => INTEL_STYLE_ALT,
146 Vendor::Nvidia => NVIDIA_STYLE_ALT,
147 Vendor::Microsoft => MICROSOFT_STYLE_ALT,
148 Vendor::Qualcomm => QUALCOMM_STYLE_ALT,
149 Vendor::Mesa => VULKAN_STYLE_ALT,
150 Vendor::Unknown
151 | Vendor::ImgTec
152 | Vendor::VIV
153 | Vendor::VSI
154 | Vendor::Kazan
155 | Vendor::Codeplay
156 | Vendor::Pocl
157 | Vendor::MobileEye => VULKAN_STYLE_ALT,
158 }
159 }
160}
161
162impl From<Vendor> for u32 {
163 fn from(v: Vendor) -> Self {
164 v as u32
165 }
166}
167
168impl std::fmt::Display for Vendor {
170 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
171 write!(f, "{}", self.name())
172 }
173}
174
175#[cfg(test)]
176mod tests {
177 use super::*;
178
179 #[test]
180 fn test_from_vendor_id() {
181 assert_eq!(Vendor::from_vendor_id(0x1002), Some(Vendor::AMD));
182 assert_eq!(Vendor::from_vendor_id(0x1010), Some(Vendor::ImgTec));
183 assert_eq!(Vendor::from_vendor_id(0x10DE), Some(Vendor::Nvidia));
184 assert_eq!(Vendor::from_vendor_id(0x9999), None);
185 }
186
187 #[test]
188 fn test_name() {
189 assert_eq!(Vendor::AMD.name(), "AMD");
190 assert_eq!(Vendor::Apple.name(), "Apple");
191 assert_eq!(Vendor::Intel.name(), "Intel");
192 assert_eq!(Vendor::Unknown.name(), "Unknown");
193 }
194
195 #[test]
196 fn test_display() {
197 let vendor = Vendor::Nvidia;
198 let s = format!("{}", vendor);
199 assert_eq!(s, vendor.name());
200 }
201
202 #[test]
203 fn test_get_styles_length() {
204 let vendor = Vendor::AMD;
205 let styles = vendor.get_style();
206 assert_eq!(styles.len(), crate::ascii_art::LUT_SIZE);
207 }
208
209 #[test]
210 fn test_get_ascii_art() {
211 let vendor = Vendor::AMD;
212 let art = vendor.get_ascii_art();
213 assert!(!art.is_empty(), "ASCII art should not be empty");
214
215 let styles = vendor.get_style();
216 let non_empty_style = styles.iter().any(|s| !s.is_empty());
217 if non_empty_style {
218 let block_found = art.iter().any(|line| line.contains(BLOCK));
219 assert!(block_found, "Styled block should appear in ASCII art lines");
220 }
221 }
222}