1 use model::Mcu;
2 use pack;
3 
4 use std::path::{Path, PathBuf};
5 use std::{fs, io};
6 
7 /// The extension on the pack files.
8 const PACK_FILE_EXT: &'static str = "atdf";
9 
10 /// All pack collections inside the 'packs' folder
11 /// of this repository.
12 const PACK_COLLECTIONS: &'static [&'static str] = &[
13     "atmega", "tiny", "xmegaa", "xmegab",
14     "xmegac", "xmegad", "xmegae", "automotive",
15 ];
16 
17 /// The on-disk path of the crate root.
18 const CRATE_ROOT: &'static str = env!("CARGO_MANIFEST_DIR");
19 
20 lazy_static! {
21     static ref MCUS: Vec<Mcu> = self::load_microcontrollers().expect("failed to load microcontrollers");
22 
23     static ref MCU_NAMES: Vec<String> = pack_informations()
24         .expect("could not find packfiles")
25         .into_iter()
26         .map(|pack| pack.mcu_name)
27         .collect();
28 }
29 
30 struct PackInfo {
31     pub mcu_name: String,
32     pub path: PathBuf,
33 }
34 
35 /// Retrieves a list of `Mcu` objects for all microcontrollers.
microcontrollers() -> &'static [Mcu]36 pub fn microcontrollers() -> &'static [Mcu] {
37     &MCUS[..]
38 }
39 
40 /// Retrieves a list of all microcontroller names.
41 ///
42 /// # Examples
43 ///
44 /// * `atmega328p`
45 /// * `attiny85`
microcontroller_names() -> &'static [String]46 pub fn microcontroller_names() -> &'static [String] {
47     &MCU_NAMES[..]
48 }
49 
50 /// Retrieves information for a specific microcontroller.
microcontroller(name: &str) -> Mcu51 pub fn microcontroller(name: &str) -> Mcu {
52     let pack_info = pack_informations().unwrap()
53                             .into_iter()
54                             .find(|pack_info| pack_info.mcu_name == name)
55                             .expect(&format!("no microcontroller with the name '{}' found", name));
56     pack::load(&pack_info.path).expect("could not parse microcontroller pack")
57 }
58 
59 /// Retrieves a list of `Mcu` objects in a directory containg `PACK_COLLECTIONS`.
load_microcontrollers() -> Result<Vec<Mcu>, io::Error>60 fn load_microcontrollers() -> Result<Vec<Mcu>, io::Error> {
61     let microcontrollers = pack_informations()?.into_iter()
62         .map(|pack_info| pack::load(&pack_info.path).unwrap())
63         .collect();
64 
65     Ok(microcontrollers)
66 }
67 
pack_informations() -> Result<Vec<PackInfo>, io::Error>68 fn pack_informations() -> Result<Vec<PackInfo>, io::Error> {
69     let path = Path::new(CRATE_ROOT).join("packs");
70     pack_informations_from(&path)
71 }
72 
pack_informations_from(path: &Path) -> Result<Vec<PackInfo>, io::Error>73 fn pack_informations_from(path: &Path) -> Result<Vec<PackInfo>, io::Error> {
74     let mut pack_paths = Vec::new();
75 
76     for pack_name in PACK_COLLECTIONS {
77         pack_paths.extend(find_packs(&path.join(pack_name)).unwrap());
78     }
79 
80     Ok(pack_paths.into_iter().map(|path| PackInfo {
81         mcu_name: path.file_stem().unwrap().to_str().unwrap().to_lowercase().to_owned(),
82         path: path.to_owned(),
83     }).collect())
84 }
85 
86 /// Finds all pack files in a directory.
find_packs(in_dir: &Path) -> Result<Vec<PathBuf>, io::Error>87 fn find_packs(in_dir: &Path) -> Result<Vec<PathBuf>, io::Error> {
88     let mut paths = Vec::new();
89 
90     for entry in fs::read_dir(in_dir)? {
91         let entry = entry?;
92         if let Some(PACK_FILE_EXT) = entry.path().extension().map(|s| s.to_str().unwrap()) {
93             paths.push(entry.path());
94         }
95     }
96     Ok(paths)
97 }
98 
99 #[cfg(test)]
100 mod test {
101     #[test]
there_are_at_least_100_microcontrollers()102     fn there_are_at_least_100_microcontrollers() {
103         let mcus = super::microcontrollers();
104         assert!(mcus.len() > 100, "there should be at least 100 microcontrollers");
105     }
106 
107     #[test]
can_get_atmega328p_by_name()108     fn can_get_atmega328p_by_name() {
109         let mcu = super::microcontroller("atmega328p");
110         assert_eq!("ATmega328P", mcu.device.name);
111     }
112 }
113 
114