Skip to content

Commit 5ae1fd0

Browse files
authored
Implement Serialization + Deserialization (#12)
* work on serde * finish deserialization * fix operand parsing
1 parent 0178774 commit 5ae1fd0

File tree

4 files changed

+208
-1
lines changed

4 files changed

+208
-1
lines changed

Cargo.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,11 @@ default-run = "main"
77
[dependencies]
88
bitvec = { version = "1.0.1" }
99
petgraph = { version = "0.8.2", optional = true }
10+
serde = { version = "1.0.219", optional = true, features = ["derive"] }
11+
serde_json = { version = "1.0.141", optional = true }
1012

1113
[features]
1214
# default = [ ]
13-
default = [ "graph" ]
15+
default = [ "graph", "serde" ]
1416
graph = [ "petgraph" ]
17+
serde = [ "dep:serde", "serde_json", "bitvec/serde" ]

examples/lut.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use circuit::{
66
};
77

88
#[derive(Debug, Clone)]
9+
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
910
struct Lut {
1011
lookup_table: BitVec,
1112
id: Identifier,
@@ -83,4 +84,12 @@ fn main() {
8384

8485
// Print the netlist
8586
println!("{netlist}");
87+
88+
#[cfg(feature = "serde")]
89+
{
90+
let res = netlist.reclaim().unwrap().serialize(std::io::stdout());
91+
if res.is_err() {
92+
eprintln!("Failed to serialize netlist: {:?}", res.err());
93+
}
94+
}
8695
}

src/circuit.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use crate::attribute::Parameter;
88

99
/// Signals in a circuit can be binary, tri-state, or four-state.
1010
#[derive(Debug, Clone, PartialEq, Eq, Hash, Copy)]
11+
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1112
pub enum DataType {
1213
/// A logical 0 or 1
1314
TwoState,
@@ -41,6 +42,7 @@ impl DataType {
4142

4243
/// The type of identifier labelling a circuit node
4344
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
45+
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
4446
pub enum IdentifierType {
4547
/// A normal identifier
4648
Normal,
@@ -52,6 +54,7 @@ pub enum IdentifierType {
5254

5355
/// An identifier of a node in a circuit
5456
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
57+
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
5558
pub struct Identifier {
5659
/// The name of the identifier
5760
name: String,
@@ -142,6 +145,7 @@ impl std::fmt::Display for Identifier {
142145

143146
/// A net in a circuit, which is identified with a name and data type.
144147
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
148+
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
145149
pub struct Net {
146150
identifier: Identifier,
147151
data_type: DataType,
@@ -274,6 +278,7 @@ pub trait Instantiable: Clone {
274278

275279
/// A tagged union for objects in a digital circuit, which can be either an input net or an instance of a module or primitive.
276280
#[derive(Debug, Clone)]
281+
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
277282
pub enum Object<I>
278283
where
279284
I: Instantiable,

src/netlist.rs

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use crate::{
1212
use std::{
1313
cell::{Ref, RefCell, RefMut},
1414
collections::{HashMap, HashSet},
15+
num::ParseIntError,
1516
rc::{Rc, Weak},
1617
};
1718

@@ -106,6 +107,7 @@ impl Gate {
106107

107108
/// An operand to an [Instantiable]
108109
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
110+
#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
109111
enum Operand {
110112
/// An index into the list of objects
111113
DirectIndex(usize),
@@ -139,6 +141,33 @@ impl Operand {
139141
}
140142
}
141143

144+
impl std::fmt::Display for Operand {
145+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
146+
match self {
147+
Operand::DirectIndex(idx) => write!(f, "{idx}"),
148+
Operand::CellIndex(idx, j) => write!(f, "{idx}.{j}"),
149+
}
150+
}
151+
}
152+
153+
impl std::str::FromStr for Operand {
154+
type Err = ParseIntError;
155+
156+
fn from_str(s: &str) -> Result<Self, Self::Err> {
157+
match s.split_once('.') {
158+
Some((idx, j)) => {
159+
let idx = idx.parse::<usize>()?;
160+
let j = j.parse::<usize>()?;
161+
Ok(Operand::CellIndex(idx, j))
162+
}
163+
None => {
164+
let idx = s.parse::<usize>()?;
165+
Ok(Operand::DirectIndex(idx))
166+
}
167+
}
168+
}
169+
}
170+
142171
/// An object that has a reference to its owning netlist/module
143172
#[derive(Debug)]
144173
struct OwnedObject<I, O>
@@ -1796,6 +1825,15 @@ where
17961825
pub fn dfs(&self, from: NetRef<I>) -> impl Iterator<Item = NetRef<I>> {
17971826
iter::DFSIterator::new(self, from)
17981827
}
1828+
1829+
#[cfg(feature = "serde")]
1830+
/// Serializes the netlist to a writer.
1831+
pub fn serialize(self, writer: impl std::io::Write) -> Result<(), serde_json::Error>
1832+
where
1833+
I: ::serde::Serialize,
1834+
{
1835+
serde::netlist_serialize(self, writer)
1836+
}
17991837
}
18001838

18011839
impl<I> std::fmt::Display for Netlist<I>
@@ -1989,3 +2027,155 @@ fn test_delete_netlist() {
19892027
pub type GateNetlist = Netlist<Gate>;
19902028
/// A type alias to Gate circuit nodes
19912029
pub type GateRef = NetRef<Gate>;
2030+
2031+
#[cfg(feature = "serde")]
2032+
/// Serde support for netlists
2033+
pub mod serde {
2034+
use super::{Netlist, Operand, OwnedObject, WeakIndex};
2035+
use crate::{
2036+
attribute::{AttributeKey, AttributeValue},
2037+
circuit::{Instantiable, Net, Object},
2038+
};
2039+
use serde::{Deserialize, Serialize, de::DeserializeOwned};
2040+
use std::cell::RefCell;
2041+
use std::{collections::HashMap, rc::Rc};
2042+
2043+
#[derive(Debug, Serialize, Deserialize)]
2044+
struct SerdeObject<I>
2045+
where
2046+
I: Instantiable + Serialize,
2047+
{
2048+
/// The object that is owned by the netlist
2049+
object: Object<I>,
2050+
/// The list of operands for the object
2051+
operands: Vec<Option<Operand>>,
2052+
/// A collection of attributes for the object
2053+
attributes: HashMap<AttributeKey, AttributeValue>,
2054+
}
2055+
2056+
impl<I, O> From<OwnedObject<I, O>> for SerdeObject<I>
2057+
where
2058+
I: Instantiable + Serialize,
2059+
O: WeakIndex<usize, Output = OwnedObject<I, O>>,
2060+
{
2061+
fn from(value: OwnedObject<I, O>) -> Self {
2062+
SerdeObject {
2063+
object: value.object,
2064+
operands: value.operands,
2065+
attributes: value.attributes,
2066+
}
2067+
}
2068+
}
2069+
2070+
impl<I> SerdeObject<I>
2071+
where
2072+
I: Instantiable + Serialize,
2073+
{
2074+
fn into_owned_object<O>(self, owner: &Rc<O>, index: usize) -> OwnedObject<I, O>
2075+
where
2076+
O: WeakIndex<usize, Output = OwnedObject<I, O>>,
2077+
{
2078+
OwnedObject {
2079+
object: self.object,
2080+
owner: Rc::downgrade(owner),
2081+
operands: self.operands,
2082+
attributes: self.attributes,
2083+
index,
2084+
}
2085+
}
2086+
}
2087+
2088+
#[derive(Debug, Serialize, Deserialize)]
2089+
struct SerdeNetlist<I>
2090+
where
2091+
I: Instantiable + Serialize,
2092+
{
2093+
/// The name of the netlist
2094+
name: String,
2095+
/// The list of objects in the netlist, such as inputs, modules, and primitives
2096+
objects: Vec<SerdeObject<I>>,
2097+
/// The list of operands that point to objects which are outputs
2098+
outputs: HashMap<String, Net>,
2099+
}
2100+
2101+
impl<I> From<Netlist<I>> for SerdeNetlist<I>
2102+
where
2103+
I: Instantiable + Serialize,
2104+
{
2105+
fn from(value: Netlist<I>) -> Self {
2106+
SerdeNetlist {
2107+
name: value.name,
2108+
objects: value
2109+
.objects
2110+
.into_inner()
2111+
.into_iter()
2112+
.map(|o| {
2113+
Rc::try_unwrap(o)
2114+
.ok()
2115+
.expect("Cannot serialize with live references")
2116+
.into_inner()
2117+
.into()
2118+
})
2119+
.collect(),
2120+
outputs: value
2121+
.outputs
2122+
.into_inner()
2123+
.into_iter()
2124+
// TODO(matth2k): Indices must be a string. This is a workaround until de-serialize is implemented.
2125+
.map(|(o, n)| (o.to_string(), n))
2126+
.collect(),
2127+
}
2128+
}
2129+
}
2130+
2131+
impl<I> SerdeNetlist<I>
2132+
where
2133+
I: Instantiable + Serialize,
2134+
{
2135+
/// Convert the serialized netlist back into a reference-counted netlist.
2136+
fn into_netlist(self) -> Rc<Netlist<I>> {
2137+
let netlist = Netlist::new(self.name);
2138+
let outputs: HashMap<Operand, Net> = self
2139+
.outputs
2140+
.into_iter()
2141+
.map(|(k, v)| {
2142+
let operand = k.parse::<Operand>().expect("Invalid index");
2143+
(operand, v)
2144+
})
2145+
.collect();
2146+
let objects = self
2147+
.objects
2148+
.into_iter()
2149+
.enumerate()
2150+
.map(|(i, o)| {
2151+
let owned_object = o.into_owned_object(&netlist, i);
2152+
Rc::new(RefCell::new(owned_object))
2153+
})
2154+
.collect::<Vec<_>>();
2155+
{
2156+
let mut objs_mut = netlist.objects.borrow_mut();
2157+
*objs_mut = objects;
2158+
let mut outputs_mut = netlist.outputs.borrow_mut();
2159+
*outputs_mut = outputs;
2160+
}
2161+
netlist
2162+
}
2163+
}
2164+
2165+
/// Serialize the netlist into the writer.
2166+
pub fn netlist_serialize<I: Instantiable + Serialize>(
2167+
netlist: Netlist<I>,
2168+
writer: impl std::io::Write,
2169+
) -> Result<(), serde_json::Error> {
2170+
let sobj: SerdeNetlist<I> = netlist.into();
2171+
serde_json::to_writer_pretty(writer, &sobj)
2172+
}
2173+
2174+
/// Deserialize a netlist from the reader.
2175+
pub fn netlist_deserialize<I: Instantiable + Serialize + DeserializeOwned>(
2176+
reader: impl std::io::Read,
2177+
) -> Result<Rc<Netlist<I>>, serde_json::Error> {
2178+
let sobj: SerdeNetlist<I> = serde_json::from_reader(reader)?;
2179+
Ok(sobj.into_netlist())
2180+
}
2181+
}

0 commit comments

Comments
 (0)