Skip to content
Snippets Groups Projects
Commit f2d502b4 authored by angloth's avatar angloth
Browse files

Add updated port and signal interface where connecting / disconnecting is done...

Add updated port and signal interface where connecting / disconnecting is done reflectibly between both signal and port, also add some more helper methods.
parent 62a7700c
No related branches found
No related tags found
1 merge request!9Resolve #1 "Port Interface", #8 "Port Coupling"
Pipeline #10257 failed
......@@ -7,14 +7,15 @@ from abc import ABC, abstractmethod
from typing import NewType, Optional, List
from b_asic.operation import Operation
import b_asic.signal as sig # Used due to cyclic imports
from b_asic.signal import Signal
PortId = NewType("PortId", int)
class Port(ABC):
"""Abstract port class.
TODO: More info.
Handles functionality for port id and saves the connection to the parent operation.
"""
_port_id: PortId
......@@ -26,24 +27,24 @@ class Port(ABC):
@property
def id(self) -> PortId:
"""Get the unique portid."""
"""Returns the unique portid."""
return self._port_id
@property
def operation(self) -> Operation:
"""Get the connected operation."""
"""Returns the connected operation."""
return self._operation
@property
@abstractmethod
def signals(self) -> List[sig.Signal]:
"""Get a list of all connected signals."""
def signals(self) -> List[Signal]:
"""Returns a list of all connected signals."""
raise NotImplementedError
@abstractmethod
def signal(self, i: int = 0) -> sig.Signal:
"""Get the connected signal at index i.
def signal(self, i: int = 0) -> Signal:
"""Returns the connected signal at index i.
Keyword argumens:
i: integer index of the signal requsted.
"""
......@@ -52,22 +53,35 @@ class Port(ABC):
@property
@abstractmethod
def connected_ports(self) -> List["Port"]:
"""Get a list of all connected Ports."""
"""Returns a list of all connected Ports."""
raise NotImplementedError
@abstractmethod
def signal_count(self) -> int:
"""Get the number of connected signals."""
"""Returns the number of connected signals."""
raise NotImplementedError
@abstractmethod
def connect_to_port(self, port: "Port") -> Signal:
"""Creates a signal that is connected to this port and the entered
port and connects this port to the signal and the entered port to the signal."""
raise NotImplementedError
@abstractmethod
def connect_to_signal(self, signal: Signal) -> None:
"""Connects this port to the entered signal. If the entered signal isn't connected to
this port then it connects the entered signal to the port aswell."""
raise NotImplementedError
@abstractmethod
def connect(self, port: "Port") -> sig.Signal:
"""Connects a port and returns a signal created between the ports."""
def disconnect_signal(self, i: int = 0) -> None:
"""Disconnect a signal from the port. If the port is still connected to the entered signal
then the port is disconnected from the the entered signal aswell."""
raise NotImplementedError
@abstractmethod
def disconnect(self, i: int = 0) -> None:
"""Disconnect a signal."""
def is_connected_to_signal(self, signal: Signal) -> bool:
"""Returns true if the port is connected to the entered signal else false."""
raise NotImplementedError
......@@ -76,17 +90,17 @@ class InputPort(Port):
TODO: More info.
"""
_signal: Optional[sig.Signal]
_signal: Optional[Signal]
def __init__(self, port_id: PortId, operation: Operation):
super().__init__(port_id, operation)
self._signal = None
@property
def signals(self) -> List[sig.Signal]:
def signals(self) -> List[Signal]:
return [] if self._signal is None else [self._signal]
def signal(self, i: int = 0) -> sig.Signal:
def signal(self, i: int = 0) -> Signal:
assert 0 <= i < self.signal_count(), "Signal index out of bound."
assert self._signal is not None, "No Signal connect to InputPort."
return self._signal
......@@ -98,17 +112,29 @@ class InputPort(Port):
def signal_count(self) -> int:
return 0 if self._signal is None else 1
def connect(self, port: "OutputPort") -> sig.Signal:
# Remove previously connected signal if there is one
if self._signal is not None:
self.disconnect()
self._signal = sig.Signal(port, self)
def connect_to_port(self, port: "OutputPort") -> Signal:
assert self._signal is None, "Connecting new port to already connected input port."
Signal(port, self) # self._signal is set by the signal constructor
return self._signal
def disconnect(self, i: int = 0) -> None:
assert 0 <= i < self.signal_count() # TODO: Error message.
self._signal.disconnect_destination()
def connect_to_signal(self, signal: Signal) -> None:
assert self._signal is None, "Connecting new port to already connected input port."
self._signal = signal
if not signal.port_is_destination(self):
# Connect this inputport as destination for this signal if it isn't already.
signal.connect_destination_port(self)
def disconnect_signal(self, i: int = 0) -> None:
assert 0 <= i < self.signal_count(), "Signal Index out of range."
old_signal: Signal = self._signal
self._signal = None
if old_signal.port_is_destination(self):
# Disconnect the destination of the signal if this inputport currently is the destination
old_signal.disconnect_destination()
old_signal.disconnect_destination()
def is_connected_to_signal(self, signal: Signal) -> bool:
return self._signal is signal
class OutputPort(Port):
......@@ -116,17 +142,17 @@ class OutputPort(Port):
TODO: More info.
"""
_signals: List[sig.Signal]
_signals: List[Signal]
def __init__(self, port_id: PortId, operation: Operation):
super().__init__(port_id, operation)
self._signals = []
@property
def signals(self) -> List[sig.Signal]:
def signals(self) -> List[Signal]:
return self._signals.copy()
def signal(self, i: int = 0) -> sig.Signal:
def signal(self, i: int = 0) -> Signal:
assert 0 <= i < self.signal_count(), "Signal index out of bounds."
return self._signals[i]
......@@ -137,12 +163,36 @@ class OutputPort(Port):
def signal_count(self) -> int:
return len(self._signals)
def connect(self, port: InputPort) -> sig.Signal:
signal = sig.Signal(self, port)
self._signals.append(signal)
def connect_to_port(self, port: InputPort) -> Signal:
signal = Signal(self, port)
port.connect_to_signal(signal) # Signal is added to self._signals in signal constructor
return signal
def disconnect(self, i: int = 0) -> None:
def connect_to_signal(self, signal: Signal) -> None:
assert not self.is_connected_to_signal(signal), "Attempting to connect to Signal already connected."
self._signals.append(signal)
if not signal.is_source(self):
# Connect this outputport to the signal if it isn't already
signal.connect_source_port(self)
def disconnect_signal(self, i: int = 0) -> None:
assert 0 <= i < self.signal_count(), "Signal index out of bounds."
self._signals[i].disconnect_source()
old_signal: Signal = self._signals[i]
del self._signals[i]
if old_signal.port_is_source(self):
# Disconnect the source of the signal if this outputport currently is the source
old_signal.disconnect_source()
def disconnect_signal_by_ref(self, signal: Signal) -> None:
"""Removes the signal that was entered from the OutputPorts signals.
If the entered signal still is connected to this port then disconnects the
entered signal from the port aswell.
Keyword arguments:
- signal: Signal to remove.
"""
i: int = self._signals.index(signal)
self.disconnect_signal(i)
def is_connected_to_signal(self, signal: Signal) -> bool:
return signal in self._signals # O(n) complexity
"""@package docstring
B-ASIC Signal Module.
"""
from typing import Optional
from typing import Optional, TYPE_CHECKING
from b_asic.graph_component import TypeName
from b_asic.abstract_graph_component import AbstractGraphComponent
from b_asic.port import InputPort, OutputPort
if TYPE_CHECKING:
from b_asic.port import InputPort, OutputPort
class Signal(AbstractGraphComponent):
"""A connection between two ports."""
_source: OutputPort
_destination: InputPort
_source: "OutputPort"
_destination: "InputPort"
def __init__(self, src: Optional[InputPort] = None, \
dest: Optional[OutputPort] = None, **kwds):
def __init__(self, source: Optional["InputPort"] = None, \
destination: Optional["OutputPort"] = None, **kwds):
super().__init__(**kwds)
# TODO: Make order of port parameters unimportant
self._source = src # Note: does not connect the source port to the signal.
self._destination = dest # Note: does not connect the destination port to the signal.
if source is not None:
self.connect_source_port(source)
else:
self._source = source
if destination is not None:
self.connect_destination_port(destination)
else:
self._destination = destination
@property
def source(self) -> OutputPort:
def source(self) -> "OutputPort":
"""Returns the source OutputPort of the signal."""
return self._source
@property
def destination(self) -> InputPort:
"""Returns the destination InputPort of the signal."""
def destination(self) -> "InputPort":
"""Returns the destination "InputPort" of the signal."""
return self._destination
def connect_source_port(self, src: "OutputPort") -> None:
"""Disconnects the previous source OutputPort of the signal and
connects to the entered source OutputPort. Also connects the entered
source port to the signal if it hasn't already been connected.
Keyword arguments:
- src: OutputPort to connect as source to the signal.
"""
self.disconnect_source()
self._source = src
if not src.is_connected_to_signal(self):
# If the new source isn't connected to this signal then connect it.
src.connect_to_signal(self)
def connect_destination_port(self, dest: "InputPort") -> None:
"""Disconnects the previous destination InputPort of the signal and
connects to the entered destination InputPort. Also connects the entered
destination port to the signal if it hasn't already been connected.
Keywords argments:
- dest: InputPort to connect as destination to the signal.
"""
self.disconnect_destination()
self._destination = dest
if not dest.is_connected_to_signal(self):
# If the new destination isn't connected to tis signal then connect it.
dest.connect_to_signal(self)
@property
def type_name(self) -> TypeName:
return "s"
def disconnect_source(self) -> None:
"""Disconnects the source OutputPort of the signal.
Note: Does not disconnect the source OutputPort from the signal.
"""
self._source = None
"""Disconnects the source OutputPort of the signal. If the source port
still is connected to this signal then also disconnects the source port."""
if self.has_source():
old_source: "OutputPort" = self._source
self._source = None
if old_source.is_connected_to_signal(self):
# If the old destination port still is connected to this signal, then disconnect it.
old_source.disconnect_signal_by_ref(self)
def disconnect_destination(self) -> None:
"""Disconnects the destination InputPort of the signal.
"""Disconnects the destination "InputPort" of the signal."""
if self.has_destination():
old_destination: "InputPort" = self._destination
self._destination = None
if old_destination.is_connected_to_signal(self):
# If the old destination port still is connected to this signal, then disconnect it.
old_destination.disconnect_signal()
Note: Does not disconnect the destination OutputPort from the signal.
"""
self._destination = None
def port_is_source(self, source: "OutputPort") -> bool:
"""Returns true if the entered OutputPort is the source else false."""
return self._source is source
def port_is_destination(self, destination: "InputPort") -> bool:
"""Returns true if the entered OutputPort is the destination else false."""
return self._destination is destination
def is_connected(self) -> bool:
"""Returns true if the signal is connected to both a source and a destination,
else false."""
return self.has_source() and self.has_destination()
def has_source(self) -> bool:
"""Returns true if the signal is connected to a source, else false."""
return self._source is not None
def has_destination(self) -> bool:
"""Returns true if the signal is connected to a destination, else false."""
return self._destination is not None
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment