use clap::Parser;
use layout21protos::conv as proto_converters;
use layout21protos::tech as protos;
use layout21raw as raw;
use raw::utils::Ptr;
use std::error::Error;
#[derive(Parser)]
struct ProgramOptions {
#[arg(short = 'i', long, default_value = "")]
proto: String,
#[arg(short = 'o', long, default_value = "")]
gds: String,
#[arg(short = 't', long, default_value = "")]
tech: String,
#[arg(short, long)]
verbose: bool,
}
fn main() -> Result<(), Box<dyn Error>> {
let options = ProgramOptions::parse();
return _main(&options);
}
fn _main(options: &ProgramOptions) -> Result<(), Box<dyn Error>> {
let proto_library = match proto_converters::open(&options.proto) {
Err(err) => panic!("Couldn't read layout protobuf: {}", err),
Ok(lib) => lib,
};
if options.verbose {
println!("read: {:?}", &options.proto);
}
let tech_library: protos::Technology = match proto_converters::open(&options.tech) {
Err(err) => panic!("Couldn't read tech protobuf: {}", err),
Ok(lib) => lib,
};
if options.verbose {
println!("read: {:?}", &options.tech);
}
let tech_layers = raw::data::Layers::from_proto(&tech_library)?;
if options.verbose {
println!("assembled technology {:?} layer mapping", tech_library.name);
}
let library = match raw::Library::from_proto(proto_library, Some(Ptr::new(tech_layers))) {
Err(err) => panic!("Couldn't load library from protobuf: {}", err),
Ok(lib) => lib,
};
let gds_library = match library.to_gds() {
Err(err) => panic!("Couldn't convert to GDS library: {}", err),
Ok(lib) => lib,
};
gds_library.save(&options.gds)?;
if options.verbose {
println!("wrote: {:?}", &options.gds);
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use chrono::NaiveDateTime;
use gds21::GdsLibrary;
#[test]
fn roundtrip_to_golden_file() {
let golden_input_path = resource("sky130_fd_sc_hd__dfxtp_1.pb");
let golden_tech_path = resource("sky130.technology.pb");
let golden_output_path = resource("sky130_fd_sc_hd__dfxtp_1.roundtrip.gds");
let golden_bytes = match std::fs::read(&golden_output_path) {
Ok(bytes) => bytes,
Err(_err) => panic!("Could not read golden output file"),
};
let mut golden_gds = match GdsLibrary::from_bytes(&golden_bytes) {
Ok(lib) => lib,
Err(_err) => panic!("Could not create golden GDS library"),
};
let output_path = resource("proto2gds_test_output.gds");
let options = ProgramOptions {
proto: golden_input_path,
gds: output_path.clone(),
tech: golden_tech_path,
verbose: true,
};
let result = _main(&options);
assert!(result.is_ok());
let output_bytes = match std::fs::read(&output_path) {
Ok(bytes) => bytes,
Err(_err) => panic!("Could not read test output file"),
};
let mut output_gds = match GdsLibrary::from_bytes(&output_bytes) {
Ok(lib) => lib,
Err(_err) => panic!("Could not create GDS library from test output"),
};
let date = NaiveDateTime::from_timestamp(0, 0);
golden_gds.set_all_dates(date.clone());
output_gds.set_all_dates(date.clone());
assert_eq!(output_gds, golden_gds);
}
fn resource(rname: &str) -> String {
format!("{}/resources/{}", env!("CARGO_MANIFEST_DIR"), rname)
}
}