libreda_db/
undo.rs

1// Copyright (c) 2020-2021 Thomas Kramer.
2// SPDX-FileCopyrightText: 2022 Thomas Kramer
3//
4// SPDX-License-Identifier: AGPL-3.0-or-later
5
6//! *Experimental*: Wrapper around netlist, layout and L2N structures that allows undoing of operations.
7//!
8//! This is work in progress.
9//! Missing things are:
10//! * Undoing a operation on the hierarchy does not necessarily restore netlist, layout and l2n information.
11//! * Undoing a netlist operation does not restore l2n information.
12//! * Undoing a layout operation does not restore l2n information.
13//! * Undoing does not restore user-defined properties.
14//!
15//! # Caveat
16//! Undoing removal of some objects does not preserve the ID of the object.
17//! For example if a cell is deleted this can be undone. The restored cell, pins, instances, etc.
18//! will have the same properties but different IDs.
19
20use crate::layout::prelude::{Geometry, SimpleTransform};
21use crate::netlist::direction::Direction;
22use crate::prelude::PropertyValue;
23use crate::traits::*;
24use std::ops::Deref;
25
26/// Undo operations on the netlist.
27pub enum NetlistUndoOp<T: NetlistBase> {
28    /// Undo an operation on the hierarchy.
29    HierarchyOp(HierarchyUndoOp<T>),
30    /// Undo creating a pin.
31    CreatePin(T::PinId),
32    /// Store the old pin name.
33    RenamePin(T::PinId, T::NameType),
34    /// Undo creating a net.
35    CreateNet(T::NetId),
36    /// Store the previous net of the pin.
37    ConnectPin(T::PinId, Option<T::NetId>),
38    /// Store the previous net of the pin instance.
39    ConnectPinInstance(T::PinInstId, Option<T::NetId>),
40    /// Store old name of the net.
41    RenameNet(T::NetId, Option<T::NameType>),
42    // /// Store parent, old name and connected terminals of a net.
43    // RemoveNet(T::CellId, Option<T::NameType>, Vec<TerminalId<T>>)
44}
45
46impl<T: NetlistBase> From<HierarchyUndoOp<T>> for NetlistUndoOp<T> {
47    fn from(op: HierarchyUndoOp<T>) -> Self {
48        Self::HierarchyOp(op)
49    }
50}
51
52/// Undo operation for `LayoutEdit` operations.
53pub enum LayoutUndoOp<T: LayoutBase> {
54    /// Undo an operation on the cell hierarchy.
55    HierarchyOp(HierarchyUndoOp<T>),
56    /// Store previous dbu.
57    SetDbu(T::Coord),
58    /// Store ID of the created layer.
59    CreateLayer(T::LayerId),
60    /// Store previous layer name.
61    SetLayerName(T::LayerId, Option<T::NameType>),
62    /// Store id of created shape.
63    InsertShape(T::ShapeId),
64    /// Store the geometry of the previous shape.
65    RemoveShape {
66        /// Parent cell of the removed shape.
67        parent_cell: T::CellId,
68        /// Layer of the removed shape.
69        layer: T::LayerId,
70        /// Geometry of the removed shape.
71        geometry: Geometry<T::Coord>,
72    },
73    /// Store the old geometry of the shape.
74    ReplaceShape(T::ShapeId, Geometry<T::Coord>),
75    /// Store the old transform.
76    SetTransform(T::CellInstId, SimpleTransform<T::Coord>),
77}
78
79impl<T: LayoutBase> From<HierarchyUndoOp<T>> for LayoutUndoOp<T> {
80    fn from(op: HierarchyUndoOp<T>) -> Self {
81        Self::HierarchyOp(op)
82    }
83}
84
85/// Undo operation for `L2NEdit` operations.
86#[allow(missing_docs)]
87pub enum L2NUndoOp<T: L2NBase> {
88    /// Undo an operation on the cell hierarchy.
89    HierarchyOp(HierarchyUndoOp<T>),
90    /// Undo a netlist operation.
91    NetlistOp(NetlistUndoOp<T>),
92    /// Undo a layout operation.
93    LayoutOp(LayoutUndoOp<T>),
94    /// Undo setting the net of a shape.
95    SetNetOfShape {
96        shape_id: T::ShapeId,
97        previous_net: Option<T::NetId>,
98    },
99    /// Undo setting the pin of a shape.
100    SetPinOfShape {
101        shape_id: T::ShapeId,
102        previous_pin: Option<T::PinId>,
103    },
104}
105
106impl<T: L2NBase> From<HierarchyUndoOp<T>> for L2NUndoOp<T> {
107    fn from(op: HierarchyUndoOp<T>) -> Self {
108        Self::HierarchyOp(op)
109    }
110}
111
112impl<T: L2NBase> From<NetlistUndoOp<T>> for L2NUndoOp<T> {
113    fn from(op: NetlistUndoOp<T>) -> Self {
114        Self::NetlistOp(op)
115    }
116}
117
118impl<T: L2NBase> From<LayoutUndoOp<T>> for L2NUndoOp<T> {
119    fn from(op: LayoutUndoOp<T>) -> Self {
120        Self::LayoutOp(op)
121    }
122}
123
124/// Undo operation for hierarchy operations.
125pub enum HierarchyUndoOp<T: HierarchyBase> {
126    /// Undo creating a cell.
127    CreateCell(T::CellId),
128    /// Undo creating a cell instance.
129    CreateCellInstance(T::CellInstId),
130    /// Holds the previous name of the cell.
131    RenameCell {
132        /// The renamed cell.
133        cell: T::CellId,
134        /// The name to be restored when undoing.
135        previous_name: T::NameType,
136    },
137    /// Holds the previous name of the cell instance.
138    RenameCellInst {
139        /// The renamed instance.
140        inst: T::CellInstId,
141        /// The name to be restored when undoing.
142        previous_name: Option<T::NameType>,
143    },
144}
145
146/// Wrapper around netlist, layout and L2N structures that allows undoing of operations.
147///
148/// # Types
149/// * `T`: Underlying data structure.
150/// * `U`: Undo-operation.
151pub struct Undo<'a, T, U> {
152    /// Underlying data structure.
153    chip: &'a mut T,
154    /// A list of performed transactions.
155    /// To undo operations, this list has to be worked through from the end.
156    transactions: Vec<U>,
157}
158
159impl<'a, T, U> Undo<'a, T, U> {
160    /// Return the number of undoable transactions.
161    pub fn num_transactions(&self) -> usize {
162        self.transactions.len()
163    }
164
165    /// Clear the undo buffer and make changes permanent.
166    pub fn flush(&mut self) {
167        self.transactions.clear()
168    }
169}
170
171impl<'a, T, U> Deref for Undo<'a, T, U> {
172    type Target = T;
173
174    fn deref(&self) -> &Self::Target {
175        self.chip
176    }
177}
178
179impl<'a, T: HierarchyEdit, U> Undo<'a, T, U> {
180    /// Undo a hierarchy operation.
181    fn undo_hierarchy_op(&mut self, op: HierarchyUndoOp<T>) {
182        match op {
183            HierarchyUndoOp::CreateCell(c) => self.chip.remove_cell(&c),
184            HierarchyUndoOp::CreateCellInstance(c) => self.chip.remove_cell_instance(&c),
185            HierarchyUndoOp::RenameCell {
186                cell,
187                previous_name,
188            } => self.chip.rename_cell(&cell, previous_name),
189            HierarchyUndoOp::RenameCellInst {
190                inst,
191                previous_name,
192            } => self.chip.rename_cell_instance(&inst, previous_name),
193        }
194    }
195}
196
197impl<'a, T: L2NEdit, U> Undo<'a, T, U> {
198    /// Undo an operation on fused netlist and layout.
199    fn undo_l2n_op(&mut self, op: L2NUndoOp<T>) {
200        match op {
201            // Redirect to base traits.
202            L2NUndoOp::HierarchyOp(op) => self.undo_hierarchy_op(op),
203            L2NUndoOp::NetlistOp(op) => self.undo_netlist_op(op),
204            L2NUndoOp::LayoutOp(op) => self.undo_layout_op(op),
205            // L2N specific operations
206            L2NUndoOp::SetNetOfShape {
207                shape_id,
208                previous_net,
209            } => {
210                self.chip.set_net_of_shape(&shape_id, previous_net);
211            }
212            L2NUndoOp::SetPinOfShape {
213                shape_id,
214                previous_pin,
215            } => {
216                self.chip.set_pin_of_shape(&shape_id, previous_pin);
217            }
218        }
219    }
220}
221
222impl<'a, T: L2NEdit> Undo<'a, T, L2NUndoOp<T>> {
223    /// Create a wrapper around a fused layout and netlist which
224    /// allows to undo operations.
225    pub fn new_l2n_undo(chip: &'a mut T) -> Self {
226        Self {
227            chip,
228            transactions: vec![],
229        }
230    }
231
232    /// Undo the latest transaction.
233    /// Does nothing if there's no transaction left to be undone.
234    pub fn undo(&mut self) {
235        if let Some(op) = self.transactions.pop() {
236            self.undo_l2n_op(op)
237        }
238    }
239}
240
241impl<'a, T: LayoutEdit, U> Undo<'a, T, U> {
242    /// Undo a layout operation
243    fn undo_layout_op(&mut self, op: LayoutUndoOp<T>) {
244        match op {
245            LayoutUndoOp::HierarchyOp(op) => self.undo_hierarchy_op(op),
246            LayoutUndoOp::SetDbu(dbu) => self.chip.set_dbu(dbu),
247            LayoutUndoOp::CreateLayer(_id) => {
248                // TODO
249                log::error!("Creating a layer cannot be undone.");
250            }
251            LayoutUndoOp::SetLayerName(id, old_name) => {
252                self.chip.set_layer_name(&id, old_name);
253            }
254            LayoutUndoOp::InsertShape(id) => {
255                self.chip.remove_shape(&id);
256            }
257            LayoutUndoOp::RemoveShape {
258                parent_cell,
259                layer,
260                geometry,
261            } => {
262                self.chip.insert_shape(&parent_cell, &layer, geometry);
263            }
264            LayoutUndoOp::ReplaceShape(id, geometry) => {
265                self.chip.replace_shape(&id, geometry);
266            }
267            LayoutUndoOp::SetTransform(inst, old_tf) => self.chip.set_transform(&inst, old_tf),
268        }
269    }
270}
271
272impl<'a, T: LayoutEdit> Undo<'a, T, LayoutUndoOp<T>> {
273    /// Create a wrapper which allows to undo operations performed
274    /// on the `LayoutEdit` trait.
275    pub fn new_layout_undo(chip: &'a mut T) -> Self {
276        Self {
277            chip,
278            transactions: vec![],
279        }
280    }
281
282    /// Undo the latest transaction.
283    /// Does nothing if there's no transaction left to be undone.
284    pub fn undo(&mut self) {
285        if let Some(op) = self.transactions.pop() {
286            self.undo_layout_op(op)
287        }
288    }
289}
290
291impl<'a, T: NetlistEdit, U> Undo<'a, T, U> {
292    /// Undo a netlist operation.
293    fn undo_netlist_op(&mut self, op: NetlistUndoOp<T>) {
294        match op {
295            NetlistUndoOp::HierarchyOp(op) => self.undo_hierarchy_op(op),
296            NetlistUndoOp::CreatePin(p) => self.chip.remove_pin(&p),
297            NetlistUndoOp::RenamePin(p, n) => {
298                self.chip.rename_pin(&p, n);
299            }
300            NetlistUndoOp::CreateNet(n) => self.chip.remove_net(&n),
301            NetlistUndoOp::ConnectPin(p, n) => {
302                self.chip.connect_pin(&p, n);
303            }
304            NetlistUndoOp::ConnectPinInstance(p, n) => {
305                self.chip.connect_pin_instance(&p, n);
306            }
307            NetlistUndoOp::RenameNet(net, name) => {
308                self.chip.rename_net(&net, name);
309            }
310        }
311    }
312}
313
314impl<'a, T: NetlistEdit> Undo<'a, T, NetlistUndoOp<T>> {
315    /// Create a wrapper which allows to undo operations performed
316    /// on the `NetlistEdit` trait.
317    pub fn new_netlist_undo(chip: &'a mut T) -> Self {
318        Self {
319            chip,
320            transactions: vec![],
321        }
322    }
323
324    /// Undo the latest transaction.
325    /// Does nothing if there's no transaction left to be undone.
326    pub fn undo(&mut self) {
327        if let Some(op) = self.transactions.pop() {
328            self.undo_netlist_op(op)
329        }
330    }
331}
332
333impl<'a, T: HierarchyEdit> Undo<'a, T, HierarchyUndoOp<T>> {
334    /// Create a wrapper which allows to undo operations performed
335    /// on the `HierarchyEdit` trait.
336    pub fn new_hierarchy_undo(chip: &'a mut T) -> Self {
337        Self {
338            chip,
339            transactions: vec![],
340        }
341    }
342
343    /// Undo the latest transaction.
344    /// Does nothing if there's no transaction left to be undone.
345    pub fn undo(&mut self) {
346        if let Some(op) = self.transactions.pop() {
347            self.undo_hierarchy_op(op)
348        }
349    }
350
351    /// Undoes all transactions.
352    pub fn undo_all(&mut self) {
353        while !self.transactions.is_empty() {
354            self.undo();
355        }
356    }
357}
358
359// Inherit everything from HierarchyBase/NetlistBase/LayoutBase/L2NBase.
360#[portrait::fill(portrait::delegate(N))]
361impl<'a, N, U> HierarchyIds for Undo<'a, N, U> where N: HierarchyIds {}
362
363#[portrait::fill(portrait::delegate(N; self.chip))]
364impl<'b, N, U> HierarchyBase for Undo<'b, N, U> where N: HierarchyBase {}
365
366#[portrait::fill(portrait::delegate(N))]
367impl<'b, N, U> NetlistIds for Undo<'b, N, U> where N: NetlistIds {}
368
369#[portrait::fill(portrait::delegate(N; self.chip))]
370impl<'b, N, U> NetlistBase for Undo<'b, N, U> where N: NetlistBase {}
371
372#[portrait::fill(portrait::delegate(N))]
373impl<'b, N, U> LayoutIds for Undo<'b, N, U> where N: LayoutIds {}
374
375#[portrait::fill(portrait::delegate(N; self.chip))]
376impl<'b, N, U> LayoutBase for Undo<'b, N, U> where N: LayoutBase {}
377
378#[portrait::fill(portrait::delegate(N; self.chip))]
379impl<'b, N, U> L2NBase for Undo<'b, N, U> where N: L2NBase {}
380
381impl<'a, T: HierarchyEdit + 'static, U: From<HierarchyUndoOp<T>>> HierarchyEdit for Undo<'a, T, U> {
382    fn create_cell(&mut self, name: Self::NameType) -> Self::CellId {
383        let id = self.chip.create_cell(name);
384        self.transactions
385            .push(HierarchyUndoOp::CreateCell(id.clone()).into());
386        id
387    }
388
389    fn remove_cell(&mut self, _cell_id: &Self::CellId) {
390        unimplemented!()
391    }
392
393    fn create_cell_instance(
394        &mut self,
395        parent_cell: &Self::CellId,
396        template_cell: &Self::CellId,
397        name: Option<Self::NameType>,
398    ) -> Self::CellInstId {
399        let id = self
400            .chip
401            .create_cell_instance(parent_cell, template_cell, name);
402        self.transactions
403            .push(HierarchyUndoOp::CreateCellInstance(id.clone()).into());
404        id
405    }
406
407    fn remove_cell_instance(&mut self, _inst: &Self::CellInstId) {
408        unimplemented!()
409    }
410
411    fn rename_cell_instance(&mut self, inst: &Self::CellInstId, new_name: Option<Self::NameType>) {
412        let previous_name = self.cell_instance_name(inst);
413        self.chip.rename_cell_instance(inst, new_name);
414        self.transactions.push(
415            HierarchyUndoOp::RenameCellInst {
416                inst: inst.clone(),
417                previous_name,
418            }
419            .into(),
420        );
421    }
422
423    fn rename_cell(&mut self, cell: &Self::CellId, new_name: Self::NameType) {
424        let previous_name = self.cell_name(cell);
425        self.chip.rename_cell(cell, new_name);
426        self.transactions.push(
427            HierarchyUndoOp::RenameCell {
428                cell: cell.clone(),
429                previous_name,
430            }
431            .into(),
432        );
433    }
434}
435
436impl<'a, T, U> NetlistEdit for Undo<'a, T, U>
437where
438    T: NetlistEdit + 'static,
439    U: From<NetlistUndoOp<T>> + From<HierarchyUndoOp<T>>,
440{
441    fn create_pin(
442        &mut self,
443        circuit: &Self::CellId,
444        name: Self::NameType,
445        direction: Direction,
446    ) -> Self::PinId {
447        let id = self.chip.create_pin(circuit, name, direction);
448        self.transactions
449            .push(NetlistUndoOp::CreatePin(id.clone()).into());
450        id
451    }
452
453    fn remove_pin(&mut self, _id: &Self::PinId) {
454        unimplemented!("Removing a pin is not implemented to be undoable.")
455    }
456
457    fn rename_pin(&mut self, pin: &Self::PinId, new_name: Self::NameType) -> Self::NameType {
458        let prev_name = self.chip.pin_name(pin);
459        self.transactions
460            .push(NetlistUndoOp::RenamePin(pin.clone(), prev_name).into());
461        self.chip.rename_pin(pin, new_name)
462    }
463
464    fn create_net(&mut self, parent: &Self::CellId, name: Option<Self::NameType>) -> Self::NetId {
465        let id = self.chip.create_net(parent, name);
466        self.transactions
467            .push(NetlistUndoOp::CreateNet(id.clone()).into());
468        id
469    }
470
471    fn rename_net(
472        &mut self,
473        net_id: &Self::NetId,
474        new_name: Option<Self::NameType>,
475    ) -> Option<Self::NameType> {
476        let old_name = self.chip.rename_net(net_id, new_name);
477        self.transactions
478            .push(NetlistUndoOp::RenameNet(net_id.clone(), old_name.clone()).into());
479        old_name
480    }
481
482    fn remove_net(&mut self, _net: &Self::NetId) {
483        // let old_name = self.net_name(net);
484        // let old_terminals = self.each_terminal_of_net_vec(net);
485        // self.transactions.push(NetlistUndoOp::RemoveNet(old_name, old_terminals).into());
486        // self.chip.remove_net(net);
487        unimplemented!("Removing a net is not implemented to be undoable.")
488    }
489
490    fn connect_pin(&mut self, pin: &Self::PinId, net: Option<Self::NetId>) -> Option<Self::NetId> {
491        let prev_net = self.chip.connect_pin(pin, net);
492        self.transactions
493            .push(NetlistUndoOp::ConnectPin(pin.clone(), prev_net.clone()).into());
494        prev_net
495    }
496
497    fn connect_pin_instance(
498        &mut self,
499        pin: &Self::PinInstId,
500        net: Option<Self::NetId>,
501    ) -> Option<Self::NetId> {
502        let prev_net = self.chip.connect_pin_instance(pin, net);
503        self.transactions
504            .push(NetlistUndoOp::ConnectPinInstance(pin.clone(), prev_net.clone()).into());
505        prev_net
506    }
507}
508
509impl<'a, T, U> LayoutEdit for Undo<'a, T, U>
510where
511    T: LayoutEdit + 'static,
512    U: From<LayoutUndoOp<T>> + From<HierarchyUndoOp<T>>,
513{
514    fn set_dbu(&mut self, dbu: Self::Coord) {
515        self.transactions
516            .push(LayoutUndoOp::SetDbu(self.dbu()).into());
517        self.chip.set_dbu(dbu)
518    }
519
520    fn create_layer(&mut self, index: u32, datatype: u32) -> Self::LayerId {
521        let id = self.chip.create_layer(index, datatype);
522        self.transactions
523            .push(LayoutUndoOp::CreateLayer(id.clone()).into());
524        id
525    }
526
527    fn create_layer_with_id(
528        &mut self,
529        layer_id: Self::LayerId,
530        index: u32,
531        datatype: u32,
532    ) -> Result<(), ()> {
533        self.chip
534            .create_layer_with_id(layer_id.clone(), index, datatype)?;
535        self.transactions
536            .push(LayoutUndoOp::CreateLayer(layer_id).into());
537        Ok(())
538    }
539
540    fn set_layer_name(
541        &mut self,
542        layer: &Self::LayerId,
543        name: Option<Self::NameType>,
544    ) -> Option<Self::NameType> {
545        let old_name = self.layer_info(layer).name;
546        self.transactions
547            .push(LayoutUndoOp::SetLayerName(layer.clone(), old_name).into());
548        self.chip.set_layer_name(layer, name)
549    }
550
551    fn insert_shape(
552        &mut self,
553        parent_cell: &T::CellId,
554        layer: &T::LayerId,
555        geometry: Geometry<Self::Coord>,
556    ) -> Self::ShapeId {
557        let id = self.chip.insert_shape(parent_cell, layer, geometry);
558        self.transactions
559            .push(LayoutUndoOp::InsertShape(id.clone()).into());
560        id
561    }
562
563    fn remove_shape(&mut self, shape_id: &Self::ShapeId) -> Option<Geometry<Self::Coord>> {
564        let geometry = self.chip.remove_shape(shape_id);
565        let (parent_cell, layer) = self.parent_of_shape(shape_id);
566        if let Some(geometry) = &geometry {
567            self.transactions.push(
568                LayoutUndoOp::RemoveShape {
569                    parent_cell,
570                    layer,
571                    geometry: geometry.clone(),
572                }
573                .into(),
574            );
575        }
576        geometry
577    }
578
579    fn replace_shape(
580        &mut self,
581        shape_id: &Self::ShapeId,
582        geometry: Geometry<Self::Coord>,
583    ) -> Geometry<Self::Coord> {
584        let old_geometry = self.chip.replace_shape(shape_id, geometry);
585
586        self.transactions
587            .push(LayoutUndoOp::ReplaceShape(shape_id.clone(), old_geometry.clone()).into());
588
589        old_geometry
590    }
591
592    fn set_transform(&mut self, cell_inst: &Self::CellInstId, tf: SimpleTransform<Self::Coord>) {
593        let old_transform = self.get_transform(cell_inst);
594        self.transactions
595            .push(LayoutUndoOp::SetTransform(cell_inst.clone(), old_transform).into());
596        self.chip.set_transform(cell_inst, tf)
597    }
598
599    fn set_shape_property(
600        &mut self,
601        shape: &Self::ShapeId,
602        key: Self::NameType,
603        _value: PropertyValue,
604    ) {
605        let _old_property = self.get_shape_property(shape, &key);
606        unimplemented!("set_shape_property() is currently not undoable.")
607    }
608}
609
610impl<'a, T, U> L2NEdit for Undo<'a, T, U>
611where
612    T: L2NEdit + 'static,
613    U: From<L2NUndoOp<T>>
614        + From<LayoutUndoOp<T>>
615        + From<NetlistUndoOp<T>>
616        + From<HierarchyUndoOp<T>>,
617{
618    fn set_pin_of_shape(
619        &mut self,
620        shape_id: &Self::ShapeId,
621        pin: Option<Self::PinId>,
622    ) -> Option<Self::PinId> {
623        let previous_pin = self.get_pin_of_shape(shape_id);
624        self.transactions.push(
625            L2NUndoOp::SetPinOfShape {
626                shape_id: shape_id.clone(),
627                previous_pin,
628            }
629            .into(),
630        );
631        self.chip.set_pin_of_shape(shape_id, pin)
632    }
633
634    fn set_net_of_shape(
635        &mut self,
636        shape_id: &Self::ShapeId,
637        net: Option<Self::NetId>,
638    ) -> Option<Self::NetId> {
639        let previous_net = self.get_net_of_shape(shape_id);
640        self.transactions.push(
641            L2NUndoOp::SetNetOfShape {
642                shape_id: shape_id.clone(),
643                previous_net,
644            }
645            .into(),
646        );
647        self.chip.set_net_of_shape(shape_id, net)
648    }
649}
650
651#[test]
652fn test_hierarchy_undoing() {
653    use crate::chip::Chip;
654    let mut chip = Chip::new();
655    let mut undo = Undo::new_netlist_undo(&mut chip);
656
657    let top = undo.create_cell("TOP".into());
658    let _top_a = undo.create_pin(&top, "A".into(), Direction::Input);
659    let sub = undo.create_cell("SUB".into());
660    let _sub_b = undo.create_pin(&sub, "B".into(), Direction::Input);
661    let inst = undo.create_cell_instance(&top, &sub, Some("inst1".into()));
662
663    // Test undo renaming.
664    undo.rename_cell(&top, "NewName".into());
665    undo.rename_cell_instance(&inst, None);
666    undo.undo();
667    undo.undo();
668    assert!(undo.cell_by_name("TOP").is_some());
669    assert!(undo.cell_instance_by_name(&top, "inst1").is_some());
670
671    // Undo create_cell_instance.
672    assert_eq!(undo.num_child_instances(&top), 1);
673    undo.undo();
674    assert_eq!(undo.num_child_instances(&top), 0);
675
676    assert_eq!(undo.num_cells(), 2);
677    // Undo create pins and cells.
678    undo.undo();
679    undo.undo();
680    undo.undo();
681    undo.undo();
682    assert_eq!(undo.num_cells(), 0);
683}