libreda-lefdef 0.0.5

LEF/DEF input/output for libreda-db.
Documentation
// Copyright (c) 2021-2021 Thomas Kramer.
// SPDX-FileCopyrightText: 2022 Thomas Kramer <code@tkramer.ch>
//
// SPDX-License-Identifier: AGPL-3.0-or-later

//! LEF and DEF input/output for the LibrEDA framework.
//!
//! LEF and DEF have their own data structures which are kept very close to the both file formats.
//! The [`import`] module provides functions to convert LEF and DEF structures
//! into a type which supports the [`L2NEdit`] trait.
//! Similar the [`export`] module helps converting [`L2NBase`] types into DEF structures.
//!
//! # Current limitations
//!
//! Currently there's no writer implemented for LEF because normally place and route tools
//! will not modify the LEF file. There was just no need yet.
//!
//! Data import from LEF and DEF is quite minimal yet. From DEF
//! there is no routing information being imported. Currently, design import from DEF
//! is only useful as input for placment and routing but not for post-routing stages.
//!
//! # Examples
//!
//! ## Read and import a LEF File
//!
//! ```
//! use std::fs::File;
//! use std::io::BufReader;
//! use libreda_lefdef::lef_parser;
//!
//! // Open a LEF file.
//! let f = File::open("./tests/data/lef_examples/freepdk45/gscl45nm.lef").unwrap();
//! // Create a buffered reader for faster reading.
//! let mut buf = BufReader::new(f);
//!
//! // Read the LEF data.
//! let result = lef_parser::read_lef_bytes(&mut buf);
//!
//! if result.is_err() {
//!     // Handle IO errors and parsing errors.
//!     println!("Failed to parse LEF: {:?}", result);
//! }
//!
//! // Access the LEF structure.
//! let lef = result.expect("Failed to parse LEF.");
//!
//! // Import a LEF library into the DB format.
//! use libreda_lefdef::import;
//! use libreda_lefdef::libreda_db::prelude::*;
//! let mut chip = Chip::new();
//! let import_options = import::LEFImportOptions::default();
//! import::import_lef_into_db(&import_options, &lef, &mut chip)
//!   .expect("Failed to import LEF.");
//! ```
//!
//! ## Read and import a DEF File
//!
//! ```
//! use std::fs::File;
//! use std::io::BufReader;
//! use libreda_lefdef::def_parser;
//!
//! // Open a DEF file.
//! let f = File::open("./tests/data/def_examples/dummy.def").unwrap();
//! // Create a buffered reader for faster reading.
//! let mut buf = BufReader::new(f);
//!
//! // Read the LEF data.
//! let result = def_parser::read_def_bytes(&mut buf);
//!
//! if result.is_err() {
//!     // Handle IO errors and parsing errors.
//!     println!("Failed to parse DEF: {:?}", result);
//! }
//!
//! // Access the DEF structure.
//! let def = result.expect("Failed to parse DEF.");
//!
//! // Import a DEF design into the DB format.
//! // Note that in this example the DEF file does not contain any components (cell instances)
//! // because otherwise this example would require to also import a (LEF) library first.
//! use libreda_lefdef::import;
//! use libreda_lefdef::libreda_db::prelude::*;
//! // Create an empty layout.
//! let mut chip = Chip::new();
//!
//! let mut import_options = import::DEFImportOptions::default();
//! // Disable import of wiring for the sake of simplicity.
//! // This way, a LEF structure is not necessary during the DEF import.
//! import_options.import_wiring = false;
//!
//! // Start the import.
//! import::import_def_into_db(&import_options, None, &def, &mut chip)
//!   .expect("Failed to import DEF.");
//! ```
//!
//! ## Export to DEF
//!
//! Designs can be exported to DEF. However, DEF has a flat hierarchy and supports only a top-level design with
//! child instances, called 'components'. A design must eventually be flattened before exported to DEF.
//!
//! The export to DEF first creates a DEF data-structure which can then be serialized.
//!
//! ```
//! use libreda_lefdef::libreda_db::prelude::*;
//! use libreda_lefdef::DEF;
//! use libreda_lefdef::export::{export_db_to_def, DEFExportOptions};
//!
//! // Create a design to be exported.
//! let mut chip = Chip::new();
//! let outline_layer = chip.create_layer(1, 0); // Outline layer is necessary for exporting to DEF.
//!
//! // The design must contain at least one cell, which will be the top-level.
//! let top = chip.create_cell("TOP".into());
//! // Create cell outline.
//! chip.insert_shape(&top, &outline_layer, Rect::new((0, 0), (10, 10)).into());
//!
//! // Populate a DEF structure with the data from the `chip`.
//! let mut def = DEF::default();
//! let mut options = DEFExportOptions::default();
//! options.outline_layer = Some(outline_layer);
//! // Do the conversion.
//! let result = export_db_to_def(&options, &chip, &top, &mut def);
//! assert!(result.is_ok()); // Handle errors.
//! ```
//!
//! ## Write DEF
//!
//! A `DEF` structure can be serialized into the DEF format.
//!
//! ```
//! use libreda_lefdef::DEF;
//! use libreda_lefdef::def_writer::*;
//!
//! // Create a new empty DEF.
//! let mut def = DEF::default();
//! // Fill it with data. Consider using the export functions for this.
//! def.design_name = Some("MyDesign".to_string());
//!
//! // Serialize to a 'writer'. This can be any type implementing the `Write` trait.
//! let mut buffer: Vec<u8> = Vec::new();
//! let result = write_def(&mut buffer, &def);
//! assert!(result.is_ok()); // Handle errors.
//!
//! ```
//!
//!
//!
//!
//! [`L2NEdit`]: trait@libreda_db::traits::L2NEdit
//! [`L2NBase`]: trait@libreda_db::traits::L2NBase

#![deny(missing_docs)]
// TODO: Remove those once this crate stabilizes.
#![allow(unused)]

pub use libreda_db;

// Public exports.
pub mod def_parser;
pub mod def_writer;
pub mod lef_parser;

pub mod common;
pub mod def_ast;
pub mod lef_ast;

pub use def_ast::DEF;
pub use lef_ast::LEF;

pub mod export;
pub mod import;
mod lef_export;

mod stream_parser;

// TODO: Implementations of netlist/layout views.
mod def_impl;
mod lef_impl;
mod lef_tech_adapter;

pub use crate::def_parser::DEFReaderConfig;
pub use crate::def_writer::DEFWriterError;
pub use crate::lef_tech_adapter::LEFDesignRuleAdapter;
pub use crate::stream_parser::LefDefParseError;
use std::fs::File;
use std::io::{BufReader, BufWriter, Read, Write};
use std::path::Path;

// Implement shortcuts for loading/storing LEF and DEF.
impl LEF {
    /// Deserialize a LEF from a `Write` trait object.
    ///
    pub fn load<R: Read>(reader: &mut R) -> Result<LEF, LefDefParseError> {
        // Read the LEF data.
        lef_parser::read_lef_bytes(reader)
    }

    /// Shortcut for reading a LEF library from a file.
    pub fn load_file(path: impl AsRef<Path>) -> Result<LEF, LefDefParseError> {
        let f =
            File::open(path).map_err(|_err| LefDefParseError::Other("Failed to open LEF file."))?;
        // Create a buffered reader for faster reading.
        let mut buf = BufReader::new(f);

        Self::load(&mut buf)
    }

    // /// Shortcut for writing a LEF library to a file.
    // pub fn store_file(&self, path: impl AsRef<Path>) -> Result<(), LefDefError> {
    //     unimplemented!()
    // }
    //
    // /// Serialize to a `Write` trait object.
    // pub fn store<W: Write>(&self, writer: &mut W) -> Result<(), LefDefError> {
    //     unimplemented!()
    // }
}

impl DEF {
    /// Deserialize a DEF from a `Write` trait object.
    pub fn load<R: Read>(
        config: &DEFReaderConfig,
        reader: &mut R,
    ) -> Result<DEF, LefDefParseError> {
        // Read the DEF data.
        def_parser::read_def_bytes(reader)
    }

    /// Shortcut for reading a LEF library from a file.
    pub fn load_file(
        config: &DEFReaderConfig,
        path: impl AsRef<Path>,
    ) -> Result<DEF, LefDefParseError> {
        let f =
            File::open(path).map_err(|_err| LefDefParseError::Other("Failed to open DEF file."))?;
        // Create a buffered reader for faster reading.
        let mut buf = BufReader::new(f);

        Self::load(config, &mut buf)
    }

    /// Shortcut for writing a LEF library to a file.
    pub fn store_file(&self, path: impl AsRef<Path>) -> Result<(), DEFWriterError> {
        let f = File::create(path)?;
        let mut buf = BufWriter::new(f);
        self.store(&mut buf)
    }

    /// Serialize to a `Write` trait object.
    pub fn store<W: Write>(&self, writer: &mut W) -> Result<(), DEFWriterError> {
        def_writer::write_def(writer, self)
    }
}