wiRedPanda
Logic Circuit Simulator
Loading...
Searching...
No Matches
ConnectionSerializer.cpp
Go to the documentation of this file.
1// Copyright 2015 - 2026, GIBIS-UNIFESP and the wiRedPanda contributors
2// SPDX-License-Identifier: GPL-3.0-or-later
3
5
6#include "App/Core/Common.h"
10#include "App/IO/VersionInfo.h"
12#include "App/Wiring/Port.h"
13
14void ConnectionSerializer::save(const Connection &connection, QDataStream &stream)
15{
16 // Calculate and save port serial IDs deterministically. See Port::makeSerialId().
17 auto calculateSerialId = [](Port *port) -> quint64 {
18 if (!port) return 0;
19
20 GraphicElement *elem = port->graphicElement();
21 if (!elem) return 0;
22
23 return Port::makeSerialId(static_cast<quint64>(elem->id()), port->globalIndex());
24 };
25
26 QMap<QString, QVariant> map;
27 map.insert("startPortId", calculateSerialId(connection.startPort()));
28 map.insert("endPortId", calculateSerialId(connection.endPort()));
29 stream << map;
30}
31
32void ConnectionSerializer::load(Connection &connection, QDataStream &stream, SerializationContext &context)
33{
34 quint64 id1, id2;
35
37 QMap<QString, QVariant> map = Serialization::readBoundedMetadata(stream);
38
39 if (stream.status() != QDataStream::Ok) {
40 throw PANDACEPTION("Stream error reading connection map at offset %1",
41 stream.device()->pos());
42 }
43
44 id1 = map.value("startPortId").toULongLong();
45 id2 = map.value("endPortId").toULongLong();
46 } else {
47 stream >> id1;
48 stream >> id2;
49
50 if (stream.status() != QDataStream::Ok) {
51 throw PANDACEPTION("Stream error reading connection port IDs at offset %1",
52 stream.device()->pos());
53 }
54
55 // For backwards compatibility with old files: if ID not found and oldPtrMap is provided, try the mapping
56 if (!context.portMap.contains(id1) && !context.oldPtrToSerialId.isEmpty()) {
57 quint64 newId = context.oldPtrToSerialId.value(id1, 0);
58 if (newId != 0) {
59 id1 = newId;
60 }
61 }
62
63 if (!context.portMap.contains(id2) && !context.oldPtrToSerialId.isEmpty()) {
64 quint64 newId = context.oldPtrToSerialId.value(id2, 0);
65 if (newId != 0) {
66 id2 = newId;
67 }
68 }
69 }
70
71 if (!context.portMap.contains(id1) || !context.portMap.contains(id2)) {
72 return;
73 }
74
75 auto *port1 = context.portMap.value(id1);
76 auto *port2 = context.portMap.value(id2);
77
78 if (port1 && port2) {
79 // Exactly one of the pair must be the output (wire start) and the other the
80 // input (wire end); which one was saved as startPortId/endPortId doesn't matter.
81 Port *outputCandidate = port1->isOutput() ? port1 : port2->isOutput() ? port2 : nullptr;
82 Port *inputCandidate = port1->isInput() ? port1 : port2->isInput() ? port2 : nullptr;
83
84 if (outputCandidate && inputCandidate && outputCandidate != inputCandidate) {
85 auto *outputPort = dynamic_cast<OutputPort *>(outputCandidate);
86 auto *inputPort = dynamic_cast<InputPort *>(inputCandidate);
87 if (outputPort && inputPort) {
88 connection.setStartPort(outputPort);
89 connection.setEndPort(inputPort);
90 }
91 }
92 }
93
94 connection.updatePosFromPorts();
95}
Common logging utilities, the Pandaception error type, and helper macros.
#define PANDACEPTION(msg,...)
Definition Common.h:98
ConnectionSerializer: reads/writes a Connection to a versioned QDataStream.
Connection: a wire that connects an output port to an input port in the circuit scene.
Abstract base class for all graphical circuit elements.
Port classes: Port (base), InputPort, and OutputPort.
Deserialization/serialization context structs passed through load()/save() call chains.
Circuit and waveform file serialization/deserialization utilities.
Named version predicates for file-format compatibility checks.
static void save(const Connection &connection, QDataStream &stream)
Writes connection's endpoint port serial IDs to stream.
static void load(Connection &connection, QDataStream &stream, SerializationContext &context)
Reads connection's endpoints from stream, resolving ports via context.
A bezier-curve wire connecting an output port to an input port in the scene.
Definition Connection.h:38
OutputPort * startPort() const
Returns the output port this connection originates from.
InputPort * endPort() const
Returns the input port this connection leads to.
void updatePosFromPorts()
Moves the wire endpoints to match the current port positions.
void setEndPort(InputPort *port)
Sets the input port this connection leads to.
void setStartPort(OutputPort *port)
Sets the output port this connection originates from.
Abstract base class for all graphical circuit elements in wiRedPanda.
A port that receives a signal (the destination end of a wire).
Definition Port.h:229
int id() const
Returns the unique integer identifier of this item, or -1 if unassigned.
Definition ItemWithId.h:40
A port that drives a signal (the source end of a wire).
Definition Port.h:261
Abstract base class for circuit element ports (connection endpoints).
Definition Port.h:39
virtual bool isOutput() const =0
Returns true if this is an output port. Pure virtual.
static quint64 makeSerialId(quint64 elementBase, int globalIndex)
Definition Port.cpp:156
virtual bool isInput() const =0
Returns true if this is an input port. Pure virtual.
static QMap< QString, QVariant > readBoundedMetadata(QDataStream &stream)
Reads the file-level metadata QMap<QString,QVariant> from stream without calling QList::reserve() wit...
bool hasConnectionQMap(const QVersionNumber &v)
V4.7: Connection uses QMap-based serialization format.
Definition VersionInfo.h:78
Bundles all per-deserialization state so that load() overrides receive it through one explicit parame...
QVersionNumber version
File-format version read from the stream header.
QHash< quint64, quint64 > oldPtrToSerialId
QHash< quint64, Port * > & portMap
Accumulated port-pointer map built during deserialization.