use std::collections::HashMap;
use std::io::{Read, Write};
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate slog;
#[derive(Copy, Clone, Serialize, Deserialize, Debug, Eq, PartialEq, Hash)]
pub enum PortDirection {
#[serde(rename = "input")]
Input,
#[serde(rename = "output")]
Output,
#[serde(rename = "inout")]
InOut,
}
#[derive(Copy, Clone, Serialize, Deserialize, Debug, Eq, PartialEq, Hash)]
pub enum SpecialBit {
#[serde(rename = "0")]
_0,
#[serde(rename = "1")]
_1,
#[serde(rename = "x")]
X,
#[serde(rename = "z")]
Z,
}
impl slog::Value for SpecialBit {
fn serialize(&self, _record: &slog::Record, key: slog::Key, serializer: &mut dyn slog::Serializer) -> slog::Result {
match self {
&SpecialBit::_0 => serializer.emit_str(key, "0"),
&SpecialBit::_1 => serializer.emit_str(key, "1"),
&SpecialBit::X => serializer.emit_str(key, "x"),
&SpecialBit::Z => serializer.emit_str(key, "z"),
}
}
}
#[derive(Copy, Clone, Serialize, Deserialize, Debug, Eq, PartialEq, Hash)]
#[serde(untagged)]
pub enum BitVal {
N(usize),
S(SpecialBit)
}
impl slog::Value for BitVal {
fn serialize(&self, record: &slog::Record, key: slog::Key, serializer: &mut dyn slog::Serializer) -> slog::Result {
match self {
&BitVal::N(n) => {
serializer.emit_usize(key, n)
},
&BitVal::S(s) => {
s.serialize(record, key, serializer)
}
}
}
}
#[derive(Clone, Serialize, Deserialize, Debug, Eq, PartialEq, Hash)]
#[serde(untagged)]
pub enum AttributeVal {
N(usize),
S(String),
}
impl AttributeVal {
pub fn to_number(&self) -> Option<usize> {
match self {
&AttributeVal::N(n) => Some(n),
&AttributeVal::S(ref s) => {
if s.len() == 0 {
Some(0)
} else {
usize::from_str_radix(s, 2).ok()
}
}
}
}
pub fn to_string_if_string(&self) -> Option<&str> {
match self {
&AttributeVal::N(_) => None,
&AttributeVal::S(ref s) => {
if s.len() == 0 {
None
} else if s.find(|c| !(c == '0' || c == '1' || c == 'x' || c == 'z')).is_none() {
None
} else {
if *s.as_bytes().last().unwrap() == b' ' {
Some(s.split_at(s.len() - 1).0)
} else {
Some(s)
}
}
}
}
}
}
impl slog::Value for AttributeVal {
fn serialize(&self, _record: &slog::Record, key: slog::Key, serializer: &mut dyn slog::Serializer) -> slog::Result {
match self {
&AttributeVal::N(n) => {
serializer.emit_usize(key, n)
},
&AttributeVal::S(ref s) => {
serializer.emit_str(key, s)
}
}
}
}
#[derive(Clone, Serialize, Deserialize, Debug, Default, Eq, PartialEq)]
pub struct Netlist {
#[serde(default)]
pub creator: String,
#[serde(default)]
pub modules: HashMap<String, Module>,
}
#[derive(Clone, Serialize, Deserialize, Debug, Default, Eq, PartialEq)]
pub struct Module {
#[serde(default)]
pub attributes: HashMap<String, AttributeVal>,
#[serde(default)]
pub ports: HashMap<String, Port>,
#[serde(default)]
pub cells: HashMap<String, Cell>,
#[serde(default)]
pub netnames: HashMap<String, Netname>,
}
#[derive(Clone, Serialize, Deserialize, Debug, Eq, PartialEq)]
pub struct Port {
pub direction: PortDirection,
pub bits: Vec<BitVal>,
}
#[derive(Clone, Serialize, Deserialize, Debug, Eq, PartialEq)]
pub struct Cell {
#[serde(default)]
pub hide_name: usize,
#[serde(rename="type")]
pub cell_type: String,
#[serde(default)]
pub parameters: HashMap<String, AttributeVal>,
#[serde(default)]
pub attributes: HashMap<String, AttributeVal>,
#[serde(default)]
pub port_directions: HashMap<String, PortDirection>,
pub connections: HashMap<String, Vec<BitVal>>,
}
#[derive(Clone, Serialize, Deserialize, Debug, Eq, PartialEq)]
pub struct Netname {
#[serde(default)]
pub hide_name: usize,
pub bits: Vec<BitVal>,
#[serde(default)]
pub attributes: HashMap<String, AttributeVal>,
}
impl Netlist {
pub fn from_reader<R: Read>(reader: R) -> Result<Netlist, serde_json::Error> {
serde_json::from_reader(reader)
}
pub fn from_slice(input: &[u8]) -> Result<Netlist, serde_json::Error> {
serde_json::from_slice(input)
}
pub fn to_string(&self) -> Result<String, serde_json::Error> {
serde_json::to_string(self)
}
pub fn to_writer<W: Write>(&self, writer: W) -> Result<(), serde_json::Error> {
serde_json::to_writer(writer, self)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn super_empty_json() {
let result = Netlist::from_slice(br#"
{}"#).unwrap();
assert_eq!(result.creator, "");
assert_eq!(result.modules.len(), 0);
}
#[test]
fn empty_json() {
let result = Netlist::from_slice(br#"
{
"creator": "this is a test",
"modules": {
}
}"#).unwrap();
assert_eq!(result.creator, "this is a test");
assert_eq!(result.modules.len(), 0);
}
#[test]
fn empty_json_2() {
let result = Netlist::from_slice(br#"
{
"modules": {
}
}"#).unwrap();
assert_eq!(result.creator, "");
assert_eq!(result.modules.len(), 0);
}
#[test]
fn bit_values_test() {
let result = Netlist::from_slice(br#"
{
"modules": {
"mymodule": {
"cells": {
"mycell": {
"type": "celltype",
"connections": {
"IN": [ "x", 0, "z", 234, "1", "0" ]
}
}
}
}
}
}"#).unwrap();
assert_eq!(result.modules.get("mymodule").unwrap().cells.get("mycell").unwrap().connections.get("IN").unwrap(),
&vec![BitVal::S(SpecialBit::X), BitVal::N(0), BitVal::S(SpecialBit::Z), BitVal::N(234),
BitVal::S(SpecialBit::_1), BitVal::S(SpecialBit::_0)]);
}
#[test]
#[should_panic]
fn invalid_bit_value_test() {
Netlist::from_slice(br#"
{
"modules": {
"mymodule": {
"cells": {
"mycell": {
"type": "celltype",
"connections": {
"IN": [ "w" ]
}
}
}
}
}
}"#).unwrap();
}
#[test]
fn attribute_value_test() {
let result = Netlist::from_slice(br#"
{
"modules": {
"mymodule": {
"cells": {
"mycell": {
"type": "celltype",
"parameters": {
"testparam": 123
},
"connections": {}
}
}
}
}
}"#).unwrap();
assert_eq!(result.modules.get("mymodule").unwrap().cells.get("mycell").unwrap()
.parameters.get("testparam").unwrap(), &AttributeVal::N(123));
}
#[test]
#[should_panic]
fn invalid_attribute_value_test() {
Netlist::from_slice(br#"
{
"modules": {
"mymodule": {
"cells": {
"mycell": {
"type": "celltype",
"parameters": {
"testparam": [123]
},
"connections": {}
}
}
}
}
}"#).unwrap();
}
}