Skip to content

Commit

Permalink
Merge pull request #29 from hovsep/v.0.1.0
Browse files Browse the repository at this point in the history
V.0.1.0
  • Loading branch information
hovsep authored Sep 11, 2024
2 parents 76d3951 + 9a6074d commit 21f3990
Show file tree
Hide file tree
Showing 9 changed files with 707 additions and 39 deletions.
28 changes: 28 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: Run tests and upload coverage

on:
push

jobs:
test:
name: Run tests and collect coverage
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Set up Go
uses: actions/setup-go@v5

- name: Install dependencies
run: go mod download

- name: Run tests
run: go test -coverprofile=coverage.txt

- name: Upload results to Codecov
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
8 changes: 4 additions & 4 deletions component/component.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,14 @@ func (c *Component) Activate() (aRes hop.ActivationResult) {
}

if !errors.Is(err, ErrWaitingForInputKeepInputs) {
c.Inputs.ClearAll()
c.Inputs.ClearSignal()
}

return
}

//Clear Inputs
c.Inputs.ClearAll()
c.Inputs.ClearSignal()

if err != nil {
aRes = hop.ActivationResult{
Expand All @@ -84,11 +84,11 @@ func (c *Component) Activate() (aRes hop.ActivationResult) {

func (c *Component) FlushOutputs() {
for _, out := range c.Outputs {
if !out.HasSignal() || len(out.Pipes) == 0 {
if !out.HasSignal() || len(out.Pipes()) == 0 {
continue
}

for _, pipe := range out.Pipes {
for _, pipe := range out.Pipes() {
//Multiplexing
pipe.Flush()
}
Expand Down
16 changes: 4 additions & 12 deletions examples/basic.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,8 @@ func main() {
c1 := &component.Component{
Name: "adder",
Description: "adds 2 to the input",
Inputs: port.Ports{
"num": &port.Port{},
},
Outputs: port.Ports{
"res": &port.Port{},
},
Inputs: port.NewPorts("num"),
Outputs: port.NewPorts("res"),
ActivationFunc: func(inputs port.Ports, outputs port.Ports) error {
num := inputs.ByName("num").Signal().Payload().(int)
outputs.ByName("res").PutSignal(signal.New(num + 2))
Expand All @@ -32,12 +28,8 @@ func main() {
c2 := &component.Component{
Name: "multiplier",
Description: "multiplies by 3",
Inputs: port.Ports{
"num": &port.Port{},
},
Outputs: port.Ports{
"res": &port.Port{},
},
Inputs: port.NewPorts("num"),
Outputs: port.NewPorts("res"),
ActivationFunc: func(inputs port.Ports, outputs port.Ports) error {
num := inputs.ByName("num").Signal().Payload().(int)
outputs.ByName("res").PutSignal(signal.New(num * 3))
Expand Down
11 changes: 11 additions & 0 deletions port/pipe.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,23 @@
package port

// Pipe is the connection between two ports
type Pipe struct {
From *Port
To *Port
}

// Pipes is a useful collection type
type Pipes []*Pipe

// NewPipe returns new pipe
func NewPipe(from *Port, to *Port) *Pipe {
return &Pipe{
From: from,
To: to,
}
}

// Flush makes the signals flow from "From" to "To" port (From is not cleared)
func (p *Pipe) Flush() {
ForwardSignal(p.From, p.To)
}
77 changes: 77 additions & 0 deletions port/pipe_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package port

import (
"github.com/hovsep/fmesh/signal"
"reflect"
"testing"
)

func TestNewPipe(t *testing.T) {
p1, p2 := NewPort(), NewPort()

type args struct {
from *Port
to *Port
}
tests := []struct {
name string
args args
want *Pipe
}{
{
name: "happy path",
args: args{
from: p1,
to: p2,
},
want: &Pipe{
From: p1,
To: p2,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := NewPipe(tt.args.from, tt.args.to); !reflect.DeepEqual(got, tt.want) {
t.Errorf("NewPipe() = %v, want %v", got, tt.want)
}
})
}
}

func TestPipe_Flush(t *testing.T) {
portWithSignal := NewPort()
portWithSignal.PutSignal(signal.New(777))

portWithMultipleSignals := NewPort()
portWithMultipleSignals.PutSignal(signal.New(11, 12))

emptyPort := NewPort()

tests := []struct {
name string
before *Pipe
after *Pipe
}{
{
name: "flush to empty port",
before: NewPipe(portWithSignal, emptyPort),
after: NewPipe(portWithSignal, portWithSignal),
},
{
name: "flush to port with signal",
before: NewPipe(portWithSignal, portWithMultipleSignals),
after: NewPipe(portWithSignal, &Port{
signal: signal.New(777, 11, 12),
}),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.before.Flush()
if !reflect.DeepEqual(tt.before, tt.after) {
t.Errorf("Flush() = %v, want %v", tt.before, tt.after)
}
})
}
}
61 changes: 44 additions & 17 deletions port/port.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,57 +4,79 @@ import (
"github.com/hovsep/fmesh/signal"
)

// Port defines a connectivity point of a component
type Port struct {
signal *signal.Signal
Pipes Pipes //Refs to Pipes connected to that port (no in\out semantics)
signal *signal.Signal //Current signal set on the port
pipes Pipes //Refs to pipes connected to this port (without in\out semantics)
}

// Ports is just useful collection type
type Ports map[string]*Port

// NewPort creates a new port
func NewPort() *Port {
return &Port{}
}

// NewPorts creates a new port with the given name
func NewPorts(names ...string) Ports {
ports := make(Ports, len(names))
for _, name := range names {
ports[name] = NewPort()
}
return ports
}

func (p *Port) Pipes() Pipes {
return p.pipes
}

// Signal returns current signal set on the port
func (p *Port) Signal() *signal.Signal {
return p.signal
}

// PutSignal adds a signal to current signal
func (p *Port) PutSignal(sig *signal.Signal) {
p.signal = sig.Merge(p.Signal())
p.signal = sig.Combine(p.Signal())
}

// ClearSignal removes current signal from the port
// @TODO: check if this affects the signal itself, as it is a pointer
func (p *Port) ClearSignal() {
p.signal = nil
}

// HasSignal says whether port signal is set or not
func (p *Port) HasSignal() bool {
return p.signal != nil
}

// Adds pipe reference to port, so all Pipes of the port are easily iterable (no in\out semantics)
// Adds pipe reference to the port, so all pipes of the port are easily accessible
func (p *Port) addPipeRef(pipe *Pipe) {
p.Pipes = append(p.Pipes, pipe)
if pipe.From == nil || pipe.To == nil {
return
}
p.pipes = append(p.pipes, pipe)
}

// PipeTo creates multiple pipes to other ports
// PipeTo creates one or multiple pipes to other port(s)
func (p *Port) PipeTo(toPorts ...*Port) {
for _, toPort := range toPorts {
newPipe := &Pipe{
From: p,
To: toPort,
}
newPipe := NewPipe(p, toPort)
p.addPipeRef(newPipe)
toPort.addPipeRef(newPipe)
}

}

// @TODO: this type must have good tooling for working with collection
// like adding new ports, filtering and so on

// @TODO: add error handling (e.g. when port does not exist)
// ByName returns a port by its name
func (ports Ports) ByName(name string) *Port {
return ports[name]
}

// Deprecated, use ByName instead
func (ports Ports) ManyByName(names ...string) Ports {
// ByNames returns multiple ports by their names
func (ports Ports) ByNames(names ...string) Ports {
selectedPorts := make(Ports)

for _, name := range names {
Expand All @@ -66,6 +88,7 @@ func (ports Ports) ManyByName(names ...string) Ports {
return selectedPorts
}

// AnyHasSignal returns true if at least one port in collection has signal
func (ports Ports) AnyHasSignal() bool {
for _, p := range ports {
if p.HasSignal() {
Expand All @@ -76,6 +99,7 @@ func (ports Ports) AnyHasSignal() bool {
return false
}

// AllHaveSignal returns true when all ports in collection have signal
func (ports Ports) AllHaveSignal() bool {
for _, p := range ports {
if !p.HasSignal() {
Expand All @@ -86,18 +110,21 @@ func (ports Ports) AllHaveSignal() bool {
return true
}

// PutSignal puts a signal to all the port in collection
func (ports Ports) PutSignal(sig *signal.Signal) {
for _, p := range ports {
p.PutSignal(sig)
}
}

func (ports Ports) ClearAll() {
// ClearSignal removes signals from all ports in collection
func (ports Ports) ClearSignal() {
for _, p := range ports {
p.ClearSignal()
}
}

// ForwardSignal puts a signal from source port to dest port, without removing it on source port
func ForwardSignal(source *Port, dest *Port) {
dest.PutSignal(source.Signal())
}
Loading

0 comments on commit 21f3990

Please sign in to comment.