forked from gnunicorn/rust-multicodec
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbuild.rs
More file actions
111 lines (88 loc) · 3.43 KB
/
Copy pathbuild.rs
File metadata and controls
111 lines (88 loc) · 3.43 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
// SPDX-License-Identifier: MIT or Apache-2.0
//! Build script for multi-codec
//!
//! Generates the Codec enum from the multicodec table CSV file.
use convert_case::{Case, Converter};
use serde_derive::Deserialize;
use std::{collections::HashSet, fs::File, io::Write, path::PathBuf};
#[derive(Debug, Deserialize)]
struct Record {
name: String,
#[serde(rename = "tag")]
_tag: String,
code: String,
#[serde(rename = "status")]
_status: String,
#[serde(rename = "description")]
_description: Option<String>,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("cargo:rerun-if-changed=table.csv");
let mut pb = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
let mut tpb = pb.clone();
// Input path
tpb.push("table.csv");
// Output path
pb.push("src");
pb.push("table_gen.rs");
// Open input file
let inf = File::open(&tpb).map_err(|e| {
format!("Failed to open table.csv: {e}. Make sure table.csv exists in the crate root.")
})?;
// Open output file
let mut f = File::create(&pb).map_err(|e| format!("Failed to create table_gen.rs: {e}"))?;
let mut rdr = csv::Reader::from_reader(inf);
let conv = Converter::new().to_case(Case::Pascal);
// Track seen codes and names to detect duplicates
let mut seen_codes = HashSet::new();
let mut seen_names = HashSet::new();
let mut record_count = 0;
writeln!(f, "build_codec_enum! {{")?;
for (row_num, row) in rdr.deserialize().enumerate() {
let rec: Record =
row.map_err(|e| format!("Failed to parse CSV row {}: {}", row_num + 2, e))?;
// Validate record
let code_str = rec.code.trim();
if code_str.is_empty() {
return Err(format!("Empty code at row {}", row_num + 2).into());
}
if rec.name.is_empty() {
return Err(format!("Empty name at row {}", row_num + 2).into());
}
// Check for duplicates — duplicate codes/names produce ambiguous enum
// variants and must fail the build rather than silently emitting a
// warning. The Rust compiler would eventually reject duplicate match
// arms, but failing early in the build script gives a clearer error
// pointing at the offending CSV row.
if !seen_codes.insert(code_str.to_string()) {
return Err(format!(
"Duplicate code {} at row {} in table.csv — each multicodec code must be unique",
code_str,
row_num + 2
)
.into());
}
if !seen_names.insert(rec.name.clone()) {
return Err(format!(
"Duplicate name '{}' at row {} in table.csv — each multicodec name must be unique",
rec.name,
row_num + 2
)
.into());
}
// Generate enum variant
let variant_name = conv.convert(&rec.name);
writeln!(f, "\t{} => ({}, \"{}\"),", code_str, variant_name, rec.name)?;
record_count += 1;
}
writeln!(f, "}}")?;
// Flush to ensure all data is written
f.flush()?;
// Informational: Generated codec variants (removed warning output for cleaner builds)
// Use RUST_LOG=debug or --verbose to see build script output if needed
// eprintln!("Generated {} codec variants from table.csv", record_count);
if record_count == 0 {
return Err("No records found in table.csv!".into());
}
Ok(())
}