substrate/schematic/
mod.rs

1//! Substrate's schematic generator framework.
2
3pub mod conv;
4pub mod netlist;
5pub mod pex;
6pub mod schema;
7#[cfg(test)]
8mod tests;
9
10use cache::CacheHandle;
11use cache::mem::TypeCache;
12pub use codegen::NestedData;
13use pathtree::PathTree;
14use serde::{Deserialize, Serialize};
15use std::any::Any;
16use std::collections::HashMap;
17use std::fmt::Formatter;
18use std::hash::{Hash, Hasher};
19use std::marker::PhantomData;
20use std::ops::Deref;
21use std::sync::Arc;
22
23use arcstr::ArcStr;
24use once_cell::sync::OnceCell;
25
26use crate::block::Block;
27use crate::context::Context;
28use crate::diagnostics::SourceInfo;
29use crate::error::{Error, Result};
30use crate::schematic::conv::ConvError;
31use crate::schematic::schema::{FromSchema, Schema};
32use crate::types::schematic::{
33    IoNodeBundle, IoTerminalBundle, Node, NodeBundle, NodeContext, NodePriority, NodeUf, Port,
34    SchematicBundleKind,
35};
36use crate::types::{Flatten, HasBundleKind, HasNameTree, IoKind, NameBuf};
37
38/// A block that has a schematic.
39pub trait Schematic: Block<Io: HasBundleKind<BundleKind: SchematicBundleKind>> {
40    /// The schema this schematic is associated with.
41    type Schema: Schema;
42    /// Extra schematic data to be stored with the block's generated cell.
43    ///
44    /// When the block is instantiated, all contained data will be nested
45    /// within that instance.
46    type NestedData: NestedData;
47
48    /// Generates the block's schematic.
49    fn schematic(
50        &self,
51        io: &IoNodeBundle<Self>,
52        cell: &mut CellBuilder<<Self as Schematic>::Schema>,
53    ) -> Result<Self::NestedData>;
54}
55
56impl<T: Schematic> Schematic for Arc<T> {
57    type Schema = T::Schema;
58    type NestedData = T::NestedData;
59
60    fn schematic(
61        &self,
62        io: &IoNodeBundle<Self>,
63        cell: &mut CellBuilder<<Self as Schematic>::Schema>,
64    ) -> Result<Self::NestedData> {
65        T::schematic(self.as_ref(), io, cell)
66    }
67}
68
69/// Data that can be stored in [`Schematic::NestedData`].
70pub trait NestedData: HasNestedView + Send + Sync {}
71impl<T: HasNestedView + Send + Sync> NestedData for T {}
72
73/// An object that can be nested within a parent context.
74pub trait HasContextView<T> {
75    /// A view of object.
76    type ContextView: Send + Sync;
77    /// Creates a context view of the object given a parent context.
78    fn context_view(&self, parent: &T) -> ContextView<Self, T>;
79}
80
81/// The associated context view of an object.
82pub type ContextView<D, T> = <D as HasContextView<T>>::ContextView;
83
84impl<T> HasContextView<T> for () {
85    type ContextView = ();
86
87    fn context_view(&self, _parent: &T) -> ContextView<Self, T> {}
88}
89
90// TODO: Potentially use lazy evaluation instead of cloning.
91impl<V, T: HasContextView<V>> HasContextView<V> for Vec<T> {
92    type ContextView = Vec<ContextView<T, V>>;
93    fn context_view(&self, parent: &V) -> ContextView<Self, V> {
94        self.iter().map(|elem| elem.context_view(parent)).collect()
95    }
96}
97
98impl<V, T: HasContextView<V>> HasContextView<V> for Option<T> {
99    type ContextView = Option<ContextView<T, V>>;
100    fn context_view(&self, parent: &V) -> ContextView<Self, V> {
101        self.as_ref().map(|inner| inner.context_view(parent))
102    }
103}
104
105/// An object that can be nested within a parent transform.
106pub trait HasNestedView {
107    /// A view of the nested object.
108    ///
109    /// Nesting a nested view should return the same type.
110    type NestedView: HasNestedView<NestedView = Self::NestedView> + Send + Sync;
111    /// Creates a nested view of the object given a parent node.
112    fn nested_view(&self, parent: &InstancePath) -> NestedView<Self>;
113}
114
115/// The associated nested view of an object.
116pub type NestedView<D> = <D as HasNestedView>::NestedView;
117
118impl HasNestedView for () {
119    type NestedView = ();
120    fn nested_view(&self, _parent: &InstancePath) -> NestedView<Self> {}
121}
122
123// TODO: Potentially use lazy evaluation instead of cloning.
124impl<T: HasNestedView> HasNestedView for Vec<T> {
125    type NestedView = Vec<NestedView<T>>;
126    fn nested_view(&self, parent: &InstancePath) -> NestedView<Self> {
127        self.iter().map(|elem| elem.nested_view(parent)).collect()
128    }
129}
130
131impl<T: HasNestedView> HasNestedView for Option<T> {
132    type NestedView = Option<NestedView<T>>;
133    fn nested_view(&self, parent: &InstancePath) -> NestedView<Self> {
134        self.as_ref().map(|inner| inner.nested_view(parent))
135    }
136}
137
138/// Block that implements [`Schematic`] in schema `S` for block `B`.
139#[derive_where::derive_where(Debug, Hash, PartialEq, Eq; B)]
140pub struct ConvertSchema<B, S>(Arc<B>, PhantomData<S>);
141
142impl<B, S> ConvertSchema<B, S> {
143    /// Creates a new [`ConvertSchema`].
144    pub fn new(block: B) -> Self {
145        Self(Arc::new(block), PhantomData)
146    }
147}
148
149impl<B, S> Clone for ConvertSchema<B, S> {
150    fn clone(&self) -> Self {
151        Self(self.0.clone(), PhantomData)
152    }
153}
154
155impl<B: Block, S: Schema> Block for ConvertSchema<B, S> {
156    type Io = <B as Block>::Io;
157
158    fn name(&self) -> ArcStr {
159        self.0.name()
160    }
161
162    fn io(&self) -> Self::Io {
163        self.0.io()
164    }
165}
166
167impl<B: Schematic, S: FromSchema<B::Schema>> Schematic for ConvertSchema<B, S>
168where
169    NestedView<B::NestedData>: HasNestedView,
170{
171    type Schema = S;
172    type NestedData = NestedView<B::NestedData>;
173    fn schematic(
174        &self,
175        io: &IoNodeBundle<Self>,
176        cell: &mut CellBuilder<<Self as Schematic>::Schema>,
177    ) -> Result<Self::NestedData> {
178        let mut s = cell.sub_builder::<B::Schema>();
179        let b = s.instantiate_blocking(self.0.clone())?;
180        cell.connect(io, b.io());
181        cell.flatten();
182        Ok(b.data())
183    }
184}
185
186/// A builder for creating a schematic cell.
187pub struct CellBuilder<S: Schema + ?Sized> {
188    /// The current global context.
189    pub(crate) ctx: Context,
190    pub(crate) id: CellId,
191    pub(crate) cell_name: ArcStr,
192    pub(crate) flatten: bool,
193    pub(crate) node_ctx: NodeContext,
194    pub(crate) node_names: HashMap<Node, NameBuf>,
195    /// Whether a fatal error occured while building the cell.
196    pub(crate) fatal_error: bool,
197    /// Outward-facing ports of this cell.
198    ///
199    /// Directions are as viewed by a parent cell instantiating this cell; these
200    /// are the wrong directions to use when looking at connections to this
201    /// cell's IO from *within* the cell.
202    pub(crate) ports: Vec<Port>,
203    pub(crate) contents: RawCellContentsBuilder<S>,
204}
205
206impl<S: Schema + ?Sized> CellBuilder<S> {
207    pub(crate) fn finish(self) -> RawCell<S> {
208        let mut roots = HashMap::with_capacity(self.node_names.len());
209        let mut uf = self.node_ctx.into_uf();
210        for &node in self.node_names.keys() {
211            let root = uf.probe_value(node).unwrap().source;
212            roots.insert(node, root);
213        }
214
215        RawCell {
216            id: self.id,
217            name: self.cell_name,
218            node_names: self.node_names,
219            ports: self.ports,
220            flatten: self.flatten,
221            uf,
222            roots,
223            contents: self.contents.build(),
224        }
225    }
226
227    /// Marks this cell to be flattened.
228    pub fn flatten(&mut self) {
229        self.flatten = true;
230    }
231
232    /// Create a new signal with the given name and hardware type.
233    #[track_caller]
234    pub fn signal<K: HasBundleKind<BundleKind: SchematicBundleKind>>(
235        &mut self,
236        name: impl Into<ArcStr>,
237        kind: K,
238    ) -> NodeBundle<K> {
239        let (nodes, data) = self.node_ctx.instantiate_undirected(
240            &kind,
241            NodePriority::Named,
242            SourceInfo::from_caller(),
243        );
244
245        let kind = kind.kind();
246        let names = kind.flat_names(Some(name.into().into()));
247        assert_eq!(nodes.len(), names.len());
248
249        self.node_names.extend(nodes.iter().copied().zip(names));
250
251        data
252    }
253
254    /// Connect all signals in the given data instances.
255    #[track_caller]
256    pub fn connect<D1, D2>(&mut self, s1: D1, s2: D2)
257    where
258        D1: Flatten<Node> + HasBundleKind,
259        D2: Flatten<Node> + HasBundleKind<BundleKind = <D1 as HasBundleKind>::BundleKind>,
260    {
261        let sinfo = SourceInfo::from_caller();
262        let s1_kind = s1.kind();
263        let s2_kind = s2.kind();
264        if s1_kind != s2_kind {
265            tracing::error!(
266                ?sinfo,
267                ?s1_kind,
268                ?s2_kind,
269                "tried to connect bundles of different kinds",
270            );
271            self.fatal_error = true;
272        } else {
273            let s1f: Vec<Node> = s1.flatten_vec();
274            let s2f: Vec<Node> = s2.flatten_vec();
275            s1f.into_iter().zip(s2f).for_each(|(a, b)| {
276                self.node_ctx.connect(a, b, sinfo.clone());
277            });
278        }
279    }
280
281    /// Connect all signals in the given data instances.
282    pub fn connect_multiple<D>(&mut self, s2: &[D])
283    where
284        D: Flatten<Node> + HasBundleKind,
285    {
286        if s2.len() > 1 {
287            for s in &s2[1..] {
288                self.connect(&s2[0], s);
289            }
290        }
291    }
292
293    /// Marks this cell as a SCIR cell.
294    pub fn set_scir(&mut self, scir: ScirBinding<S>) {
295        self.contents = RawCellContentsBuilder::Scir(scir);
296    }
297
298    /// Marks this cell as a primitive.
299    pub fn set_primitive(&mut self, primitive: PrimitiveBinding<S>) {
300        self.contents = RawCellContentsBuilder::Primitive(primitive);
301    }
302
303    /// Gets the global context.
304    pub fn ctx(&self) -> &Context {
305        &self.ctx
306    }
307
308    /// Starts generating a block in a new thread and returns a handle to its cell.
309    ///
310    /// Can be used to check data stored in the cell or other generated results before adding the
311    /// cell to the current schematic with [`CellBuilder::add`].
312    ///
313    /// To generate and add the block simultaneously, use [`CellBuilder::instantiate`].
314    pub fn generate<B: Schematic<Schema = S>>(
315        &mut self,
316        block: B,
317    ) -> SchemaCellHandle<B::Schema, B> {
318        self.ctx().generate_schematic(block)
319    }
320
321    /// Generates a cell corresponding to `block` and returns a handle to it.
322    ///
323    /// Blocks on generation. Useful for handling errors thrown by the generation of a cell immediately.
324    ///
325    /// As with [`CellBuilder::generate`], the resulting handle must be added to the schematic with
326    /// [`CellBuilder::add`] before it can be connected as an instance.
327    pub fn generate_blocking<B: Schematic<Schema = S>>(
328        &mut self,
329        block: B,
330    ) -> Result<SchemaCellHandle<B::Schema, B>> {
331        let handle = self.ctx().generate_schematic(block);
332        handle.cell.try_cell()?;
333        Ok(handle)
334    }
335
336    /// Adds a cell generated with [`CellBuilder::generate`] to the current schematic.
337    ///
338    /// Does not block on generation. If immediate error recovery is desired,
339    /// check errors before calling this function using [`CellHandle::try_cell`].
340    ///
341    /// # Panics
342    ///
343    /// If the instantiated cell fails to generate, this function will eventually cause a panic after
344    /// the parent cell's generator completes. To avoid this, return errors using [`Instance::try_data`]
345    /// before your generator returns.
346    #[track_caller]
347    pub fn add<B: Schematic>(&mut self, cell: SchemaCellHandle<S, B>) -> Instance<B>
348    where
349        S: FromSchema<B::Schema>,
350    {
351        self.post_instantiate(cell, SourceInfo::from_caller(), None)
352    }
353
354    /// Instantiates a schematic view of the given block.
355    ///
356    /// This function generates and adds the cell to the schematic. If checks need to be done on
357    /// the generated cell before it is added to the schematic, use [`CellBuilder::generate`] and
358    /// [`CellBuilder::add`].
359    ///
360    /// Spawns a thread that generates the underlying cell. If immediate error
361    /// recovery is desired, use the generate and add workflow mentioned above.
362    ///
363    /// # Panics
364    ///
365    /// If the instantiated cell fails to generate, this function will eventually cause a panic after
366    /// the parent cell's generator completes. To avoid this, return errors using [`Instance::try_data`]
367    /// before your generator returns.
368    ///
369    /// If an error is not returned from the enclosing generator, but this function returns
370    /// an error, the enclosing generator will panic since the instantiation irrecoverably failed.
371    #[track_caller]
372    pub fn instantiate<B: Schematic<Schema = S>>(&mut self, block: B) -> Instance<B> {
373        let cell = self.ctx().generate_schematic(block);
374        self.post_instantiate(cell, SourceInfo::from_caller(), None)
375    }
376
377    /// Instantiates a block and assigns a name to the instance.
378    ///
379    /// See [`CellBuilder::instantiate`] for details.
380    ///
381    /// Callers must ensure that instance names are unique.
382    #[track_caller]
383    pub fn instantiate_named<B: Schematic<Schema = S>>(
384        &mut self,
385        block: B,
386        name: impl Into<ArcStr>,
387    ) -> Instance<B> {
388        let cell = self.ctx().generate_schematic(block);
389        self.post_instantiate(cell, SourceInfo::from_caller(), Some(name.into()))
390    }
391
392    /// Instantiates a schematic view of the given block, blocking on generator for underlying
393    /// cell. Returns an error if the generator returned an error.
394    ///
395    /// See [`SubCellBuilder::instantiate`] for details.
396    ///
397    /// # Panics
398    ///
399    /// If an error is not returned from the enclosing generator, but this function returns
400    /// an error, the enclosing generator will panic since the instantiation irrecoverably failed.
401    #[track_caller]
402    pub fn instantiate_blocking<B: Schematic<Schema = S>>(
403        &mut self,
404        block: B,
405    ) -> Result<Instance<B>> {
406        let inst = self.instantiate(block);
407        inst.try_data()?;
408        Ok(inst)
409    }
410
411    /// Creates an instance using [`CellBuilder::instantiate`] and immediately connects its ports.
412    pub fn instantiate_connected<B, C>(&mut self, block: B, io: C) -> Instance<B>
413    where
414        B: Schematic<Schema = S>,
415        C: Flatten<Node> + HasBundleKind<BundleKind = IoKind<B>>,
416    {
417        let inst = self.instantiate(block);
418        self.connect(inst.io(), io);
419        inst
420    }
421
422    /// Creates an instance using [`CellBuilder::instantiate`] and immediately connects its ports.
423    pub fn instantiate_connected_named<B, C>(
424        &mut self,
425        block: B,
426        io: C,
427        name: impl Into<ArcStr>,
428    ) -> Instance<B>
429    where
430        B: Schematic<Schema = S>,
431        C: Flatten<Node> + HasBundleKind<BundleKind = IoKind<B>>,
432    {
433        let inst = self.instantiate_named(block, name);
434        self.connect(inst.io(), io);
435        inst
436    }
437
438    /// Creates nodes for the newly-instantiated block's IOs and adds the raw instance.
439    fn post_instantiate<B: Schematic>(
440        &mut self,
441        cell: SchemaCellHandle<S, B>,
442        source_info: SourceInfo,
443        name: Option<ArcStr>,
444    ) -> Instance<B>
445    where
446        S: FromSchema<B::Schema>,
447    {
448        let io = cell.cell.block.io();
449        let cell_contents = self.contents.as_mut().unwrap_cell();
450        cell_contents.next_instance_id.increment();
451
452        let inst_name =
453            name.unwrap_or_else(|| arcstr::format!("xinst{}", cell_contents.instances.len()));
454
455        let (nodes, io_data) =
456            self.node_ctx
457                .instantiate_directed(&io, NodePriority::Auto, source_info);
458
459        let names = <<B as Block>::Io as HasBundleKind>::kind(&io)
460            .flat_names(Some(inst_name.clone().into()));
461        assert_eq!(nodes.len(), names.len());
462
463        self.node_names.extend(nodes.iter().copied().zip(names));
464
465        let root = InstancePath::new(self.id);
466        let inst = Instance {
467            id: cell_contents.next_instance_id,
468            parent: root.clone(),
469            path: root.append_segment(cell_contents.next_instance_id, cell.cell.id),
470            cell: cell.cell,
471            io: Arc::new(io_data),
472            terminal_view: OnceCell::new(),
473            nested_data: OnceCell::new(),
474        };
475
476        cell_contents.instances.push(RawInstanceBuilder {
477            id: inst.id,
478            name: inst_name.clone(),
479            // name: arcstr::literal!("unnamed"),
480            connections: nodes,
481            child: cell.handle.map(|handle| match handle {
482                Ok(Ok(SchemaCellCacheValue { raw, .. })) => Ok(raw.clone()),
483                Ok(Err(e)) => {
484                    tracing::error!("{:?}", e);
485                    panic!("cell generator failed")
486                }
487                Err(e) => {
488                    tracing::error!("{:?}", e);
489                    panic!("cache failed")
490                }
491            }),
492        });
493
494        inst
495    }
496
497    /// Creates a [`SubCellBuilder`] for instantiating blocks from schema `S2`.
498    pub fn sub_builder<S2: Schema + ?Sized>(&mut self) -> SubCellBuilder<'_, S, S2>
499    where
500        S: FromSchema<S2>,
501    {
502        SubCellBuilder(self, PhantomData)
503    }
504}
505
506/// A cell builder for instantiating blocks from schema `S2` in schema `S`.
507pub struct SubCellBuilder<'a, S1: Schema + ?Sized, S2: Schema + ?Sized>(
508    &'a mut CellBuilder<S1>,
509    PhantomData<S2>,
510);
511
512impl<S1: FromSchema<S2>, S2: Schema + ?Sized> SubCellBuilder<'_, S1, S2> {
513    /// Create a new signal with the given name and hardware type.
514    #[track_caller]
515    pub fn signal<K: HasBundleKind<BundleKind: SchematicBundleKind>>(
516        &mut self,
517        name: impl Into<ArcStr>,
518        kind: K,
519    ) -> NodeBundle<K> {
520        self.0.signal(name, kind)
521    }
522
523    /// Connect all signals in the given data instances.
524    pub fn connect<D1, D2>(&mut self, s1: D1, s2: D2)
525    where
526        D1: Flatten<Node> + HasBundleKind,
527        D2: Flatten<Node> + HasBundleKind<BundleKind = <D1 as HasBundleKind>::BundleKind>,
528    {
529        self.0.connect(s1, s2)
530    }
531
532    /// Gets the global context.
533    pub fn ctx(&self) -> &Context {
534        &self.0.ctx
535    }
536
537    /// Starts generating a block in a new thread and returns a handle to its cell.
538    ///
539    /// Can be used to check data stored in the cell or other generated results before adding the
540    /// cell to the current schematic with [`CellBuilder::add`].
541    ///
542    /// To generate and add the block simultaneously, use [`CellBuilder::instantiate`].
543    pub fn generate<B: Schematic<Schema = S2>>(
544        &mut self,
545        block: B,
546    ) -> SchemaCellHandle<B::Schema, B> {
547        self.ctx().generate_cross_schematic(block)
548    }
549
550    /// Generates a cell corresponding to `block` and returns a handle to it.
551    ///
552    /// Blocks on generation. Useful for handling errors thrown by the generation of a cell immediately.
553    ///
554    /// As with [`CellBuilder::generate`], the resulting handle must be added to the schematic with
555    /// [`CellBuilder::add`] before it can be connected as an instance.
556    pub fn generate_blocking<B: Schematic<Schema = S2>>(
557        &mut self,
558        block: B,
559    ) -> Result<SchemaCellHandle<B::Schema, B>> {
560        let handle = self.ctx().generate_cross_schematic(block);
561        handle.cell.try_cell()?;
562        Ok(handle)
563    }
564
565    /// Adds a cell generated with [`CellBuilder::generate`] to the current schematic.
566    ///
567    /// Does not block on generation. If immediate error recovery is desired,
568    /// check errors before calling this function using [`CellHandle::try_cell`].
569    ///
570    /// # Panics
571    ///
572    /// If the instantiated cell fails to generate, this function will eventually cause a panic after
573    /// the parent cell's generator completes. To avoid this, return errors using [`Instance::try_data`]
574    /// before your generator returns.
575    #[track_caller]
576    pub fn add<B: Schematic<Schema = S2>>(&mut self, cell: SchemaCellHandle<S1, B>) -> Instance<B> {
577        self.0.add(cell)
578    }
579
580    /// Instantiates a schematic view of the given block.
581    ///
582    /// This function generates and adds the cell to the schematic. If checks need to be done on
583    /// the generated cell before it is added to the schematic, use [`SubCellBuilder::generate`] and
584    /// [`SubCellBuilder::add`].
585    ///
586    /// Spawns a thread that generates the underlying cell. If immediate error
587    /// recovery is desired, use the generate and add workflow mentioned above.
588    ///
589    /// # Panics
590    ///
591    /// If the instantiated cell fails to generate, this function will eventually cause a panic after
592    /// the parent cell's generator completes. To avoid this, return errors using [`Instance::try_data`]
593    /// before your generator returns.
594    ///
595    /// If an error is not returned from the enclosing generator, but this function returns
596    /// an error, the enclosing generator will panic since the instantiation irrecoverably failed.
597    #[track_caller]
598    pub fn instantiate<B: Schematic<Schema = S2>>(&mut self, block: B) -> Instance<B> {
599        let cell = self.ctx().generate_cross_schematic(block);
600        self.post_instantiate(cell, SourceInfo::from_caller(), None)
601    }
602
603    /// Instantiates a block and assigns a name to the instance.
604    ///
605    /// See [`CellBuilder::instantiate`] for details.
606    ///
607    /// Callers must ensure that instance names are unique.
608    #[track_caller]
609    pub fn instantiate_named<B: Schematic<Schema = S2>>(
610        &mut self,
611        block: B,
612        name: impl Into<ArcStr>,
613    ) -> Instance<B> {
614        let cell = self.ctx().generate_cross_schematic(block);
615        self.post_instantiate(cell, SourceInfo::from_caller(), Some(name.into()))
616    }
617
618    /// Instantiates a schematic view of the given block, blocking on generator for underlying
619    /// cell. Returns an error if the generator returned an error.
620    ///
621    /// See [`SubCellBuilder::instantiate`] for details.
622    ///
623    /// # Panics
624    ///
625    /// If an error is not returned from the enclosing generator, but this function returns
626    /// an error, the enclosing generator will panic since the instantiation irrecoverably failed.
627    #[track_caller]
628    pub fn instantiate_blocking<B: Schematic<Schema = S2>>(
629        &mut self,
630        block: B,
631    ) -> Result<Instance<B>> {
632        let inst = self.instantiate(block);
633        inst.try_data()?;
634        Ok(inst)
635    }
636
637    /// Creates an instance using [`SubCellBuilder::instantiate`] and immediately connects its ports.
638    pub fn instantiate_connected<B, C>(&mut self, block: B, io: C) -> Instance<B>
639    where
640        B: Schematic<Schema = S2>,
641        C: Flatten<Node> + HasBundleKind<BundleKind = IoKind<B>>,
642    {
643        let inst = self.instantiate(block);
644        self.connect(inst.io(), io);
645        inst
646    }
647
648    /// Creates an instance using [`SubCellBuilder::instantiate`] and immediately connects its ports.
649    pub fn instantiate_connected_named<B, C>(
650        &mut self,
651        block: B,
652        io: C,
653        name: impl Into<ArcStr>,
654    ) -> Instance<B>
655    where
656        B: Schematic<Schema = S2>,
657        C: Flatten<Node> + HasBundleKind<BundleKind = IoKind<B>>,
658    {
659        let inst = self.instantiate_named(block, name);
660        self.connect(inst.io(), io);
661        inst
662    }
663
664    /// Creates nodes for the newly-instantiated block's IOs.
665    fn post_instantiate<B: Schematic<Schema = S2>>(
666        &mut self,
667        cell: SchemaCellHandle<S1, B>,
668        source_info: SourceInfo,
669        name: Option<ArcStr>,
670    ) -> Instance<B> {
671        self.0.post_instantiate(cell, source_info, name)
672    }
673}
674
675/// A schematic cell.
676pub struct Cell<T: Schematic> {
677    /// The block from which this cell was generated.
678    block: Arc<T>,
679    /// Data returned by the cell's schematic generator.
680    nodes: Arc<T::NestedData>,
681    /// The cell's input/output interface.
682    io: Arc<IoNodeBundle<T>>,
683    /// The path corresponding to this cell.
684    path: InstancePath,
685
686    pub(crate) raw: Arc<RawCell<T::Schema>>,
687
688    /// Stored nested data for deref purposes.
689    nested_data: OnceCell<Arc<NestedView<T::NestedData>>>,
690}
691
692impl<T: Schematic> Deref for Cell<T> {
693    type Target = NestedView<T::NestedData>;
694
695    fn deref(&self) -> &Self::Target {
696        self.nested_data
697            .get_or_init(|| Arc::new(self.data()))
698            .as_ref()
699    }
700}
701
702impl<T: Schematic> Clone for Cell<T> {
703    fn clone(&self) -> Self {
704        Self {
705            block: self.block.clone(),
706            nodes: self.nodes.clone(),
707            io: self.io.clone(),
708            path: self.path.clone(),
709            raw: self.raw.clone(),
710            nested_data: self.nested_data.clone(),
711        }
712    }
713}
714
715impl<T: Schematic> Cell<T> {
716    pub(crate) fn new(
717        id: CellId,
718        io: Arc<IoNodeBundle<T>>,
719        block: Arc<T>,
720        raw: Arc<RawCell<T::Schema>>,
721        data: Arc<T::NestedData>,
722    ) -> Self {
723        Self {
724            io,
725            block,
726            nodes: data,
727            path: InstancePath::new(id),
728            raw,
729            nested_data: OnceCell::new(),
730        }
731    }
732
733    /// Returns the block whose schematic this cell represents.
734    pub fn block(&self) -> &T {
735        &self.block
736    }
737
738    /// Returns nested data propagated by the cell's schematic generator.
739    pub fn data(&self) -> NestedView<T::NestedData> {
740        self.nodes.nested_view(&self.path)
741    }
742
743    /// Returns the cell's exposed data, nested using the given parent.
744    pub fn context_data<V>(&self, parent: &V) -> ContextView<T::NestedData, V>
745    where
746        T::NestedData: HasContextView<V>,
747    {
748        self.nodes.context_view(parent)
749    }
750
751    /// Returns this cell's IO.
752    pub fn io(&self) -> NestedView<IoNodeBundle<T>> {
753        self.io.nested_view(&self.path)
754    }
755}
756
757/// A handle to a schematic cell that is being generated.
758pub struct CellHandle<B: Schematic> {
759    pub(crate) id: CellId,
760    pub(crate) block: Arc<B>,
761    pub(crate) io_data: Arc<IoNodeBundle<B>>,
762    pub(crate) cell: CacheHandle<Result<Arc<Cell<B>>>>,
763}
764
765impl<B: Schematic> Clone for CellHandle<B> {
766    fn clone(&self) -> Self {
767        Self {
768            id: self.id,
769            block: self.block.clone(),
770            io_data: self.io_data.clone(),
771            cell: self.cell.clone(),
772        }
773    }
774}
775
776impl<B: Schematic> CellHandle<B> {
777    /// Tries to access the underlying [`Cell`].
778    ///
779    /// Blocks until cell generation completes and returns an error if one was thrown during generation.
780    pub fn try_cell(&self) -> Result<&Cell<B>> {
781        // TODO: Handle cache errors with more granularity.
782        self.cell
783            .try_get()
784            .as_ref()
785            .map_err(|_| Error::Internal)?
786            .as_ref()
787            .map(|cell| cell.as_ref())
788            .map_err(|e| e.clone())
789    }
790    /// Returns the underlying [`Cell`].
791    ///
792    /// Blocks until cell generation completes.
793    ///
794    /// # Panics
795    ///
796    /// Panics if generation fails.
797    pub fn cell(&self) -> &Cell<B> {
798        self.try_cell().expect("cell generation failed")
799    }
800}
801
802pub(crate) struct SchemaCellCacheValue<S: Schema + ?Sized, B: Schematic> {
803    pub(crate) raw: Arc<RawCell<S>>,
804    pub(crate) cell: Arc<Cell<B>>,
805}
806
807/// A cell handle associated with a schema `S`.
808pub struct SchemaCellHandle<S: Schema + ?Sized, B: Schematic> {
809    pub(crate) handle: CacheHandle<Result<SchemaCellCacheValue<S, B>>>,
810    pub(crate) cell: CellHandle<B>,
811}
812
813impl<S: Schema, B: Schematic> SchemaCellHandle<S, B> {
814    /// Tries to access the underlying [`Cell`].
815    ///
816    /// Blocks until cell generation completes and returns an error if one was thrown during generation.
817    pub fn try_cell(&self) -> Result<&Cell<B>> {
818        // TODO: Handle cache errors with more granularity.
819        self.cell.try_cell()
820    }
821
822    /// Returns the underlying [`Cell`].
823    ///
824    /// Blocks until cell generation completes.
825    ///
826    /// # Panics
827    ///
828    /// Panics if generation fails.
829    pub fn cell(&self) -> &Cell<B> {
830        self.cell.cell()
831    }
832
833    /// Returns the raw cell.
834    #[doc(hidden)]
835    pub fn raw(&self) -> Arc<RawCell<S>> {
836        let val = self.handle.unwrap_inner();
837        val.raw.clone()
838    }
839}
840
841impl<S: Schema + ?Sized, B: Schematic> Deref for SchemaCellHandle<S, B> {
842    type Target = CellHandle<B>;
843
844    fn deref(&self) -> &Self::Target {
845        &self.cell
846    }
847}
848
849impl<S: Schema + ?Sized, B: Schematic> Clone for SchemaCellHandle<S, B> {
850    fn clone(&self) -> Self {
851        Self {
852            handle: self.handle.clone(),
853            cell: self.cell.clone(),
854        }
855    }
856}
857
858/// An instance of a schematic cell.
859#[allow(dead_code)]
860pub struct Instance<B: Schematic> {
861    id: InstanceId,
862    /// Path of the parent cell.
863    parent: InstancePath,
864    /// Path to this instance relative to the current cell.
865    path: InstancePath,
866    /// The cell's input/output interface.
867    io: Arc<IoNodeBundle<B>>,
868    cell: CellHandle<B>,
869    /// Stored terminal view for IO purposes.
870    terminal_view: OnceCell<Arc<IoTerminalBundle<B>>>,
871    /// Stored nested data for deref purposes.
872    nested_data: OnceCell<Arc<NestedView<B::NestedData>>>,
873}
874
875impl<T: Schematic> Deref for Instance<T> {
876    type Target = NestedView<T::NestedData>;
877
878    fn deref(&self) -> &Self::Target {
879        self.nested_data
880            .get_or_init(|| Arc::new(self.data()))
881            .as_ref()
882    }
883}
884
885impl<B: Schematic> Clone for Instance<B> {
886    fn clone(&self) -> Self {
887        Self {
888            id: self.id,
889            parent: self.parent.clone(),
890            path: self.path.clone(),
891            io: self.io.clone(),
892            cell: self.cell.clone(),
893            terminal_view: self.terminal_view.clone(),
894            nested_data: self.nested_data.clone(),
895        }
896    }
897}
898
899impl<B: Schematic> HasNestedView for Instance<B> {
900    type NestedView = NestedInstance<B>;
901    fn nested_view(&self, parent: &InstancePath) -> NestedView<Self> {
902        let mut inst = (*self).clone();
903        inst.path = self.path.prepend(parent);
904        inst.parent = self.parent.prepend(parent);
905        inst.nested_data = OnceCell::new();
906        inst.terminal_view = OnceCell::new();
907        NestedInstance(inst)
908    }
909}
910
911impl<T: Schematic> Instance<T> {
912    /// The ports of this instance.
913    ///
914    /// Used for node connection purposes.
915    pub fn io(&self) -> &IoTerminalBundle<T> {
916        self.terminal_view
917            .get_or_init(|| {
918                Arc::new(<IoKind<T> as SchematicBundleKind>::terminal_view(
919                    self.cell.id,
920                    self.cell.io_data.as_ref(),
921                    self.id,
922                    &self.io,
923                ))
924            })
925            .as_ref()
926    }
927
928    /// Tries to access the underlying cell data.
929    ///
930    /// Returns an error if one was thrown during generation.
931    pub fn try_data(&self) -> Result<NestedView<T::NestedData>> {
932        self.cell
933            .try_cell()
934            .map(|data| data.nodes.nested_view(&self.path))
935    }
936
937    /// Tries to access the underlying cell data.
938    ///
939    /// # Panics
940    ///
941    /// Panics if an error was thrown during generation.
942    pub fn data(&self) -> NestedView<T::NestedData> {
943        self.cell.cell().nodes.nested_view(&self.path)
944    }
945
946    /// Tries to access the underlying block used to create this instance's cell.
947    ///
948    /// # Panics
949    ///
950    /// Panics if an error was thrown during generation.
951    pub fn block(&self) -> &T {
952        &self.cell.block
953    }
954
955    /// Returns the path to this [`Instance`].
956    pub fn path(&self) -> &InstancePath {
957        &self.path
958    }
959}
960
961/// A nested view of an [`Instance`].
962pub struct NestedInstance<T: Schematic>(Instance<T>);
963
964impl<T: Schematic> Deref for NestedInstance<T> {
965    type Target = NestedView<T::NestedData>;
966
967    fn deref(&self) -> &Self::Target {
968        &self.0
969    }
970}
971
972impl<B: Schematic> Clone for NestedInstance<B> {
973    fn clone(&self) -> Self {
974        Self(self.0.clone())
975    }
976}
977
978impl<B: Schematic> HasNestedView for NestedInstance<B> {
979    type NestedView = NestedInstance<B>;
980    fn nested_view(&self, parent: &InstancePath) -> NestedView<Self> {
981        let mut inst = (*self).clone();
982        inst.0.path = self.0.path.prepend(parent);
983        inst.0.parent = self.0.parent.prepend(parent);
984        inst.0.nested_data = OnceCell::new();
985        inst.0.terminal_view = OnceCell::new();
986        inst
987    }
988}
989
990impl<T: Schematic> NestedInstance<T> {
991    /// The ports of this instance.
992    ///
993    /// Used for node connection purposes.
994    pub fn io(&self) -> NestedView<IoTerminalBundle<T>> {
995        self.0.io().nested_view(&self.0.parent)
996    }
997
998    /// Tries to access the underlying cell data.
999    ///
1000    /// Returns an error if one was thrown during generation.
1001    pub fn try_data(&self) -> Result<NestedView<T::NestedData>> {
1002        self.0.try_data()
1003    }
1004
1005    /// Tries to access the underlying cell data.
1006    ///
1007    /// # Panics
1008    ///
1009    /// Panics if an error was thrown during generation.
1010    pub fn data(&self) -> NestedView<T::NestedData> {
1011        self.0.data()
1012    }
1013
1014    /// Tries to access the underlying block used to create this instance's cell.
1015    pub fn block(&self) -> &T {
1016        self.0.block()
1017    }
1018
1019    /// Returns the path to this [`NestedInstance`].
1020    pub fn path(&self) -> &InstancePath {
1021        &self.0.path
1022    }
1023}
1024
1025/// A wrapper around schematic-specific context data.
1026#[derive(Debug)]
1027pub struct SchematicContext {
1028    pub(crate) next_id: CellId,
1029    /// Cache from [`CellCacheKey`] and [`ConvCacheKey`]
1030    /// to `Result<(Arc<RawCell>, Arc<Cell>)>`.
1031    pub(crate) cell_cache: TypeCache,
1032}
1033
1034impl Default for SchematicContext {
1035    fn default() -> Self {
1036        Self {
1037            next_id: CellId(0),
1038            cell_cache: Default::default(),
1039        }
1040    }
1041}
1042
1043impl SchematicContext {
1044    #[allow(dead_code)]
1045    pub(crate) fn new() -> Self {
1046        Self::default()
1047    }
1048}
1049
1050/// Cell metadata that can be generated quickly.
1051pub(crate) struct CellMetadata<B: Schematic> {
1052    pub(crate) id: CellId,
1053    pub(crate) io_data: Arc<IoNodeBundle<B>>,
1054}
1055
1056impl<B: Schematic> Clone for CellMetadata<B> {
1057    fn clone(&self) -> Self {
1058        Self {
1059            id: self.id,
1060            io_data: self.io_data.clone(),
1061        }
1062    }
1063}
1064
1065pub(crate) struct CellCacheKey<B, S: ?Sized> {
1066    pub(crate) block: Arc<B>,
1067    pub(crate) phantom: PhantomData<S>,
1068}
1069
1070impl<B, S: ?Sized> Clone for CellCacheKey<B, S> {
1071    fn clone(&self) -> Self {
1072        Self {
1073            block: self.block.clone(),
1074            phantom: PhantomData,
1075        }
1076    }
1077}
1078
1079impl<B: PartialEq, S: ?Sized> PartialEq for CellCacheKey<B, S> {
1080    fn eq(&self, other: &Self) -> bool {
1081        self.block.eq(&other.block)
1082    }
1083}
1084
1085impl<B: Eq, S: ?Sized> Eq for CellCacheKey<B, S> {}
1086
1087impl<B: Hash, S: ?Sized> Hash for CellCacheKey<B, S> {
1088    fn hash<H: Hasher>(&self, state: &mut H) {
1089        self.block.hash(state)
1090    }
1091}
1092
1093/// A key for a block that was generated in schema `S1` and converted to schema `S2`.
1094pub(crate) type ConvCacheKey<B, S1, S2> = CellCacheKey<B, (PhantomData<S1>, S2)>;
1095
1096/// A path to an instance from a top level cell.
1097///
1098/// Inexpensive to clone as it only clones an ID and a reference counted pointer.
1099#[derive(Debug, Clone, Eq, PartialEq, Hash)]
1100pub struct InstancePath {
1101    /// The ID of the top level cell that this path is relative to.
1102    pub(crate) top: CellId,
1103    /// The ID of the last instance's underlying cell.
1104    ///
1105    /// Allows for verification that two paths can be concatenated.
1106    /// `None` if path is empty.
1107    pub(crate) bot: Option<CellId>,
1108    /// A path of instance IDs.
1109    pub(crate) path: PathTree<InstanceId>,
1110}
1111
1112impl InstancePath {
1113    pub(crate) fn new(top: CellId) -> Self {
1114        Self {
1115            top,
1116            bot: None,
1117            path: PathTree::empty(),
1118        }
1119    }
1120    #[allow(dead_code)]
1121    pub(crate) fn append(&self, other: &Self) -> Self {
1122        if let Some(bot) = self.bot {
1123            assert_eq!(
1124                bot, other.top,
1125                "path to append must start with the cell ID that the current path ends with"
1126            );
1127        } else {
1128            assert_eq!(
1129                self.top, other.top,
1130                "path to append must start with the cell ID that the current path ends with"
1131            );
1132        }
1133        Self {
1134            top: self.top,
1135            bot: other.bot,
1136            path: self.path.append(&other.path),
1137        }
1138    }
1139
1140    /// Prepend another path to this path.
1141    pub fn prepend(&self, other: &Self) -> Self {
1142        if let Some(bot) = other.bot {
1143            assert_eq!(
1144                bot, self.top,
1145                "path to prepend must end with the cell ID that the current path starts with"
1146            );
1147        } else {
1148            assert_eq!(
1149                other.top, self.top,
1150                "path to prepend must end with the cell ID that the current path starts with"
1151            );
1152        }
1153        Self {
1154            top: other.top,
1155            bot: self.bot,
1156            path: self.path.prepend(&other.path),
1157        }
1158    }
1159
1160    pub(crate) fn append_segment(&self, id: InstanceId, cell_id: CellId) -> Self {
1161        Self {
1162            top: self.top,
1163            bot: Some(cell_id),
1164            path: self.path.append_segment(id),
1165        }
1166    }
1167
1168    #[allow(dead_code)]
1169    pub(crate) fn is_empty(&self) -> bool {
1170        self.bot.is_none()
1171    }
1172}
1173
1174/// A raw (weakly-typed) instance of a cell.
1175#[allow(dead_code)]
1176pub(crate) struct RawInstanceBuilder<S: Schema + ?Sized> {
1177    id: InstanceId,
1178    name: ArcStr,
1179    connections: Vec<Node>,
1180    child: CacheHandle<Arc<RawCell<S>>>,
1181}
1182
1183impl<S: Schema<Primitive = impl std::fmt::Debug> + ?Sized> std::fmt::Debug
1184    for RawInstanceBuilder<S>
1185{
1186    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1187        let mut builder = f.debug_struct("RawInstanceBuilder");
1188        let _ = builder.field("id", &self.id);
1189        let _ = builder.field("name", &self.name);
1190        let _ = builder.field("connections", &self.connections);
1191        let _ = builder.field("child", &self.child);
1192        builder.finish()
1193    }
1194}
1195
1196impl<S: Schema + ?Sized> RawInstanceBuilder<S> {
1197    fn build(self) -> RawInstance<S> {
1198        RawInstance {
1199            id: self.id,
1200            name: self.name,
1201            connections: self.connections,
1202            child: self.child.get().clone(),
1203        }
1204    }
1205}
1206
1207/// A raw (weakly-typed) instance of a cell.
1208#[allow(dead_code)]
1209pub(crate) struct RawInstance<S: Schema + ?Sized> {
1210    id: InstanceId,
1211    name: ArcStr,
1212    connections: Vec<Node>,
1213    child: Arc<RawCell<S>>,
1214}
1215
1216impl<S: Schema<Primitive = impl std::fmt::Debug> + ?Sized> std::fmt::Debug for RawInstance<S> {
1217    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1218        let mut builder = f.debug_struct("RawInstance");
1219        let _ = builder.field("id", &self.id);
1220        let _ = builder.field("name", &self.name);
1221        let _ = builder.field("connections", &self.connections);
1222        let _ = builder.field("child", &self.child);
1223        builder.finish()
1224    }
1225}
1226
1227impl<S: Schema + ?Sized> Clone for RawInstance<S> {
1228    fn clone(&self) -> Self {
1229        Self {
1230            id: self.id,
1231            name: self.name.clone(),
1232            connections: self.connections.clone(),
1233            child: self.child.clone(),
1234        }
1235    }
1236}
1237
1238impl<S: Schema + ?Sized> RawInstance<S> {
1239    fn convert_schema<S2: FromSchema<S> + ?Sized>(self) -> Result<RawInstance<S2>> {
1240        Ok(RawInstance {
1241            id: self.id,
1242            name: self.name,
1243            connections: self.connections,
1244            child: Arc::new((*self.child).clone().convert_schema()?),
1245        })
1246    }
1247}
1248
1249/// A raw (weakly-typed) cell.
1250///
1251/// Only public for the sake of making the [`Schematic`] trait public,
1252/// should not have any public methods.
1253#[doc(hidden)]
1254pub struct RawCell<S: Schema + ?Sized> {
1255    id: CellId,
1256    pub(crate) name: ArcStr,
1257    ports: Vec<Port>,
1258    uf: NodeUf,
1259    node_names: HashMap<Node, NameBuf>,
1260    roots: HashMap<Node, Node>,
1261    /// Whether this cell should be flattened when being exported.
1262    flatten: bool,
1263    contents: RawCellContents<S>,
1264}
1265
1266// TODO: See if can make these without using `= impl`.
1267impl<S: Schema<Primitive = impl std::fmt::Debug> + ?Sized> std::fmt::Debug for RawCell<S> {
1268    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1269        let mut builder = f.debug_struct("RawCell");
1270        let _ = builder.field("id", &self.id);
1271        let _ = builder.field("name", &self.name);
1272        let _ = builder.field("ports", &self.ports);
1273        let _ = builder.field("uf", &self.uf);
1274        let _ = builder.field("node_names", &self.node_names);
1275        let _ = builder.field("roots", &self.roots);
1276        let _ = builder.field("contents", &self.contents);
1277        let _ = builder.field("flatten", &self.flatten);
1278        builder.finish()
1279    }
1280}
1281
1282impl<S: Schema + ?Sized> Clone for RawCell<S> {
1283    fn clone(&self) -> Self {
1284        Self {
1285            id: self.id,
1286            name: self.name.clone(),
1287            ports: self.ports.clone(),
1288            uf: self.uf.clone(),
1289            node_names: self.node_names.clone(),
1290            roots: self.roots.clone(),
1291            contents: self.contents.clone(),
1292            flatten: self.flatten,
1293        }
1294    }
1295}
1296
1297impl<S: Schema + ?Sized> RawCell<S> {
1298    pub(crate) fn convert_schema<S2: FromSchema<S> + ?Sized>(self) -> Result<RawCell<S2>> {
1299        Ok(RawCell {
1300            id: self.id,
1301            name: self.name,
1302            ports: self.ports,
1303            uf: self.uf,
1304            node_names: self.node_names,
1305            roots: self.roots,
1306            flatten: self.flatten,
1307            contents: self.contents.convert_schema()?,
1308        })
1309    }
1310}
1311
1312/// The contents of a raw cell.
1313pub(crate) type RawCellContentsBuilder<S> =
1314    RawCellKind<RawCellInnerBuilder<S>, ScirBinding<S>, PrimitiveBinding<S>, ConvertedPrimitive<S>>;
1315
1316impl<S: Schema + ?Sized> RawCellContentsBuilder<S> {
1317    fn build(self) -> RawCellContents<S> {
1318        match self {
1319            RawCellContentsBuilder::Cell(b) => RawCellContents::Cell(b.build()),
1320            RawCellContentsBuilder::Scir(s) => RawCellContents::Scir(s),
1321            RawCellContentsBuilder::Primitive(s) => RawCellContents::Primitive(s),
1322            RawCellContentsBuilder::ConvertedPrimitive(s) => RawCellContents::ConvertedPrimitive(s),
1323        }
1324    }
1325}
1326
1327/// The contents of a raw cell.
1328pub(crate) type RawCellContents<S> =
1329    RawCellKind<RawCellInner<S>, ScirBinding<S>, PrimitiveBinding<S>, ConvertedPrimitive<S>>;
1330
1331impl<S: Schema + ?Sized> RawCellContents<S> {
1332    fn convert_schema<S2: FromSchema<S> + ?Sized>(self) -> Result<RawCellContents<S2>> {
1333        Ok(match self {
1334            RawCellContents::Cell(c) => RawCellContents::Cell(c.convert_schema()?),
1335            RawCellContents::Scir(s) => RawCellContents::Scir(ScirBinding {
1336                lib: s
1337                    .lib
1338                    .convert_schema()
1339                    .map_err(|_| Error::UnsupportedPrimitive)?
1340                    .build()
1341                    .map_err(ConvError::from)?,
1342                cell: s.cell,
1343                port_map: s.port_map,
1344            }),
1345            RawCellContents::Primitive(p) => {
1346                RawCellContents::ConvertedPrimitive(ConvertedPrimitive {
1347                    converted: <S2 as scir::schema::FromSchema<S>>::convert_primitive(
1348                        p.primitive.clone(),
1349                    )
1350                    .map_err(|_| Error::UnsupportedPrimitive)?,
1351                    original: Arc::new(p),
1352                })
1353            }
1354            RawCellContents::ConvertedPrimitive(p) => {
1355                RawCellContents::ConvertedPrimitive(ConvertedPrimitive {
1356                    converted: <S2 as scir::schema::FromSchema<S>>::convert_primitive(
1357                        p.converted.clone(),
1358                    )
1359                    .map_err(|_| Error::UnsupportedPrimitive)?,
1360                    original: Arc::new(p),
1361                })
1362            }
1363        })
1364    }
1365}
1366
1367pub(crate) trait ConvertPrimitive<S: Schema + ?Sized>: Any + Send + Sync {
1368    fn convert_primitive(&self) -> Result<<S as Schema>::Primitive>;
1369    fn convert_instance(&self, inst: &mut scir::Instance) -> Result<()>;
1370    fn port_map(&self) -> &HashMap<ArcStr, Vec<Node>>;
1371}
1372
1373impl<S1: FromSchema<S2> + ?Sized, S2: Schema + ?Sized> ConvertPrimitive<S1>
1374    for PrimitiveBinding<S2>
1375{
1376    // TODO: Improve error handling
1377    fn convert_primitive(&self) -> Result<<S1 as Schema>::Primitive> {
1378        <S1 as scir::schema::FromSchema<S2>>::convert_primitive(self.primitive.clone())
1379            .map_err(|_| Error::UnsupportedPrimitive)
1380    }
1381    fn convert_instance(&self, inst: &mut scir::Instance) -> Result<()> {
1382        <S1 as scir::schema::FromSchema<S2>>::convert_instance(inst, &self.primitive)
1383            .map_err(|_| Error::UnsupportedPrimitive)
1384    }
1385    fn port_map(&self) -> &HashMap<ArcStr, Vec<Node>> {
1386        &self.port_map
1387    }
1388}
1389
1390impl<S1: FromSchema<S2> + ?Sized, S2: Schema + ?Sized> ConvertPrimitive<S1>
1391    for ConvertedPrimitive<S2>
1392{
1393    // TODO: Improve error handling
1394    fn convert_primitive(&self) -> Result<<S1 as Schema>::Primitive> {
1395        <S1 as scir::schema::FromSchema<S2>>::convert_primitive(self.original.convert_primitive()?)
1396            .map_err(|_| Error::UnsupportedPrimitive)
1397    }
1398    fn convert_instance(&self, inst: &mut scir::Instance) -> Result<()> {
1399        self.original.convert_instance(inst)?;
1400        <S1 as scir::schema::FromSchema<S2>>::convert_instance(inst, &self.converted)
1401            .map_err(|_| Error::UnsupportedPrimitive)
1402    }
1403    fn port_map(&self) -> &HashMap<ArcStr, Vec<Node>> {
1404        self.original.port_map()
1405    }
1406}
1407
1408/// A binding to a schema primitive that can be used to define
1409/// a Substrate schematic.
1410pub struct PrimitiveBinding<S: Schema + ?Sized> {
1411    pub(crate) primitive: <S as Schema>::Primitive,
1412    pub(crate) port_map: HashMap<ArcStr, Vec<Node>>,
1413}
1414
1415impl<S: Schema<Primitive = impl std::fmt::Debug> + ?Sized> std::fmt::Debug for PrimitiveBinding<S> {
1416    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1417        let mut builder = f.debug_struct("Primitive");
1418        let _ = builder.field("primitive", &self.primitive);
1419        let _ = builder.field("port_map", &self.port_map);
1420        builder.finish()
1421    }
1422}
1423
1424impl<S: Schema + ?Sized> Clone for PrimitiveBinding<S> {
1425    fn clone(&self) -> Self {
1426        Self {
1427            primitive: self.primitive.clone(),
1428            port_map: self.port_map.clone(),
1429        }
1430    }
1431}
1432
1433impl<S: Schema> PrimitiveBinding<S> {
1434    /// Creates a new [`PrimitiveBinding`] corresponding to the given schema primitive.
1435    pub fn new(primitive: <S as Schema>::Primitive) -> Self {
1436        Self {
1437            primitive,
1438            port_map: Default::default(),
1439        }
1440    }
1441
1442    /// Connects port `port` of the schema primitive to Substrate nodes `s`.
1443    pub fn connect(&mut self, port: impl Into<ArcStr>, s: impl Flatten<Node>) {
1444        self.port_map.insert(port.into(), s.flatten_vec());
1445    }
1446}
1447
1448pub(crate) struct ConvertedPrimitive<S: Schema + ?Sized> {
1449    converted: <S as Schema>::Primitive,
1450    original: Arc<dyn ConvertPrimitive<S>>,
1451}
1452
1453impl<S: Schema<Primitive = impl std::fmt::Debug> + ?Sized> std::fmt::Debug
1454    for ConvertedPrimitive<S>
1455{
1456    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1457        let mut builder = f.debug_struct("ConvertedPrimitive");
1458        let _ = builder.field("converted", &self.converted);
1459        builder.finish()
1460    }
1461}
1462
1463impl<S: Schema + ?Sized> Clone for ConvertedPrimitive<S> {
1464    fn clone(&self) -> Self {
1465        Self {
1466            converted: self.converted.clone(),
1467            original: self.original.clone(),
1468        }
1469    }
1470}
1471
1472impl<S: Schema + ?Sized> ConvertedPrimitive<S> {
1473    pub(crate) fn port_map(&self) -> &HashMap<ArcStr, Vec<Node>> {
1474        self.original.port_map()
1475    }
1476}
1477
1478/// An enumeration of raw cell kinds.
1479///
1480/// Can be used to store data associated with each kind of raw cell.
1481#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize)]
1482#[enumify::enumify(generics_only)]
1483pub(crate) enum RawCellKind<C, S, P, CP> {
1484    Cell(C),
1485    Scir(S),
1486    Primitive(P),
1487    ConvertedPrimitive(CP),
1488}
1489
1490pub(crate) struct RawCellInnerBuilder<S: Schema + ?Sized> {
1491    pub(crate) next_instance_id: InstanceId,
1492    instances: Vec<RawInstanceBuilder<S>>,
1493}
1494
1495impl<S: Schema<Primitive = impl std::fmt::Debug> + ?Sized> std::fmt::Debug
1496    for RawCellInnerBuilder<S>
1497{
1498    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1499        let mut builder = f.debug_struct("RawCellInnerBuilder");
1500        let _ = builder.field("next_instance_id", &self.next_instance_id);
1501        let _ = builder.field("instances", &self.instances);
1502        builder.finish()
1503    }
1504}
1505
1506impl<S: Schema + ?Sized> Default for RawCellInnerBuilder<S> {
1507    fn default() -> Self {
1508        Self {
1509            next_instance_id: Default::default(),
1510            instances: Default::default(),
1511        }
1512    }
1513}
1514
1515impl<S: Schema + ?Sized> RawCellInnerBuilder<S> {
1516    fn build(self) -> RawCellInner<S> {
1517        RawCellInner {
1518            instances: self
1519                .instances
1520                .into_iter()
1521                .map(|builder| builder.build())
1522                .collect(),
1523        }
1524    }
1525}
1526
1527pub(crate) struct RawCellInner<S: Schema + ?Sized> {
1528    pub(crate) instances: Vec<RawInstance<S>>,
1529}
1530
1531impl<S: Schema<Primitive = impl std::fmt::Debug> + ?Sized> std::fmt::Debug for RawCellInner<S> {
1532    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1533        let mut builder = f.debug_struct("RawCellInner");
1534        let _ = builder.field("instances", &self.instances);
1535        builder.finish()
1536    }
1537}
1538
1539impl<S: Schema + ?Sized> Clone for RawCellInner<S> {
1540    fn clone(&self) -> Self {
1541        Self {
1542            instances: self.instances.clone(),
1543        }
1544    }
1545}
1546
1547impl<S: Schema + ?Sized> RawCellInner<S> {
1548    fn convert_schema<S2: FromSchema<S> + ?Sized>(self) -> Result<RawCellInner<S2>> {
1549        Ok(RawCellInner {
1550            instances: self
1551                .instances
1552                .into_iter()
1553                .map(|instance| instance.convert_schema())
1554                .collect::<Result<_>>()?,
1555        })
1556    }
1557}
1558
1559/// A binding to a cell within a SCIR library that can be used to define a Substrate schematic.
1560pub struct ScirBinding<S: Schema + ?Sized> {
1561    pub(crate) lib: scir::Library<S>,
1562    pub(crate) cell: scir::CellId,
1563    pub(crate) port_map: HashMap<ArcStr, Vec<Node>>,
1564}
1565
1566impl<S: Schema<Primitive = impl Clone> + ?Sized> Clone for ScirBinding<S> {
1567    fn clone(&self) -> Self {
1568        Self {
1569            lib: self.lib.clone(),
1570            cell: self.cell,
1571            port_map: self.port_map.clone(),
1572        }
1573    }
1574}
1575
1576impl<S: Schema<Primitive = impl std::fmt::Debug> + ?Sized> std::fmt::Debug for ScirBinding<S> {
1577    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1578        let mut builder = f.debug_struct("ScirCellInner");
1579        let _ = builder.field("lib", &self.lib);
1580        let _ = builder.field("cell", &self.cell);
1581        builder.finish()
1582    }
1583}
1584
1585impl<S: Schema + ?Sized> ScirBinding<S> {
1586    /// Creates a new [`ScirBinding`] corresponding to the given cell in
1587    /// SCIR library `lib`.
1588    ///
1589    /// # Panics
1590    ///
1591    /// Panics if the provided cell does not exist in the SCIR library.
1592    pub fn new(lib: scir::Library<S>, cell: scir::CellId) -> Self {
1593        assert!(lib.try_cell(cell).is_some());
1594        Self {
1595            lib,
1596            cell,
1597            port_map: HashMap::new(),
1598        }
1599    }
1600
1601    /// Connects port `port` of the SCIR cell to Substrate nodes `s`.
1602    pub fn connect(&mut self, port: impl Into<ArcStr>, s: impl Flatten<Node>) {
1603        self.port_map.insert(port.into(), s.flatten_vec());
1604    }
1605
1606    /// Returns the SCIR cell that this Substrate translation corresponds to.
1607    pub fn cell(&self) -> &scir::Cell {
1608        self.lib.cell(self.cell)
1609    }
1610
1611    /// Returns the ports of the underlying SCIR cell in order.
1612    pub fn ports(&self) -> impl Iterator<Item = &ArcStr> {
1613        let cell = self.cell();
1614        cell.ports().map(|port| &cell.signal(port.signal()).name)
1615    }
1616
1617    fn port_map(&self) -> &HashMap<ArcStr, Vec<Node>> {
1618        &self.port_map
1619    }
1620
1621    /// Converts the underlying SCIR library to schema `S2`.
1622    pub fn convert_schema<S2: FromSchema<S> + ?Sized>(
1623        self,
1624    ) -> substrate::error::Result<ScirBinding<S2>> {
1625        Ok(ScirBinding {
1626            //  TODO: More descriptive error.
1627            lib: self
1628                .lib
1629                .convert_schema::<S2>()
1630                .map_err(|_| Error::UnsupportedPrimitive)?
1631                .build()
1632                .unwrap(),
1633            cell: self.cell,
1634            port_map: self.port_map,
1635        })
1636    }
1637}
1638
1639/// A context-wide unique identifier for a cell.
1640#[derive(Debug, Copy, Clone, Serialize, Deserialize, Hash, PartialEq, Eq)]
1641pub struct CellId(u64);
1642
1643impl CellId {
1644    pub(crate) fn increment(&mut self) {
1645        let next = self.0.checked_add(1).expect("integer overflow");
1646        *self = CellId(next)
1647    }
1648}
1649
1650/// A cell-wide unique identifier for an instance.
1651#[derive(Default, Debug, Copy, Clone, Serialize, Deserialize, Hash, PartialEq, Eq)]
1652pub struct InstanceId(pub(crate) u64);
1653
1654impl InstanceId {
1655    pub(crate) fn increment(&mut self) {
1656        let next = self.0.checked_add(1).expect("integer overflow");
1657        *self = InstanceId(next)
1658    }
1659}