scir/
lib.rs

1//! Schematic cell intermediate representation (SCIR).
2//!
3//! An intermediate-level representation of schematic cells and instances.
4//!
5//! Unlike higher-level Substrate APIs, the structures in this crate use
6//! strings, rather than generics, to specify ports and connections.
7//!
8//! This format is designed to be easy to generate from high-level APIs and
9//! easy to parse from lower-level formats, such as SPICE or structural Verilog.
10//!
11//! SCIR supports single-bit wires and 1-dimensional buses.
12//! Higher-dimensional buses should be flattened to 1-dimensional buses or single bits
13//! when converting to SCIR.
14//!
15//! Single-bit wires are not exactly the same as single-bit buses:
16//! A single bit wire named `x` will typically be exported to netlists as `x`,
17//! unless the name contains reserved characters or is a keyword in the target
18//! netlist format.
19//! On the other hand, a bus named `x` with width 1
20//! will typically be exported as `x[0]`.
21//! Furthermore, whenever a 1-bit bus is used, a zero index must be specified.
22//! However, single bit wires require that no index is specified.
23//!
24//! Zero-width buses are not supported.
25#![warn(missing_docs)]
26
27use std::collections::{HashMap, HashSet, VecDeque};
28use std::fmt::{Display, Formatter};
29use std::ops::{Deref, DerefMut};
30
31use arcstr::ArcStr;
32use diagnostics::IssueSet;
33use drivers::DriverIssue;
34use indexmap::IndexMap;
35use rust_decimal::Decimal;
36use serde::{Deserialize, Serialize};
37use tracing::{Level, span};
38use uniquify::Names;
39
40use crate::schema::{FromSchema, NoSchema, NoSchemaError, Schema};
41use crate::validation::ValidatorIssue;
42pub use slice::{Concat, IndexOwned, NamedSlice, NamedSliceOne, Slice, SliceOne, SliceRange};
43
44pub mod drivers;
45pub mod merge;
46pub mod netlist;
47pub mod schema;
48mod slice;
49pub mod validation;
50
51#[cfg(test)]
52pub(crate) mod tests;
53
54/// A value of a parameter.
55#[enumify::enumify(no_as_ref, no_as_mut)]
56#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
57pub enum ParamValue {
58    /// A string parameter value.
59    String(ArcStr),
60    /// A numeric parameter value.
61    Numeric(Decimal),
62}
63
64impl From<ArcStr> for ParamValue {
65    fn from(value: ArcStr) -> Self {
66        Self::String(value)
67    }
68}
69
70impl From<Decimal> for ParamValue {
71    fn from(value: Decimal) -> Self {
72        Self::Numeric(value)
73    }
74}
75
76impl Display for ParamValue {
77    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
78        match self {
79            ParamValue::String(s) => write!(f, "{}", s),
80            ParamValue::Numeric(n) => write!(f, "{}", n),
81        }
82    }
83}
84
85/// An opaque signal identifier.
86///
87/// A signal ID created in the context of one cell must
88/// *not* be used in the context of another cell.
89/// You should instead create a new signal ID in the second cell.
90#[derive(
91    Copy, Clone, Debug, Default, Hash, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize,
92)]
93pub struct SignalId(u64);
94
95impl From<Slice> for SignalId {
96    #[inline]
97    fn from(value: Slice) -> Self {
98        value.signal()
99    }
100}
101
102impl From<SliceOne> for SignalId {
103    #[inline]
104    fn from(value: SliceOne) -> Self {
105        value.signal()
106    }
107}
108
109/// A path to a nested [`Slice`].
110#[derive(Clone, Debug, Hash, Eq, PartialEq, Serialize, Deserialize)]
111pub struct SlicePath(SignalPath<Slice, NamedSlice>);
112
113impl SlicePath {
114    /// Returns the instance path associated with this path.
115    pub fn instances(&self) -> &InstancePath {
116        &self.0.instances
117    }
118    /// Returns a mutable pointer to the instance path associated with this path.
119    pub fn instances_mut(&mut self) -> &mut InstancePath {
120        &mut self.0.instances
121    }
122    /// Returns the tail of this path.
123    ///
124    /// The tail includes information on the signal that this path addresses.
125    pub fn tail(&self) -> &SignalPathTail<Slice, NamedSlice> {
126        &self.0.tail
127    }
128}
129
130/// A path to a nested [`SliceOne`].
131#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
132pub struct SliceOnePath(SignalPath<SliceOne, NamedSliceOne>);
133
134impl SliceOnePath {
135    /// Creates a new [`SliceOnePath`].
136    pub fn new(
137        instances: InstancePath,
138        tail: impl Into<SignalPathTail<SliceOne, NamedSliceOne>>,
139    ) -> Self {
140        Self(SignalPath {
141            instances,
142            tail: tail.into(),
143        })
144    }
145    /// Returns the instance path associated with this path.
146    pub fn instances(&self) -> &InstancePath {
147        &self.0.instances
148    }
149    /// Returns a mutable pointer to the instance path associated with this path.
150    pub fn instances_mut(&mut self) -> &mut InstancePath {
151        &mut self.0.instances
152    }
153    /// Returns the tail of this path.
154    ///
155    /// The tail includes information on the signal that this path addresses.
156    pub fn tail(&self) -> &SignalPathTail<SliceOne, NamedSliceOne> {
157        &self.0.tail
158    }
159}
160
161/// A path to a signal of type `I` or `N` in a SCIR library.
162#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
163struct SignalPath<I, N> {
164    instances: InstancePath,
165    tail: SignalPathTail<I, N>,
166}
167
168/// The end of a signal path.
169#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
170#[enumify::enumify(generics_only)]
171pub enum SignalPathTail<I, N> {
172    /// A signal addressed by ID.
173    Id(I),
174    /// A signal addressed by name.
175    Name(N),
176}
177
178impl From<Slice> for SignalPathTail<Slice, NamedSlice> {
179    fn from(value: Slice) -> Self {
180        SignalPathTail::Id(value)
181    }
182}
183
184impl From<NamedSlice> for SignalPathTail<Slice, NamedSlice> {
185    fn from(value: NamedSlice) -> Self {
186        SignalPathTail::Name(value)
187    }
188}
189
190impl SignalPathTail<Slice, NamedSlice> {
191    /// The range of indices indexed by this signal path tail.
192    ///
193    /// Returns [`None`] if this slice represents a single bit wire.
194    pub fn range(&self) -> Option<SliceRange> {
195        match self {
196            SignalPathTail::Id(slice) => slice.range(),
197            SignalPathTail::Name(slice) => slice.range(),
198        }
199    }
200}
201
202impl From<SliceOne> for SignalPathTail<SliceOne, NamedSliceOne> {
203    fn from(value: SliceOne) -> Self {
204        SignalPathTail::Id(value)
205    }
206}
207
208impl From<NamedSliceOne> for SignalPathTail<SliceOne, NamedSliceOne> {
209    fn from(value: NamedSliceOne) -> Self {
210        SignalPathTail::Name(value)
211    }
212}
213
214impl SignalPathTail<SliceOne, NamedSliceOne> {
215    /// The index this single-bit signal path tail contains.
216    pub fn index(&self) -> Option<usize> {
217        match self {
218            SignalPathTail::Id(slice) => slice.index(),
219            SignalPathTail::Name(slice) => slice.index(),
220        }
221    }
222}
223
224/// A path to an instance in a SCIR library.
225#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
226pub struct InstancePath {
227    /// The top cell of the path.
228    top: InstancePathCell,
229    /// Path of SCIR instances.
230    elems: Vec<InstancePathElement>,
231}
232
233impl Deref for InstancePath {
234    type Target = Vec<InstancePathElement>;
235
236    fn deref(&self) -> &Self::Target {
237        &self.elems
238    }
239}
240
241impl DerefMut for InstancePath {
242    fn deref_mut(&mut self) -> &mut Self::Target {
243        &mut self.elems
244    }
245}
246
247impl InstancePath {
248    /// Creates a new empty [`InstancePath`] with the given reference point.
249    pub fn new(top: impl Into<InstancePathCell>) -> Self {
250        Self {
251            top: top.into(),
252            elems: Vec::new(),
253        }
254    }
255
256    /// Pushes a new instance to the path.
257    pub fn push(&mut self, elem: impl Into<InstancePathElement>) {
258        self.elems.push(elem.into())
259    }
260
261    /// Pushes an iterator of instances to the path.
262    pub fn push_iter<E: Into<InstancePathElement>>(&mut self, elems: impl IntoIterator<Item = E>) {
263        for elem in elems {
264            self.push(elem);
265        }
266    }
267
268    /// Returns the top cell of the path.
269    pub fn top(&self) -> &InstancePathCell {
270        &self.top
271    }
272
273    /// Returns `true` if the path is empty.
274    pub fn is_empty(&self) -> bool {
275        self.elems.is_empty()
276    }
277
278    /// Creates a [`SliceOnePath`] by appending the provided `tail`.
279    pub fn slice_one(
280        self,
281        tail: impl Into<SignalPathTail<SliceOne, NamedSliceOne>>,
282    ) -> SliceOnePath {
283        SliceOnePath(SignalPath {
284            instances: self,
285            tail: tail.into(),
286        })
287    }
288}
289
290/// The cell within an [`InstancePath`].
291#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
292#[enumify::enumify]
293pub enum InstancePathCell {
294    /// A cell addressed by ID.
295    Id(CellId),
296    /// A cell addressed by name.
297    Name(ArcStr),
298}
299
300impl From<CellId> for InstancePathCell {
301    fn from(value: CellId) -> Self {
302        Self::Id(value)
303    }
304}
305
306impl<S: Into<ArcStr>> From<S> for InstancePathCell {
307    fn from(value: S) -> Self {
308        Self::Name(value.into())
309    }
310}
311
312/// An element of an [`InstancePath`].
313#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
314#[enumify::enumify]
315pub enum InstancePathElement {
316    /// An instance addressed by ID.
317    Id(InstanceId),
318    /// An instance addressed by name.
319    Name(ArcStr),
320}
321
322impl From<InstanceId> for InstancePathElement {
323    fn from(value: InstanceId) -> Self {
324        Self::Id(value)
325    }
326}
327
328impl<S: Into<ArcStr>> From<S> for InstancePathElement {
329    fn from(value: S) -> Self {
330        Self::Name(value.into())
331    }
332}
333
334/// A path to an instance in a SCIR library with annotated metadata.
335#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
336pub struct AnnotatedInstancePath {
337    /// ID or name of the top cell.
338    ///
339    /// If the name corresponds to a SCIR cell, this should always be an ID.
340    pub top: InstancePathCell,
341    /// Path of SCIR instance IDs.
342    pub instances: Vec<AnnotatedInstancePathElement>,
343}
344
345impl AnnotatedInstancePath {
346    fn bot(&self) -> Option<CellId> {
347        self.instances
348            .last()
349            .and_then(|inst| inst.child?.into_cell())
350            .or_else(|| self.top.get_id().copied())
351    }
352}
353
354/// An element of an [`AnnotatedInstancePath`].
355#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
356pub struct AnnotatedInstancePathElement {
357    /// The underlying instance path element.
358    pub elem: InstancePathElement,
359    /// The child associated with this element, if it exists.
360    pub child: Option<ChildId>,
361}
362
363impl From<AnnotatedInstancePath> for InstancePath {
364    fn from(value: AnnotatedInstancePath) -> Self {
365        let AnnotatedInstancePath { top, instances } = value;
366
367        InstancePath {
368            top,
369            elems: instances
370                .into_iter()
371                .map(|instance| instance.elem)
372                .collect(),
373        }
374    }
375}
376
377/// A path of strings to an instance or signal in a SCIR library.
378#[derive(Clone, Default, Debug, Hash, Eq, PartialEq, Serialize, Deserialize)]
379pub struct NamedPath(Vec<ArcStr>);
380
381impl Deref for NamedPath {
382    type Target = Vec<ArcStr>;
383
384    fn deref(&self) -> &Self::Target {
385        &self.0
386    }
387}
388
389impl DerefMut for NamedPath {
390    fn deref_mut(&mut self) -> &mut Self::Target {
391        &mut self.0
392    }
393}
394
395impl NamedPath {
396    fn new() -> Self {
397        Self::default()
398    }
399
400    /// Consumes the [`NamedPath`], returning the path as a [`Vec<ArcStr>`].
401    pub fn into_vec(self) -> Vec<ArcStr> {
402        self.0
403    }
404}
405
406/// An opaque cell identifier.
407///
408/// A cell ID created in the context of one library must
409/// *not* be used in the context of another library.
410/// You should instead create a new cell ID in the second library.
411#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
412pub struct CellId(u64);
413
414/// An opaque instance identifier.
415///
416/// An instance ID created in the context of one cell must
417/// *not* be used in the context of another cell.
418/// You should instead create a new instance ID in the second cell.
419#[derive(
420    Copy, Clone, Debug, Default, Hash, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize,
421)]
422pub struct InstanceId(u64);
423
424/// An opaque primitive identifier.
425///
426/// A primitive ID created in the context of one library must
427/// *not* be used in the context of another library.
428/// You should instead create a new primitive ID in the second library.
429#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
430pub struct PrimitiveId(u64);
431
432impl Display for SignalId {
433    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
434        write!(f, "signal{}", self.0)
435    }
436}
437
438impl Display for CellId {
439    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
440        write!(f, "cell{}", self.0)
441    }
442}
443
444impl Display for InstanceId {
445    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
446        write!(f, "inst{}", self.0)
447    }
448}
449
450impl Display for PrimitiveId {
451    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
452        write!(f, "primitive{}", self.0)
453    }
454}
455
456impl Display for ChildId {
457    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
458        match self {
459            ChildId::Cell(c) => c.fmt(f),
460            ChildId::Primitive(p) => p.fmt(f),
461        }
462    }
463}
464
465/// A library of SCIR cells with schema `S`.
466pub struct LibraryBuilder<S: Schema + ?Sized = NoSchema> {
467    /// The current cell ID counter.
468    ///
469    /// Initialized to 0 when the library is created.
470    /// Should be incremented before assigning a new ID.
471    cell_id: u64,
472
473    /// The current primitive ID counter.
474    ///
475    /// Initialized to 0 when the library is created.
476    /// Should be incremented before assigning a new ID.
477    primitive_id: u64,
478
479    /// A map of the cells in the library.
480    cells: IndexMap<CellId, Cell>,
481
482    /// A map of cell name to cell ID.
483    ///
484    /// Cell names are only guaranteed to be unique in a validated [`Library`].
485    name_map: HashMap<ArcStr, CellId>,
486
487    /// Assigned names for purposes of auto-assigning names to new cells.
488    names: Names<CellId>,
489
490    /// A map of the primitives in the library.
491    primitives: IndexMap<PrimitiveId, S::Primitive>,
492
493    /// The ID of the top cell, if there is one.
494    top: Option<CellId>,
495}
496
497impl<S: Schema + ?Sized> Default for LibraryBuilder<S> {
498    fn default() -> Self {
499        Self {
500            cell_id: 0,
501            primitive_id: 0,
502            cells: IndexMap::new(),
503            primitives: IndexMap::new(),
504            name_map: HashMap::new(),
505            names: Names::new(),
506            top: None,
507        }
508    }
509}
510
511impl<S: Schema<Primitive = impl Clone> + ?Sized> Clone for LibraryBuilder<S> {
512    fn clone(&self) -> Self {
513        Self {
514            cell_id: self.cell_id,
515            primitive_id: self.primitive_id,
516            cells: self.cells.clone(),
517            name_map: self.name_map.clone(),
518            names: self.names.clone(),
519            primitives: self.primitives.clone(),
520            top: self.top,
521        }
522    }
523}
524
525impl<S: Schema<Primitive = impl std::fmt::Debug> + ?Sized> std::fmt::Debug for LibraryBuilder<S> {
526    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
527        let mut builder = f.debug_struct("LibraryBuilder");
528        let _ = builder.field("cell_id", &self.cell_id);
529        let _ = builder.field("primitive_id", &self.primitive_id);
530        let _ = builder.field("cells", &self.cells);
531        let _ = builder.field("name_map", &self.name_map);
532        let _ = builder.field("names", &self.names);
533        let _ = builder.field("primitives", &self.primitives);
534        let _ = builder.field("top", &self.top);
535        builder.finish()
536    }
537}
538
539/// A SCIR library that is guaranteed to be valid (with the exception of primitives,
540/// which are opaque to SCIR).
541///
542/// The contents of the library cannot be mutated.
543pub struct Library<S: Schema + ?Sized = NoSchema>(LibraryBuilder<S>);
544
545impl<S: Schema<Primitive = impl std::fmt::Debug> + ?Sized> std::fmt::Debug for Library<S> {
546    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
547        let mut builder = f.debug_struct("Library");
548        let _ = builder.field("0", &self.0);
549        builder.finish()
550    }
551}
552
553impl<S: Schema + ?Sized> Clone for Library<S>
554where
555    LibraryBuilder<S>: Clone,
556{
557    fn clone(&self) -> Self {
558        Self(self.0.clone())
559    }
560}
561
562impl<S: Schema + ?Sized> Deref for Library<S> {
563    type Target = LibraryBuilder<S>;
564    fn deref(&self) -> &Self::Target {
565        &self.0
566    }
567}
568
569impl<S: Schema + ?Sized> Library<S> {
570    /// Converts a [`Library<S>`] to a [`Library<NoSchema>`], throwing an error if there
571    /// are any primitives.
572    pub fn drop_schema(self) -> Result<Library<NoSchema>, NoSchemaError> {
573        Ok(Library(self.0.drop_schema()?))
574    }
575
576    /// Converts a [`Library<S>`] into a [`LibraryBuilder<C>`].
577    ///
578    /// A [`LibraryBuilder`] is created to indicate that validation must be done again
579    /// to ensure errors were not introduced during the conversion.
580    pub fn convert_schema<C>(self) -> Result<LibraryBuilder<C>, C::Error>
581    where
582        C: FromSchema<S> + ?Sized,
583    {
584        self.0.convert_schema()
585    }
586
587    /// Converts this library into a [`LibraryBuilder`] that can be modified.
588    pub fn into_builder(self) -> LibraryBuilder<S> {
589        self.0
590    }
591}
592
593impl<S: Schema<Primitive = impl Clone> + ?Sized> Library<S> {
594    /// Creates a new SCIR library containing only the named cell and its children
595    /// from an existing library.
596    pub fn from_cell_named(lib: &Self, cell: &str) -> Self {
597        LibraryBuilder::from_cell_named(lib, cell).build().unwrap()
598    }
599}
600
601/// Issues encountered when validating a SCIR library.
602#[derive(Debug, Clone)]
603pub struct Issues {
604    /// Correctness issues.
605    pub correctness: IssueSet<ValidatorIssue>,
606    /// Driver connectivity issues.
607    pub drivers: IssueSet<DriverIssue>,
608}
609
610impl Display for Issues {
611    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
612        if self.correctness.is_empty() && self.drivers.is_empty() {
613            write!(f, "no issues")?;
614        }
615        if !self.correctness.is_empty() {
616            writeln!(f, "correctness issues:\n{}", self.correctness)?;
617        }
618        if !self.drivers.is_empty() {
619            writeln!(f, "driver issues:\n{}", self.drivers)?;
620        }
621        Ok(())
622    }
623}
624
625impl std::error::Error for Issues {}
626
627impl Issues {
628    /// Returns `true` if there are warnings.
629    pub fn has_warning(&self) -> bool {
630        self.correctness.has_warning() || self.drivers.has_warning()
631    }
632
633    /// Returns `true` if there are errors.
634    pub fn has_error(&self) -> bool {
635        self.correctness.has_error() || self.drivers.has_error()
636    }
637}
638
639/// Port directions.
640#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Default, Serialize, Deserialize)]
641pub enum Direction {
642    /// Input.
643    Input,
644    /// Output.
645    Output,
646    /// Input or output.
647    ///
648    /// Represents ports whose direction is not known
649    /// at generator elaboration time (e.g. the output of a tristate buffer).
650    #[default]
651    InOut,
652}
653
654impl Direction {
655    /// Returns the flipped direction.
656    ///
657    /// [`Direction::InOut`] is unchanged by flipping.
658    ///
659    /// # Examples
660    ///
661    /// ```
662    /// use scir::Direction;
663    /// assert_eq!(Direction::Input.flip(), Direction::Output);
664    /// assert_eq!(Direction::Output.flip(), Direction::Input);
665    /// assert_eq!(Direction::InOut.flip(), Direction::InOut);
666    /// ```
667    #[inline]
668    pub fn flip(&self) -> Self {
669        match *self {
670            Self::Input => Self::Output,
671            Self::Output => Self::Input,
672            Self::InOut => Self::InOut,
673        }
674    }
675
676    /// Test if two nodes of the respective directions are allowed be connected
677    /// to each other.
678    ///
679    /// # Examples
680    ///
681    /// ```
682    /// use scir::Direction;
683    /// assert_eq!(Direction::Input.is_compatible_with(Direction::Output), true);
684    /// assert_eq!(Direction::Output.is_compatible_with(Direction::Output), false);
685    /// assert_eq!(Direction::Output.is_compatible_with(Direction::InOut), true);
686    /// ```
687    pub fn is_compatible_with(&self, other: Direction) -> bool {
688        use Direction::*;
689
690        #[allow(clippy::match_like_matches_macro)]
691        match (*self, other) {
692            (Output, Output) => false,
693            _ => true,
694        }
695    }
696}
697
698impl Display for Direction {
699    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
700        match *self {
701            Self::Output => write!(f, "output"),
702            Self::Input => write!(f, "input"),
703            Self::InOut => write!(f, "inout"),
704        }
705    }
706}
707
708/// A signal exposed by a cell.
709#[derive(Debug, Clone, Serialize, Deserialize)]
710pub struct Port {
711    signal: SignalId,
712    direction: Direction,
713}
714
715/// Information about a signal in a cell.
716#[derive(Debug, Clone, Serialize, Deserialize)]
717pub struct SignalInfo {
718    /// The ID representing this signal.
719    pub id: SignalId,
720
721    /// The name of this signal.
722    pub name: ArcStr,
723
724    /// The width of this signal, if this signal is a bus.
725    ///
726    /// For single-wire signals, this will be [`None`].
727    pub width: Option<usize>,
728
729    /// Set to `Some(..)` if this signal corresponds to a port.
730    ///
731    /// The contained `usize` represents the index at which the port
732    /// corresponding to this signal starts.
733    pub port: Option<usize>,
734}
735
736impl SignalInfo {
737    /// The [`Slice`] representing this entire signal.
738    #[inline]
739    pub fn slice(&self) -> Slice {
740        Slice::new(self.id, self.width.map(SliceRange::with_width))
741    }
742
743    /// Returns `true` if this signal is exposed as a port.
744    pub fn is_port(&self) -> bool {
745        self.port.is_some()
746    }
747}
748
749/// An instance of a child cell placed inside a parent cell.
750#[derive(Debug, Clone, Serialize, Deserialize)]
751pub struct Instance {
752    /// The ID of the child.
753    child: ChildId,
754    /// The name of this instance.
755    ///
756    /// This is not necessarily the name of the child cell.
757    name: ArcStr,
758    /// A map mapping port names to connections.
759    ///
760    /// The ports are the ports of the **child** cell.
761    /// The connected signals are signals of the **parent** cell.
762    connections: HashMap<ArcStr, Concat>,
763}
764
765/// The ID of an instance's child.
766#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
767#[enumify::enumify(no_as_ref, no_as_mut)]
768pub enum ChildId {
769    /// A child cell.
770    Cell(CellId),
771    /// A child primitive.
772    ///
773    /// The contents of instance's with a child primitive are opaque to SCIR.
774    Primitive(PrimitiveId),
775}
776
777impl From<CellId> for ChildId {
778    fn from(value: CellId) -> Self {
779        Self::Cell(value)
780    }
781}
782
783impl From<PrimitiveId> for ChildId {
784    fn from(value: PrimitiveId) -> Self {
785        Self::Primitive(value)
786    }
787}
788
789/// A cell.
790#[derive(Debug, Clone, Serialize, Deserialize)]
791pub struct Cell {
792    /// The last signal ID used.
793    ///
794    /// Initialized to 0 upon cell creation.
795    signal_id: u64,
796    port_idx: usize,
797    pub(crate) name: ArcStr,
798    pub(crate) ports: IndexMap<ArcStr, Port>,
799    pub(crate) signals: HashMap<SignalId, SignalInfo>,
800    /// A map of instance name to instance ID.
801    ///
802    /// Signal names are only guaranteed to be unique in a validated [`Library`].
803    signal_name_map: HashMap<ArcStr, SignalId>,
804    /// The last instance ID assigned.
805    ///
806    /// Initialized to 0 upon cell creation.
807    instance_id: u64,
808    pub(crate) instances: IndexMap<InstanceId, Instance>,
809    /// A map of instance name to instance ID.
810    ///
811    /// Instance names are only guaranteed to be unique in a validated [`Library`].
812    instance_name_map: HashMap<ArcStr, InstanceId>,
813}
814
815/// Metadata associated with the conversion from a SCIR library to a netlist.
816#[derive(Debug, Clone, Default)]
817pub struct NetlistLibConversion {
818    /// Conversion metadata for each cell in the SCIR library.
819    pub cells: HashMap<CellId, NetlistCellConversion>,
820}
821
822impl NetlistLibConversion {
823    /// Creates a new [`NetlistLibConversion`].
824    pub fn new() -> Self {
825        Self::default()
826    }
827}
828
829/// Metadata associated with the conversion from a SCIR cell to a netlisted subcircuit.
830#[derive(Debug, Clone, Default)]
831pub struct NetlistCellConversion {
832    /// The netlisted names of SCIR instances.
833    pub instances: HashMap<InstanceId, ArcStr>,
834}
835
836impl NetlistCellConversion {
837    /// Creates a new [`NetlistCellConversion`].
838    pub fn new() -> Self {
839        Self::default()
840    }
841}
842
843impl<S: Schema + ?Sized> LibraryBuilder<S> {
844    /// Creates a new, empty library.
845    pub fn new() -> Self {
846        Self::default()
847    }
848
849    /// Adds the given cell to the library.
850    ///
851    /// Returns the ID of the newly added cell.
852    pub fn add_cell(&mut self, cell: Cell) -> CellId {
853        let id = self.alloc_cell_id();
854        self.name_map.insert(cell.name.clone(), id);
855        self.names.reserve_name(id, cell.name.clone());
856        self.cells.insert(id, cell);
857        id
858    }
859
860    /// Merges the given cell into the library.
861    ///
862    /// Returns the ID of the newly added cell. May rename the cell if the name is already taken.
863    pub fn merge_cell(&mut self, mut cell: Cell) -> CellId {
864        let id = self.alloc_cell_id();
865        let n_name = self.names.assign_name(id, &cell.name);
866        cell.name = n_name;
867        self.name_map.insert(cell.name.clone(), id);
868        self.cells.insert(id, cell);
869        id
870    }
871
872    #[inline]
873    pub(crate) fn alloc_cell_id(&mut self) -> CellId {
874        self.cell_id += 1;
875        self.curr_cell_id()
876    }
877
878    #[inline]
879    pub(crate) fn curr_cell_id(&self) -> CellId {
880        CellId(self.cell_id)
881    }
882
883    /// Adds the given cell to the library with the given cell ID.
884    ///
885    /// Returns the ID of the newly added cell.
886    ///
887    /// # Panics
888    ///
889    /// Panics if the ID is already in use.
890    pub(crate) fn add_cell_with_id(&mut self, id: impl Into<CellId>, cell: Cell) {
891        let id = id.into();
892        assert!(!self.cells.contains_key(&id));
893        self.cell_id = std::cmp::max(id.0, self.cell_id);
894        self.name_map.insert(cell.name.clone(), id);
895        self.names.reserve_name(id, cell.name.clone());
896        self.cells.insert(id, cell);
897    }
898
899    /// Adds the given cell to the library with the given cell ID,
900    /// overwriting an existing cell with the same ID.
901    ///
902    /// This can lead to unintended effects.
903    /// This method is intended for use only by Substrate libraries.
904    ///
905    /// # Panics
906    ///
907    /// Panics if the ID is **not** already in use.
908    #[doc(hidden)]
909    pub fn overwrite_cell_with_id(&mut self, id: impl Into<CellId>, cell: Cell) {
910        let id = id.into();
911        assert!(self.cells.contains_key(&id));
912        self.cell_id = std::cmp::max(id.0, self.cell_id);
913        self.name_map.insert(cell.name.clone(), id);
914        self.cells.insert(id, cell);
915    }
916
917    /// Adds the given primitive to the library.
918    ///
919    /// Returns the ID of the newly added primitive.
920    pub fn add_primitive(&mut self, primitive: S::Primitive) -> PrimitiveId {
921        let id = self.alloc_primitive_id();
922        self.primitives.insert(id, primitive);
923        id
924    }
925
926    #[inline]
927    pub(crate) fn alloc_primitive_id(&mut self) -> PrimitiveId {
928        self.primitive_id += 1;
929        self.curr_primitive_id()
930    }
931
932    #[inline]
933    pub(crate) fn curr_primitive_id(&self) -> PrimitiveId {
934        PrimitiveId(self.primitive_id)
935    }
936
937    /// Adds the given primitive to the library with the given primitive ID.
938    ///
939    /// Returns the ID of the newly added primitive.
940    ///
941    /// # Panics
942    ///
943    /// Panics if the ID is already in use.
944    pub(crate) fn add_primitive_with_id(
945        &mut self,
946        id: impl Into<PrimitiveId>,
947        primitive: S::Primitive,
948    ) {
949        let id = id.into();
950        assert!(!self.primitives.contains_key(&id));
951        self.primitive_id = std::cmp::max(id.0, self.primitive_id);
952        self.primitives.insert(id, primitive);
953    }
954
955    /// Adds the given primitive to the library with the given primitive ID,
956    /// overwriting an existing primitive with the same ID.
957    ///
958    /// This can lead to unintended effects.
959    /// This method is intended for use only by Substrate libraries.
960    ///
961    /// # Panics
962    ///
963    /// Panics if the ID is **not** already in use.
964    #[doc(hidden)]
965    pub fn overwrite_primitive_with_id(
966        &mut self,
967        id: impl Into<PrimitiveId>,
968        primitive: S::Primitive,
969    ) {
970        let id = id.into();
971        assert!(self.primitives.contains_key(&id));
972        self.primitive_id = std::cmp::max(id.0, self.primitive_id);
973        self.primitives.insert(id, primitive);
974    }
975
976    /// Sets the top cell to the given cell ID.
977    pub fn set_top(&mut self, cell: CellId) {
978        self.top = Some(cell);
979    }
980
981    /// The ID of the top-level cell, if there is one.
982    #[inline]
983    pub fn top_cell(&self) -> Option<CellId> {
984        self.top
985    }
986
987    /// Returns `true` if the given cell is the top cell.
988    pub fn is_top(&self, cell: CellId) -> bool {
989        self.top_cell().map(|c| c == cell).unwrap_or_default()
990    }
991
992    /// Gets the cell with the given ID.
993    ///
994    /// # Panics
995    ///
996    /// Panics if no cell has the given ID.
997    /// For a non-panicking alternative, see [`try_cell`](LibraryBuilder::try_cell).
998    pub fn cell(&self, id: CellId) -> &Cell {
999        self.cells.get(&id).unwrap()
1000    }
1001
1002    /// Gets the cell with the given ID.
1003    #[inline]
1004    pub fn try_cell(&self, id: CellId) -> Option<&Cell> {
1005        self.cells.get(&id)
1006    }
1007
1008    /// Gets the cell with the given name.
1009    ///
1010    /// # Panics
1011    ///
1012    /// Panics if no cell has the given name.
1013    pub fn cell_named(&self, name: &str) -> &Cell {
1014        self.cell(*self.name_map.get(name).unwrap())
1015    }
1016
1017    /// Gets the cell with the given name.
1018    pub fn try_cell_named(&self, name: &str) -> Option<&Cell> {
1019        self.try_cell(*self.name_map.get(name)?)
1020    }
1021
1022    /// Gets the cell ID corresponding to the given name.
1023    ///
1024    /// # Panics
1025    ///
1026    /// Panics if no cell has the given name.
1027    /// For a non-panicking alternative, see [`try_cell_id_named`](LibraryBuilder::try_cell_id_named).
1028    pub fn cell_id_named(&self, name: &str) -> CellId {
1029        match self.name_map.get(name) {
1030            Some(&cell) => cell,
1031            None => {
1032                tracing::error!("no cell named `{}`", name);
1033                panic!("no cell named `{}`", name);
1034            }
1035        }
1036    }
1037
1038    /// Gets the cell ID corresponding to the given name.
1039    pub fn try_cell_id_named(&self, name: &str) -> Option<CellId> {
1040        self.name_map.get(name).copied()
1041    }
1042
1043    /// Iterates over the `(id, cell)` pairs in this library.
1044    pub fn cells(&self) -> impl Iterator<Item = (CellId, &Cell)> {
1045        self.cells.iter().map(|(id, cell)| (*id, cell))
1046    }
1047
1048    /// Keeps only the cells in `roots` and their dependencies.
1049    pub fn retain_cells(&mut self, roots: impl IntoIterator<Item = CellId>) {
1050        let (cells, primitives) = self.cells_and_primitives_used_by(roots);
1051        // Remove names from name map
1052        self.name_map.retain(|_, cell| cells.contains(cell));
1053        for (id, _) in self.cells.iter() {
1054            if !cells.contains(id) {
1055                // Remove names from `self.names`.
1056                self.names.unassign(id);
1057            }
1058        }
1059        // Remove cells from HashMap.
1060        self.cells.retain(|id, _| cells.contains(id));
1061
1062        // Clear top cell if top cell was deleted.
1063        if let Some(top) = self.top_cell()
1064            && !cells.contains(&top)
1065        {
1066            self.top = None;
1067        }
1068
1069        // Remove primitives.
1070        self.primitives.retain(|id, _| primitives.contains(id));
1071    }
1072
1073    /// The list of cell IDs and primitive IDs instantiated by the given root cells.
1074    ///
1075    /// The cell list returned will include the root cell IDs.
1076    pub(crate) fn cells_and_primitives_used_by(
1077        &self,
1078        roots: impl IntoIterator<Item = CellId>,
1079    ) -> (HashSet<CellId>, HashSet<PrimitiveId>) {
1080        let mut stack = VecDeque::new();
1081        let mut visited = HashSet::new();
1082        let mut primitives = HashSet::new();
1083        for root in roots {
1084            stack.push_back(root);
1085        }
1086
1087        while let Some(id) = stack.pop_front() {
1088            if visited.contains(&id) {
1089                continue;
1090            }
1091            visited.insert(id);
1092            let cell = self.cell(id);
1093            for (_, inst) in cell.instances() {
1094                match inst.child {
1095                    ChildId::Cell(c) => {
1096                        stack.push_back(c);
1097                    }
1098                    ChildId::Primitive(p) => {
1099                        primitives.insert(p);
1100                    }
1101                }
1102            }
1103        }
1104
1105        (visited, primitives)
1106    }
1107
1108    /// The list of cell IDs instantiated by the given root cells.
1109    ///
1110    /// The list returned will include the root cell IDs.
1111    pub(crate) fn cells_used_by(&self, roots: impl IntoIterator<Item = CellId>) -> HashSet<CellId> {
1112        let mut stack = VecDeque::new();
1113        let mut visited = HashSet::new();
1114        for root in roots {
1115            stack.push_back(root);
1116        }
1117
1118        while let Some(id) = stack.pop_front() {
1119            if visited.contains(&id) {
1120                continue;
1121            }
1122            visited.insert(id);
1123            let cell = self.cell(id);
1124            for (_, inst) in cell.instances() {
1125                if let ChildId::Cell(c) = inst.child {
1126                    stack.push_back(c);
1127                }
1128            }
1129        }
1130
1131        visited
1132    }
1133
1134    /// Gets the primitive with the given ID.
1135    ///
1136    /// # Panics
1137    ///
1138    /// Panics if no primitive has the given ID.
1139    /// For a non-panicking alternative, see [`try_primitive`](LibraryBuilder::try_primitive).
1140    pub fn primitive(&self, id: PrimitiveId) -> &S::Primitive {
1141        self.primitives.get(&id).unwrap()
1142    }
1143
1144    /// Gets the primitive with the given ID.
1145    #[inline]
1146    pub fn try_primitive(&self, id: PrimitiveId) -> Option<&S::Primitive> {
1147        self.primitives.get(&id)
1148    }
1149
1150    /// Iterates over the `(id, primitive)` pairs in this library.
1151    pub fn primitives(&self) -> impl Iterator<Item = (PrimitiveId, &S::Primitive)> {
1152        self.primitives
1153            .iter()
1154            .map(|(id, primitive)| (*id, primitive))
1155    }
1156
1157    fn convert_instance_path_cell(&self, top: &InstancePathCell) -> Option<(CellId, &Cell)> {
1158        Some(match top {
1159            InstancePathCell::Id(id) => (*id, self.cell(*id)),
1160            InstancePathCell::Name(name) => (
1161                *self.name_map.get(name)?,
1162                self.try_cell_named(name.as_ref())?,
1163            ),
1164        })
1165    }
1166
1167    /// Annotates an [`InstancePath`] with additional metadata.
1168    ///
1169    /// Finds cell IDs associated with instances in the path if they are in the SCIR
1170    /// library, and converts the top of the path to a cell ID if possible.
1171    pub fn annotate_instance_path(&self, path: InstancePath) -> AnnotatedInstancePath {
1172        let mut annotated_elems = Vec::new();
1173
1174        let (top, mut cell) = if let Some((id, cell)) = self.convert_instance_path_cell(&path.top) {
1175            (Some(id), Some(cell))
1176        } else {
1177            (None, None)
1178        };
1179
1180        for instance in path.elems {
1181            if let Some(cell_inner) = cell {
1182                let child = match &instance {
1183                    InstancePathElement::Id(id) => cell_inner.try_instance(*id),
1184                    InstancePathElement::Name(name) => cell_inner.try_instance_named(name),
1185                }
1186                .map(|inst| inst.child);
1187
1188                annotated_elems.push(AnnotatedInstancePathElement {
1189                    elem: instance,
1190                    child,
1191                });
1192
1193                cell = match child {
1194                    Some(ChildId::Cell(c)) => self.try_cell(c),
1195                    _ => None,
1196                };
1197            } else {
1198                annotated_elems.push(AnnotatedInstancePathElement {
1199                    elem: instance.clone(),
1200                    child: None,
1201                });
1202            }
1203        }
1204
1205        AnnotatedInstancePath {
1206            top: top.map(|top| top.into()).unwrap_or(path.top),
1207            instances: annotated_elems,
1208        }
1209    }
1210
1211    /// Annotates an instance path with additional metadata, such as whether
1212    /// each instance in the path corresponds to an actual SCIR instance.
1213    pub fn convert_annotated_instance_path(
1214        &self,
1215        conv: Option<&NetlistLibConversion>,
1216        path: AnnotatedInstancePath,
1217    ) -> NamedPath {
1218        let mut named_path = NamedPath::new();
1219
1220        let (top_id, top) = if let Some((top_id, top)) = self.convert_instance_path_cell(&path.top)
1221        {
1222            (Some(top_id), Some(top))
1223        } else {
1224            (None, None)
1225        };
1226
1227        for (i, instance) in path.instances.iter().enumerate() {
1228            match &instance.elem {
1229                InstancePathElement::Id(id) => {
1230                    let inst = if i == 0 {
1231                        top
1232                    } else {
1233                        self.try_cell(path.instances[i - 1].child.unwrap().unwrap_cell())
1234                    }
1235                    .unwrap()
1236                    .instance(*id);
1237
1238                    let name = conv
1239                        .and_then(|conv| {
1240                            Some(
1241                                conv.cells
1242                                    .get(&if i == 0 {
1243                                        top_id?
1244                                    } else {
1245                                        path.instances[i - 1].child.unwrap().unwrap_cell()
1246                                    })?
1247                                    .instances
1248                                    .get(id)?
1249                                    .clone(),
1250                            )
1251                        })
1252                        .unwrap_or(inst.name().clone());
1253                    named_path.push(name);
1254                }
1255                InstancePathElement::Name(name) => {
1256                    named_path.push(name.clone());
1257                }
1258            }
1259        }
1260
1261        named_path
1262    }
1263
1264    /// Converts an [`InstancePath`] to a [`NamedPath`].
1265    ///
1266    /// # Panics
1267    ///
1268    /// Panics if the path contains instance or cell IDs that do not exist.
1269    pub fn convert_instance_path(&self, path: InstancePath) -> NamedPath {
1270        let annotated_path = self.annotate_instance_path(path);
1271
1272        self.convert_annotated_instance_path(None, annotated_path)
1273    }
1274
1275    /// Converts an [`InstancePath`] to a [`NamedPath`], using the provided `conv`
1276    /// to modify instance names that were converted during netlisting.
1277    ///
1278    /// # Panics
1279    ///
1280    /// Panics if the path contains instance or cell IDs that do not exist.
1281    pub fn convert_instance_path_with_conv(
1282        &self,
1283        conv: &NetlistLibConversion,
1284        path: InstancePath,
1285    ) -> NamedPath {
1286        let annotated_path = self.annotate_instance_path(path);
1287
1288        self.convert_annotated_instance_path(Some(conv), annotated_path)
1289    }
1290
1291    /// Converts a [`SliceOnePath`] to a [`NamedPath`], using the provided `conv`
1292    /// to modify instance names that were converted during netlisting.
1293    ///
1294    /// # Panics
1295    ///
1296    /// Panics if the path contains instance or cell IDs that do not exist.
1297    fn convert_slice_one_path_inner(
1298        &self,
1299        conv: Option<&NetlistLibConversion>,
1300        path: SliceOnePath,
1301        index_fmt: impl FnOnce(&ArcStr, Option<usize>) -> ArcStr,
1302    ) -> NamedPath {
1303        let SignalPath { instances, tail } = path.0;
1304        let annotated_path = self.annotate_instance_path(instances);
1305
1306        let bot = self.cell(annotated_path.bot().unwrap());
1307
1308        let (name, index) = match &tail {
1309            SignalPathTail::Id(id) => (&bot.signal(id.signal()).name, id.index()),
1310            SignalPathTail::Name(name) => (name.signal(), name.index()),
1311        };
1312
1313        let mut name_path = self.convert_annotated_instance_path(conv, annotated_path);
1314        name_path.push(index_fmt(name, index));
1315
1316        name_path
1317    }
1318
1319    /// Converts a [`SliceOnePath`] to a [`NamedPath`].
1320    /// to modify instance names that were converted during netlisting.
1321    ///
1322    /// # Panics
1323    ///
1324    /// Panics if the path contains instance or cell IDs that do not exist.
1325    pub fn convert_slice_one_path(
1326        &self,
1327        path: SliceOnePath,
1328        index_fmt: impl FnOnce(&ArcStr, Option<usize>) -> ArcStr,
1329    ) -> NamedPath {
1330        self.convert_slice_one_path_inner(None, path, index_fmt)
1331    }
1332
1333    /// Converts a [`SliceOnePath`] to a [`NamedPath`], using the provided `conv`
1334    /// to modify instance names that were converted during netlisting.
1335    ///
1336    /// # Panics
1337    ///
1338    /// Panics if the path contains instance or cell IDs that do not exist.
1339    pub fn convert_slice_one_path_with_conv(
1340        &self,
1341        conv: &NetlistLibConversion,
1342        path: SliceOnePath,
1343        index_fmt: impl FnOnce(&ArcStr, Option<usize>) -> ArcStr,
1344    ) -> NamedPath {
1345        self.convert_slice_one_path_inner(Some(conv), path, index_fmt)
1346    }
1347
1348    /// Returns a simplified path to the provided node, bubbling up through IOs.
1349    ///
1350    /// # Panics
1351    ///
1352    /// Panics if the provided path does not exist within the SCIR library.
1353    pub fn simplify_path(&self, path: SliceOnePath) -> SliceOnePath {
1354        if path.instances().is_empty() {
1355            return path;
1356        }
1357        let SignalPath {
1358            instances,
1359            mut tail,
1360        } = path.0;
1361
1362        let mut annotated_instances = self.annotate_instance_path(instances);
1363        let top = self
1364            .convert_instance_path_cell(&annotated_instances.top)
1365            .map(|(_, cell)| cell);
1366
1367        for i in (0..annotated_instances.instances.len()).rev() {
1368            let parent = if i == 0 {
1369                top.unwrap()
1370            } else {
1371                self.cell(
1372                    annotated_instances.instances[i - 1]
1373                        .child
1374                        .unwrap()
1375                        .unwrap_cell(),
1376                )
1377            };
1378            match annotated_instances.instances[i].child.unwrap() {
1379                ChildId::Cell(id) => {
1380                    let cell = self.cell(id);
1381                    let info = match &tail {
1382                        SignalPathTail::Id(id) => cell.signal(id.signal()),
1383                        SignalPathTail::Name(name) => cell.signal_named(name.signal()),
1384                    };
1385                    if info.port.is_none() {
1386                        annotated_instances.instances.truncate(i + 1);
1387                        return SliceOnePath(SignalPath {
1388                            instances: annotated_instances.into(),
1389                            tail,
1390                        });
1391                    } else {
1392                        let inst = parent
1393                            .instance_from_path_element(&annotated_instances.instances[i].elem);
1394                        let idx = tail.index().unwrap_or_default();
1395                        tail = SignalPathTail::Id(inst.connection(info.name.as_ref()).index(idx));
1396                    }
1397                }
1398                ChildId::Primitive(_) => {
1399                    let inst =
1400                        parent.instance_from_path_element(&annotated_instances.instances[i].elem);
1401                    tail = SignalPathTail::Id(match &tail {
1402                        SignalPathTail::Id(_) => {
1403                            panic!("only paths to named primitive ports can be simplified")
1404                        }
1405                        SignalPathTail::Name(name) => inst
1406                            .connection(name.signal())
1407                            .index(name.index().unwrap_or_default()),
1408                    });
1409                }
1410            }
1411        }
1412
1413        annotated_instances.instances = Vec::new();
1414        SliceOnePath(SignalPath {
1415            instances: annotated_instances.into(),
1416            tail,
1417        })
1418    }
1419
1420    /// Validate and construct a SCIR [`Library`].
1421    ///
1422    /// If errors are encountered during validation,
1423    /// returns an `Err(_)` containing the set of issues found.
1424    /// If no errors are encountered, returns an `Ok(_)` containing
1425    /// the SCIR library. Warnings and infos are discarded.
1426    ///
1427    /// If you want to inspect warnings/infos, consider using
1428    /// [`try_build`](LibraryBuilder::try_build) instead.
1429    #[inline]
1430    pub fn build(self) -> Result<Library<S>, Issues> {
1431        self.try_build().map(|ok| ok.0)
1432    }
1433
1434    /// Validate and construct a SCIR [`Library`].
1435    ///
1436    /// If errors are encountered during validation,
1437    /// returns an `Err(_)` containing the set of issues found.
1438    /// If no errors are encountered, returns `Ok((library, issues))`.
1439    /// The issues returned will not have any errors, but may have
1440    /// warnings or infos.
1441    ///
1442    /// If you do not want to inspect warnings/infos, consider using
1443    /// [`build`](LibraryBuilder::build) instead.
1444    ///
1445    pub fn try_build(self) -> Result<(Library<S>, Issues), Issues> {
1446        let correctness = self.validate();
1447        let drivers = self.validate_drivers();
1448        let issues = Issues {
1449            correctness,
1450            drivers,
1451        };
1452        if issues.has_error() {
1453            Err(issues)
1454        } else {
1455            Ok((Library(self), issues))
1456        }
1457    }
1458
1459    fn convert_inner<C: Schema + ?Sized, E>(
1460        self,
1461        convert_primitive: fn(<S as Schema>::Primitive) -> Result<<C as Schema>::Primitive, E>,
1462        convert_instance: fn(&mut Instance, &<S as Schema>::Primitive) -> Result<(), E>,
1463    ) -> Result<LibraryBuilder<C>, E> {
1464        let LibraryBuilder {
1465            cell_id,
1466            primitive_id,
1467            mut cells,
1468            name_map,
1469            primitives,
1470            top,
1471            names,
1472        } = self;
1473
1474        for (_, cell) in cells.iter_mut() {
1475            for (_, instance) in cell.instances.iter_mut() {
1476                if let ChildId::Primitive(p) = instance.child
1477                    && let Some(primitive) = primitives.get(&p)
1478                {
1479                    convert_instance(instance, primitive)?;
1480                }
1481            }
1482        }
1483
1484        Ok(LibraryBuilder {
1485            cell_id,
1486            primitive_id,
1487            cells,
1488            name_map,
1489            names,
1490            primitives: primitives
1491                .into_iter()
1492                .map(|(k, v)| Ok((k, convert_primitive(v)?)))
1493                .collect::<Result<_, _>>()?,
1494            top,
1495        })
1496    }
1497
1498    /// Converts a [`LibraryBuilder<S>`] to a [`LibraryBuilder<NoSchema>`], throwing an error if there
1499    /// are any primitives.
1500    pub fn drop_schema(self) -> Result<LibraryBuilder<NoSchema>, NoSchemaError> {
1501        self.convert_inner(|_| Err(NoSchemaError), |_, _| Err(NoSchemaError))
1502    }
1503
1504    /// Converts a [`LibraryBuilder<S>`] into a [`LibraryBuilder<C>`].
1505    ///
1506    /// Instances associated with non-existent primitives will remain unchanged.
1507    pub fn convert_schema<C>(self) -> Result<LibraryBuilder<C>, C::Error>
1508    where
1509        C: FromSchema<S> + ?Sized,
1510    {
1511        self.convert_inner(C::convert_primitive, C::convert_instance)
1512    }
1513}
1514
1515impl<S: Schema<Primitive = impl Clone> + ?Sized> LibraryBuilder<S> {
1516    /// Creates a new SCIR library builder containing only the named cell and its children
1517    /// from an existing library builder.
1518    pub fn from_cell_named(lib: &Self, cell: &str) -> Self {
1519        let mut new_lib = LibraryBuilder::new();
1520        let mut cells = vec![(lib.cell_id_named(cell), lib.cell_named(cell))];
1521        while let Some((id, cell)) = cells.pop() {
1522            for (_, inst) in cell.instances() {
1523                match inst.child {
1524                    ChildId::Primitive(id) => {
1525                        let prim = lib.primitive(id);
1526                        new_lib.add_primitive_with_id(id, prim.clone());
1527                    }
1528                    ChildId::Cell(cell) => {
1529                        cells.push((cell, lib.cell(cell)));
1530                    }
1531                }
1532            }
1533            new_lib.add_cell_with_id(id, cell.clone());
1534        }
1535        new_lib
1536    }
1537}
1538
1539impl Cell {
1540    /// Creates a new cell with the given name.
1541    pub fn new(name: impl Into<ArcStr>) -> Self {
1542        Self {
1543            signal_id: 0,
1544            port_idx: 0,
1545            name: name.into(),
1546            ports: IndexMap::new(),
1547            signals: HashMap::new(),
1548            signal_name_map: HashMap::new(),
1549            instance_id: 0,
1550            instances: IndexMap::new(),
1551            instance_name_map: HashMap::new(),
1552        }
1553    }
1554
1555    fn add_signal(&mut self, name: ArcStr, width: Option<usize>) -> SignalId {
1556        self.signal_id += 1;
1557        let id = SignalId(self.signal_id);
1558        self.signal_name_map.insert(name.clone(), id);
1559        self.signals.insert(
1560            id,
1561            SignalInfo {
1562                id,
1563                port: None,
1564                name,
1565                width,
1566            },
1567        );
1568        id
1569    }
1570
1571    /// Creates a new 1-bit signal in this cell.
1572    pub fn add_node(&mut self, name: impl Into<ArcStr>) -> SliceOne {
1573        let id = self.add_signal(name.into(), None);
1574        SliceOne::new(id, None)
1575    }
1576
1577    /// Creates a new 1-dimensional bus in this cell.
1578    pub fn add_bus(&mut self, name: impl Into<ArcStr>, width: usize) -> Slice {
1579        assert!(width > 0);
1580        let id = self.add_signal(name.into(), Some(width));
1581        Slice::new(id, Some(SliceRange::with_width(width)))
1582    }
1583
1584    /// Exposes the given signal as a port.
1585    ///
1586    /// If the signal is a bus, the entire bus is exposed.
1587    /// It is not possible to expose only a portion of a bus.
1588    /// Create two separate buses instead.
1589    ///
1590    /// # Panics
1591    ///
1592    /// Panics if the provided signal does not exist.
1593    pub fn expose_port(&mut self, signal: impl Into<SignalId>, direction: Direction) {
1594        let signal = signal.into();
1595        let info = self.signals.get_mut(&signal).unwrap();
1596
1597        // If this signal was already marked as a port, no need to do anything.
1598        if info.port.is_none() {
1599            info.port = Some(self.port_idx);
1600            self.port_idx += info.width.unwrap_or(1);
1601            self.ports
1602                .insert(info.name.clone(), Port { signal, direction });
1603        }
1604    }
1605
1606    /// The name of the cell.
1607    #[inline]
1608    pub fn name(&self) -> &ArcStr {
1609        &self.name
1610    }
1611
1612    /// Iterate over the ports of this cell.
1613    #[inline]
1614    pub fn ports(&self) -> impl Iterator<Item = &Port> {
1615        self.ports.iter().map(|(_, port)| port)
1616    }
1617
1618    /// Get a port of this cell by name.
1619    ///
1620    /// # Panics
1621    ///
1622    /// Panics if the provided port does not exist.
1623    #[inline]
1624    pub fn port(&self, name: &str) -> &Port {
1625        self.ports.get(name).unwrap()
1626    }
1627
1628    /// Iterate over the signals of this cell.
1629    #[inline]
1630    pub fn signals(&self) -> impl Iterator<Item = (SignalId, &SignalInfo)> {
1631        self.signals.iter().map(|x| (*x.0, x.1))
1632    }
1633
1634    /// Get the signal associated with the given ID.
1635    ///
1636    /// # Panics
1637    ///
1638    /// Panics if no signal with the given ID exists.
1639    #[inline]
1640    pub fn signal(&self, id: SignalId) -> &SignalInfo {
1641        self.signals.get(&id).unwrap()
1642    }
1643
1644    /// Get the signal associated with the given ID.
1645    #[inline]
1646    pub fn try_signal(&self, id: SignalId) -> Option<&SignalInfo> {
1647        self.signals.get(&id)
1648    }
1649
1650    /// Get the signal associated with the given name.
1651    ///
1652    /// # Panics
1653    ///
1654    /// Panics if no signal with the given name exists.
1655    #[inline]
1656    pub fn signal_named(&self, name: &str) -> &SignalInfo {
1657        self.signal(*self.signal_name_map.get(name).unwrap())
1658    }
1659
1660    /// Get the signal associated with the given ID.
1661    #[inline]
1662    pub fn try_signal_named(&self, name: &str) -> Option<&SignalInfo> {
1663        self.try_signal(*self.signal_name_map.get(name)?)
1664    }
1665
1666    /// Get the instance associated with the given ID.
1667    ///
1668    /// # Panics
1669    ///
1670    /// Panics if no instance with the given ID exists.
1671    #[inline]
1672    pub fn instance(&self, id: InstanceId) -> &Instance {
1673        self.instances.get(&id).unwrap()
1674    }
1675
1676    /// Get the instance associated with the given ID.
1677    #[inline]
1678    pub fn try_instance(&self, id: InstanceId) -> Option<&Instance> {
1679        self.instances.get(&id)
1680    }
1681
1682    /// Gets the instance with the given name.
1683    ///
1684    /// # Panics
1685    ///
1686    /// Panics if no instance has the given name.
1687    pub fn instance_named(&self, name: &str) -> &Instance {
1688        self.instance(*self.instance_name_map.get(name).unwrap())
1689    }
1690
1691    /// Gets the instance with the given name.
1692    pub fn try_instance_named(&self, name: &str) -> Option<&Instance> {
1693        self.try_instance(*self.instance_name_map.get(name)?)
1694    }
1695
1696    /// Gets the instance associated with the given path element.
1697    pub fn instance_from_path_element(&self, elem: &InstancePathElement) -> &Instance {
1698        match elem {
1699            InstancePathElement::Id(id) => self.instance(*id),
1700            InstancePathElement::Name(name) => self.instance_named(name),
1701        }
1702    }
1703
1704    /// Add the given instance to the cell.
1705    #[inline]
1706    pub fn add_instance(&mut self, instance: Instance) -> InstanceId {
1707        self.instance_id += 1;
1708        let id = InstanceId(self.instance_id);
1709        self.instance_name_map.insert(instance.name.clone(), id);
1710        self.instances.insert(id, instance);
1711        id
1712    }
1713
1714    /// Iterate over the instances of this cell.
1715    #[inline]
1716    pub fn instances(&self) -> impl Iterator<Item = (InstanceId, &Instance)> {
1717        self.instances.iter().map(|x| (*x.0, x.1))
1718    }
1719}
1720
1721impl Instance {
1722    /// Create an instance of the given cell with the given name.
1723    pub fn new(name: impl Into<ArcStr>, child: impl Into<ChildId>) -> Self {
1724        Self {
1725            child: child.into(),
1726            name: name.into(),
1727            connections: HashMap::new(),
1728        }
1729    }
1730
1731    /// Connect the given port of the child cell to the given node in the parent cell.
1732    #[inline]
1733    pub fn connect(&mut self, name: impl Into<ArcStr>, conn: impl Into<Concat>) {
1734        self.connections.insert(name.into(), conn.into());
1735    }
1736
1737    /// The ID of the child cell.
1738    ///
1739    /// This instance represents an instantiation of the child cell in a parent cell.
1740    #[inline]
1741    pub fn child(&self) -> ChildId {
1742        self.child
1743    }
1744
1745    /// The name of this instance.
1746    ///
1747    /// This is not necessarily the name of the child cell.
1748    #[inline]
1749    pub fn name(&self) -> &ArcStr {
1750        &self.name
1751    }
1752
1753    /// Returns a reference to this instance's connection map.
1754    #[inline]
1755    pub fn connections(&self) -> &HashMap<ArcStr, Concat> {
1756        &self.connections
1757    }
1758
1759    /// Returns a mutable reference to this instance's connection map.
1760    #[inline]
1761    pub fn connections_mut(&mut self) -> &mut HashMap<ArcStr, Concat> {
1762        &mut self.connections
1763    }
1764
1765    /// The connection to the given port.
1766    ///
1767    /// # Panics
1768    ///
1769    /// Panics if there is no connection for the given port.
1770    #[inline]
1771    pub fn connection<'a>(&'a self, port: &str) -> &'a Concat {
1772        &self.connections[port]
1773    }
1774
1775    /// Maps the connections to this instance to new port names.
1776    ///
1777    /// Exhibits undefined behavior if two connections map to the same port name.
1778    pub fn map_connections(&mut self, map_fn: impl Fn(ArcStr) -> ArcStr) {
1779        self.connections = self
1780            .connections
1781            .drain()
1782            .map(|(k, v)| (map_fn(k), v))
1783            .collect();
1784    }
1785}
1786
1787impl Port {
1788    /// The ID of the signal this port exposes.
1789    #[inline]
1790    pub fn signal(&self) -> SignalId {
1791        self.signal
1792    }
1793
1794    /// The direction of this port.
1795    #[inline]
1796    pub fn direction(&self) -> Direction {
1797        self.direction
1798    }
1799}