1 use std::collections::BTreeMap;
2 use std::fs::File;
3 use std::io::{BufRead, BufReader, Result, Write};
4 use std::path::Path;
5
6 /// Temporary structure, created when reading a file containing OID declarations
7 #[derive(Debug)]
8 pub struct LoadedEntry {
9 /// Name of the global constant for this entry.
10 ///
11 /// If `name` is "", then no global constant is defined
12 pub name: String,
13 /// Textual representation of OID (ex: 2.5.4.3)
14 pub oid: String,
15 /// A short name to describe OID. Should be unique (no check is done)
16 pub sn: String,
17 /// A description for this entry
18 pub description: String,
19 }
20
21 /// Temporary structure, created when reading a file containing OID declarations
22 pub type LoadedMap = BTreeMap<String, Vec<LoadedEntry>>;
23
24 /// Load a file to an OID description map
25 ///
26 /// format of the file: tab-separated values
27 /// <pre>
28 /// feature name oid short_name description (until end of line)
29 /// </pre>
30 ///
31 /// `name` is used to declare a global constant when creating output file (see `generate_file`).
32 /// If `name` is "" then no constant will be written
33 ///
load_file<P: AsRef<Path>>(path: P) -> Result<LoadedMap>34 pub fn load_file<P: AsRef<Path>>(path: P) -> Result<LoadedMap> {
35 let mut map = BTreeMap::new();
36
37 let file = File::open(path)?;
38 for line in BufReader::new(file).lines() {
39 let line = line?;
40 if line.is_empty() || line.starts_with('#') {
41 continue;
42 }
43 // split by tabs
44 let mut iter = line.splitn(5, '\t');
45 let feature = iter.next().expect("invalid oid_db format: missing feature").replace("-", "_");
46 let name = iter.next().expect("invalid oid_db format: missing name").to_string();
47 let oid = iter.next().expect("invalid oid_db format: missing OID").to_string();
48 let sn = iter.next().expect("invalid oid_db format: missing short name").to_string();
49 let description = iter.next().expect("invalid oid_db format: missing description").to_string();
50
51 let entry = LoadedEntry {
52 name,
53 oid,
54 sn,
55 description,
56 };
57
58 let v = map.entry(feature.to_string()).or_insert_with(Vec::new);
59
60 v.push(entry);
61 }
62 Ok(map)
63 }
64
65 /// Generate a file containing a `with_<feat>` method for OidRegistry
generate_file<P: AsRef<Path>>(map: &LoadedMap, dest_path: P) -> Result<()>66 pub fn generate_file<P: AsRef<Path>>(map: &LoadedMap, dest_path: P) -> Result<()> {
67 let mut out_file = File::create(&dest_path)?;
68 for feat_entries in map.values() {
69 for v in feat_entries {
70 if v.name != "\"\"" {
71 writeln!(out_file, "/// {}", v.oid)?;
72 writeln!(out_file, "pub const {}: Oid<'static> = oid!({});", v.name, v.oid)?;
73 }
74 }
75 }
76 writeln!(out_file)?;
77 writeln!(out_file, "impl<'a> OidRegistry<'a> {{")?;
78 for (k, v) in map {
79 writeln!(out_file, r#" #[cfg(feature = "{}")]"#, k)?;
80 writeln!(out_file, r#" #[cfg_attr(docsrs, doc(cfg(feature = "{}")))]"#, k)?;
81 writeln!(
82 out_file,
83 r#" #[doc = "Load all known OIDs for feature `{}` in the registry."]"#,
84 k
85 )?;
86 writeln!(out_file, " pub fn with_{}(mut self) -> Self {{", k)?;
87 for item in v {
88 writeln!(
89 out_file,
90 r#" self.insert(oid!({}), OidEntry::new("{}", "{}"));"#,
91 item.oid, item.sn, item.description
92 )?;
93 }
94 writeln!(out_file, " self")?;
95 writeln!(out_file, " }}")?;
96 writeln!(out_file)?;
97 }
98 writeln!(out_file, "}}")?;
99 Ok(())
100 }
101