extern crate serde;
use std::{error::Error, fs::File};
use std::io::{self, Write};
macro_rules! dbg
{
($($tokens: tt)*) => {
println!("cargo::warning={}", format!($($tokens)*))
}
}
#[derive(Debug, serde::Deserialize)]
struct AlpnProtocolIds
{
Protocol: String,
Idc: String,
Reference: String,
}
struct AlpnStorTmp
{
ident_hex: String,
ident_str: String,
descr: String,
}
impl AlpnStorTmp
{
fn rewrite_enum(raw: &str) -> String
{
let mut s = String::with_capacity(raw.len());
let mut upper = true;
let mut pc = None;
for c in raw.chars()
{
pc = Some(c);
if s.len() == 0
{
if c.is_ascii_alphabetic() == true
{
s.push(c.to_ascii_uppercase());
upper = false;
}
}
else
{
if c.is_ascii_punctuation() == true || c.is_whitespace() == true
{
upper = true;
}
else if c.is_ascii_digit() == true
{
upper = true;
s.push(c);
}
else if c.is_ascii_alphabetic() == true
{
if upper == true
{
s.push(c.to_ascii_uppercase());
upper = false;
}
else
{
s.push(c.to_ascii_lowercase());
}
}
}
}
return s;
}
pub
fn write_enum(&self, file: &mut File) -> io::Result<()>
{
writeln!(file, "\t{},", Self::rewrite_enum(&self.descr))
}
pub
fn write_array(&self, file: &mut File) -> io::Result<()>
{
writeln!(file, "\tAlpnProtocolId\n\t{{ \n\t\tident: AlpnType::{}, \n\t\tident_seq: b\"{}\", \n\t\tident_str: \"{}\", \n\t\tdescr: \"{}\" \n\t}},",
Self::rewrite_enum(&self.descr), self.ident_hex, self.ident_str, self.descr)
}
}
impl AlpnProtocolIds
{
fn example() -> Result<(), Box<dyn Error>>
{
let mut autogen_path = std::env::current_dir().unwrap();
autogen_path.push("src/protocol/autogen/autogen_alpn.rs");
let mut path = std::env::current_dir().unwrap();
path.push("alpn-protocol-ids.csv");
let mut file =
File::options()
.create(true)
.truncate(true)
.write(true)
.open(autogen_path)
.unwrap();
writeln!(file, "// ---- AUTOGENERATED FILE ----\n ")?;
writeln!(file, "use super::AlpnProtocolId;\n\n")?;
let mut alpns: Vec<AlpnStorTmp> = Vec::new();
let mut rdr = csv::Reader::from_path(path)?;
for result in rdr.deserialize()
{
let mut record: AlpnProtocolIds = result?;
dbg!("{:?}", record);
if record.Protocol.as_str() == "Reserved"
{
continue;
}
record.Idc.retain(|c| !r#"""#.contains(c) && !c.is_whitespace());
let Some((ident_hex, ident_str)) = record.Idc.split_once("(")
else {continue;};
let ident_hex = ident_hex.replace("0x", "\\x");
let ident_str = ident_str.replace(")", "");
dbg!("{} {} {}", ident_hex, ident_str, record.Protocol);
alpns.push(AlpnStorTmp{ ident_hex, ident_str, descr: record.Protocol });
}
alpns.sort_by(|a, b| a.ident_str.cmp(&b.ident_str));
writeln!(file, "#[repr(usize)]\n#[derive(Copy, Clone, Debug, Eq, PartialEq)]")?;
writeln!(file, "pub enum AlpnType \n{{\n")?;
for alpn in alpns.iter()
{
alpn.write_enum(&mut file)?;
}
writeln!(file, "}}\n\n")?;
write!(file, "pub const ALPNS_LIST: &'static [AlpnProtocolId] = \n&[\n")?;
for alpn in alpns.iter()
{
alpn.write_array(&mut file)?;
}
write!(file, "];")?;
Ok(())
}
}
fn main()
{
if std::env::var("DOCS_RS").is_ok()
{
println!("cargo:warning=DOCS_RS, AlpnProtocolIds will not be build.");
return;
}
AlpnProtocolIds::example().unwrap();
}