Skip to content

Commit

Permalink
Merge pull request #2 from squadracorsepolito/dev/AttributeAssignment
Browse files Browse the repository at this point in the history
Dev/attribute assignment
  • Loading branch information
FerroO2000 committed May 28, 2024
2 parents 13003d5 + ddfd60f commit 3b3e446
Show file tree
Hide file tree
Showing 33 changed files with 2,120 additions and 789 deletions.
239 changes: 141 additions & 98 deletions attribute.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,84 +6,6 @@ import (
"time"
)

// AttributeValue connects a general [Attribute] to the value associated by an entity.
type AttributeValue struct {
attribute Attribute
value any
}

func newAttributeValue(att Attribute, val any) *AttributeValue {
return &AttributeValue{
attribute: att,
value: val,
}
}

func (av *AttributeValue) stringify(b *strings.Builder, tabs int) {
b.WriteString(fmt.Sprintf("%sname: %s; type: %s; value: %v\n",
getTabString(tabs), av.attribute.Name(), av.attribute.Type(), av.value))
}

// Attribute returns the [Attribute] of the [AttributeValue].
func (av *AttributeValue) Attribute() Attribute {
return av.attribute
}

// Value returns the value of the [AttributeValue].
func (av *AttributeValue) Value() any {
return av.value
}

// AttributeRefKind defines the kind of an [AttributeRef].
type AttributeRefKind string

const (
// AttributeRefKindBus defines a bus reference.
AttributeRefKindBus AttributeRefKind = "attribute_ref-bus"
// AttributeRefKindNode defines a node reference.
AttributeRefKindNode AttributeRefKind = "attribute_ref-node"
// AttributeRefKindMessage defines a message reference.
AttributeRefKindMessage AttributeRefKind = "attribute_ref-message"
// AttributeRefKindSignal defines a signal reference.
AttributeRefKindSignal AttributeRefKind = "attribute_ref-signal"
)

// AttributeRef connects an [Attribute] to an entity and the value
// the latter has associated to the former.
// It is useful to connect an attribute to the entities that are using it.
type AttributeRef struct {
entityID EntityID
kind AttributeRefKind
value any
}

func newAttributeRef(entID EntityID, kind AttributeRefKind, val any) *AttributeRef {
return &AttributeRef{
entityID: entID,
kind: kind,
value: val,
}
}

func (af *AttributeRef) stringify(b *strings.Builder, tabs int) {
b.WriteString(fmt.Sprintf("%skind: %s; entity_id: %s;value: %v\n", getTabString(tabs), af.kind, af.entityID, af.value))
}

// EntityID returns the entity id of the [AttributeRef]
func (af *AttributeRef) EntityID() EntityID {
return af.entityID
}

// Kind returns the kind of the [AttributeRef]
func (af *AttributeRef) Kind() AttributeRefKind {
return af.kind
}

// Value returns the value of the [AttributeRef]
func (af *AttributeRef) Value() any {
return af.value
}

// AttributeType defines the type of an [Attribute].
type AttributeType int

Expand Down Expand Up @@ -117,22 +39,23 @@ func (at AttributeType) String() string {
// [StringAttribute], [IntegerAttribute], [FloatAttribute], and
// [EnumAttribute].
type Attribute interface {
// EntityID returns the entity id of an attribute.
// EntityID returns the entity id of the attribute.
EntityID() EntityID
// Name returns the name of an attribute.
// Name returns the name of the attribute.
Name() string
// Desc returns the description of an attribute.
// Desc returns the description of the attribute.
Desc() string
// CreateTime returns the time of creation of an attribute.
// CreateTime returns the time of creation of the attribute.
CreateTime() time.Time

// Type returns the kind of an attribute.
// Type returns the kind of the attribute.
Type() AttributeType

addReference(ref *AttributeRef)
removeReference(refID EntityID)
// References returns a slice of references of an attribute.
References() []*AttributeRef
addRef(*AttributeAssignment)
removeRef(EntityID)

// References returns a slice of references of the attribute.
References() []*AttributeAssignment

String() string

Expand All @@ -148,15 +71,15 @@ type Attribute interface {

type attribute struct {
*entity
*withRefs[*AttributeRef]
*withRefs[*AttributeAssignment]

typ AttributeType
}

func newAttribute(name string, typ AttributeType) *attribute {
return &attribute{
entity: newEntity(name),
withRefs: newWithRefs[*AttributeRef](),
entity: newEntity(name, EntityKindAttribute),
withRefs: newWithRefs[*AttributeAssignment](),

typ: typ,
}
Expand Down Expand Up @@ -191,14 +114,6 @@ func (a *attribute) Type() AttributeType {
return a.typ
}

func (a *attribute) addReference(ref *AttributeRef) {
a.refs.add(ref.entityID, ref)
}

func (a *attribute) removeReference(refID EntityID) {
a.refs.remove(refID)
}

// StringAttribute is an [Attribute] that holds a string value.
type StringAttribute struct {
*attribute
Expand Down Expand Up @@ -602,3 +517,131 @@ func (ea *EnumAttribute) ToFloat() (*FloatAttribute, error) {
func (ea *EnumAttribute) ToEnum() (*EnumAttribute, error) {
return ea, nil
}

// AttributableEntity represents an entity that can hold attributes.
type AttributableEntity interface {
errorf(err error) error

// EntityID returns the unique identifier of the entity.
EntityID() EntityID
// EntityKind returns the kind of the entity.
EntityKind() EntityKind
// Name returns the name of the entity.
Name() string

// AssignAttribute assigns the given attribute/value pair to the entity.
AssignAttribute(attribute Attribute, value any) error
// RemoveAttributeAssignment removes the attribute assignment
// with the given attribute entity id from the entity.
RemoveAttributeAssignment(attributeEntityID EntityID) error
// RemoveAllAttributeAssignments removes all the attribute assignments from the entity.
RemoveAllAttributeAssignments()
// AttributeAssignments returns a slice of all attribute assignments of the entity.
AttributeAssignments() []*AttributeAssignment
// GetAttributeAssignment returns the attribute assignment
// with the given attribute entity id from the entity.
GetAttributeAssignment(attributeEntityID EntityID) (*AttributeAssignment, error)
}

// AttributeAssignment represents a link between an [Attribute] and an [AttributableEntity]
// with an assigned value.
type AttributeAssignment struct {
attribute Attribute
entity AttributableEntity
value any
}

func newAttributeAssignment(att Attribute, ent AttributableEntity, val any) *AttributeAssignment {
return &AttributeAssignment{
attribute: att,
entity: ent,
value: val,
}
}

func (aa *AttributeAssignment) stringify(b *strings.Builder, tabs int) {
tabStr := getTabString(tabs)

b.WriteString(fmt.Sprintf("%sentity_id: %s; entity_kind: %s; name: %s; value: %v;\n",
tabStr, aa.EntityID(), aa.entity.EntityKind(), aa.entity.Name(), aa.value))
}

// EntityID returns the entity id of the [AttributableEntity] of the [AttributeAssignment].
func (aa *AttributeAssignment) EntityID() EntityID {
return aa.entity.EntityID()
}

// Attribute returns the [Attribute] of the [AttributeAssignment].
func (aa *AttributeAssignment) Attribute() Attribute {
return aa.attribute
}

// Value returns the value of the [AttributeAssignment].
func (aa *AttributeAssignment) Value() any {
return aa.value
}

// Entity returns the [AttributableEntity] of the [AttributeAssignment].
func (aa *AttributeAssignment) Entity() AttributableEntity {
return aa.entity
}

// ToBusEntity returns the [AttributableEntity] as a [Bus].
//
// It returns a [ConversionError] if the kind of the entity is not equal to
// [EntityKindBus].
func (aa *AttributeAssignment) ToBusEntity() (*Bus, error) {
if aa.entity.EntityKind() == EntityKindBus {
return aa.entity.(*Bus), nil
}

return nil, aa.entity.errorf(&ConversionError{
From: aa.entity.EntityKind().String(),
To: EntityKindBus.String(),
})
}

// ToNodeEntity returns the [AttributableEntity] as a [Node].
//
// It returns a [ConversionError] if the kind of the entity is not equal to
// [EntityKindNode].
func (aa *AttributeAssignment) ToNodeEntity() (*Node, error) {
if aa.entity.EntityKind() == EntityKindNode {
return aa.entity.(*Node), nil
}

return nil, aa.entity.errorf(&ConversionError{
From: aa.entity.EntityKind().String(),
To: EntityKindNode.String(),
})
}

// ToMessageEntity returns the [AttributableEntity] as a [Message].
//
// It returns a [ConversionError] if the kind of the entity is not equal to
// [EntityKindMessage].
func (aa *AttributeAssignment) ToMessageEntity() (*Message, error) {
if aa.entity.EntityKind() == EntityKindMessage {
return aa.entity.(*Message), nil
}

return nil, aa.entity.errorf(&ConversionError{
From: aa.entity.EntityKind().String(),
To: EntityKindMessage.String(),
})
}

// ToSignalEntity returns the [AttributableEntity] as a [Signal].
//
// It returns a [ConversionError] if the kind of the entity is not equal to
// [EntityKindSignal].
func (aa *AttributeAssignment) ToSignalEntity() (Signal, error) {
if aa.entity.EntityKind() == EntityKindSignal {
return aa.entity.(Signal), nil
}

return nil, aa.entity.errorf(&ConversionError{
From: aa.entity.EntityKind().String(),
To: EntityKindSignal.String(),
})
}
43 changes: 43 additions & 0 deletions attribute_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,3 +130,46 @@ func Test_EnumAttribute(t *testing.T) {
_, err = enumAtt.ToFloat()
assert.Error(err)
}

func Test_AttributeAssignment(t *testing.T) {
assert := assert.New(t)

att := NewStringAttribute("att", "")

bus := NewBus("bus")
node := NewNode("node", 1, 1)
msg := NewMessage("msg", 1, 1)
sig, err := NewStandardSignal("sig", NewFlagSignalType("flag_type"))
assert.NoError(err)

attValues := []string{"bus_att", "node_att", "msg_att", "sig_att"}
assert.NoError(bus.AssignAttribute(att, attValues[0]))
assert.NoError(node.AssignAttribute(att, attValues[1]))
assert.NoError(msg.AssignAttribute(att, attValues[2]))
assert.NoError(sig.AssignAttribute(att, attValues[3]))

assert.Len(att.References(), 4)
for _, attAss := range att.References() {
switch attAss.entity.EntityKind() {
case EntityKindBus:
assert.Equal(attValues[0], attAss.Value())
_, err := attAss.ToBusEntity()
assert.NoError(err)

case EntityKindNode:
assert.Equal(attValues[1], attAss.Value())
_, err := attAss.ToNodeEntity()
assert.NoError(err)

case EntityKindMessage:
assert.Equal(attValues[2], attAss.Value())
_, err := attAss.ToMessageEntity()
assert.NoError(err)

case EntityKindSignal:
assert.Equal(attValues[3], attAss.Value())
_, err := attAss.ToSignalEntity()
assert.NoError(err)
}
}
}
42 changes: 39 additions & 3 deletions bus.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ func (bt BusType) String() string {
// Bus is the virtual representation of physical CAN bus cable.
// It holds a list of nodes that are connected to it.
type Bus struct {
*attributeEntity
*entity
*withAttributes

parentNetwork *Network

Expand All @@ -45,7 +46,8 @@ type Bus struct {
// By default, the bus is set to be of type CAN 2.0A.
func NewBus(name string) *Bus {
return &Bus{
attributeEntity: newAttributeEntity(name, AttributeRefKindBus),
entity: newEntity(name, EntityKindBus),
withAttributes: newWithAttributes(),

parentNetwork: nil,

Expand All @@ -70,7 +72,7 @@ func (b *Bus) setParentNetwork(net *Network) {

func (b *Bus) errorf(err error) error {
busErr := &EntityError{
Kind: "bus",
Kind: EntityKindBus,
EntityID: b.entityID,
Name: b.name,
Err: err,
Expand Down Expand Up @@ -288,3 +290,37 @@ func (b *Bus) SetType(typ BusType) {
func (b *Bus) Type() BusType {
return b.typ
}

// AssignAttribute assigns the given attribute/value pair to the [Bus].
//
// It returns an [ArgumentError] if the attribute is nil,
// or an [AttributeValueError] if the value does not conform to the attribute.
func (b *Bus) AssignAttribute(attribute Attribute, value any) error {
if err := b.addAttributeAssignment(attribute, b, value); err != nil {
return b.errorf(err)
}
return nil
}

// RemoveAttributeAssignment removes the [AttributeAssignment]
// with the given attribute entity id from the [Bus].
//
// It returns an [ErrNotFound] if the provided attribute entity id is not found.
func (b *Bus) RemoveAttributeAssignment(attributeEntityID EntityID) error {
if err := b.removeAttributeAssignment(attributeEntityID); err != nil {
return b.errorf(err)
}
return nil
}

// GetAttributeAssignment returns the [AttributeAssignment]
// with the given attribute entity id from the [Bus].
//
// It returns an [ErrNotFound] if the provided attribute entity id is not found.
func (b *Bus) GetAttributeAssignment(attributeEntityID EntityID) (*AttributeAssignment, error) {
attAss, err := b.getAttributeAssignment(attributeEntityID)
if err != nil {
return nil, b.errorf(err)
}
return attAss, nil
}
Loading

0 comments on commit 3b3e446

Please sign in to comment.