generated from dogmatiq/template-go
-
Notifications
You must be signed in to change notification settings - Fork 0
/
entity.go
150 lines (122 loc) · 3.55 KB
/
entity.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
package configkit
import (
"context"
"fmt"
"iter"
"reflect"
"slices"
"github.com/dogmatiq/enginekit/message"
)
// Entity is an interface that represents the configuration of a Dogma "entity"
// such as an application or handler.
//
// Each implementation of this interface represents the configuration described
// by a call to the entity's Configure() method.
type Entity interface {
// Identity returns the identity of the entity.
Identity() Identity
// TypeName returns the fully-qualified type name of the entity.
TypeName() string
// MessageNames returns information about the messages used by the entity.
MessageNames() EntityMessages[message.Name]
// AcceptVisitor calls the appropriate method on v for this entity type.
AcceptVisitor(ctx context.Context, v Visitor) error
}
// RichEntity is a specialization of the Entity interface that exposes
// information about the Go types used to implement the Dogma entity.
type RichEntity interface {
Entity
// ReflectType returns the reflect.Type of the Dogma entity.
ReflectType() reflect.Type
// MessageTypes returns information about the messages used by the entity.
MessageTypes() EntityMessages[message.Type]
// AcceptRichVisitor calls the appropriate method on v for this
// configuration type.
AcceptRichVisitor(ctx context.Context, v RichVisitor) error
}
// EntityMessage describes a message used by a Dogma entity.
type EntityMessage struct {
Kind message.Kind
IsProduced, IsConsumed bool
}
// EntityMessages describes the messages used by a Dogma entity.
type EntityMessages[K comparable] map[K]EntityMessage
// IsEqual returns true if m is equal to n.
func (m EntityMessages[K]) IsEqual(n EntityMessages[K]) bool {
if len(m) != len(n) {
return false
}
for k, v := range m {
if x, ok := n[k]; !ok || x != v {
return false
}
}
return true
}
// Produced returns an iterator that yields the messages that are produced by
// the entity.
func (m EntityMessages[K]) Produced(filter ...message.Kind) iter.Seq2[K, message.Kind] {
return func(yield func(K, message.Kind) bool) {
for k, v := range m {
if v.IsProduced {
if len(filter) == 0 || slices.Contains(filter, v.Kind) {
if !yield(k, v.Kind) {
return
}
}
}
}
}
}
// Consumed returns an iterator that yields the messages that are consumed by
// the entity.
func (m EntityMessages[K]) Consumed(filter ...message.Kind) iter.Seq2[K, message.Kind] {
return func(yield func(K, message.Kind) bool) {
for n, m := range m {
if m.IsConsumed {
if len(filter) == 0 || slices.Contains(filter, m.Kind) {
if !yield(n, m.Kind) {
return
}
}
}
}
}
}
// Update updates the message with the given key by calling fn.
//
// If, after calling fn, the [EntityMessage] is neither produced nor consumed,
// it is removed from the map.
func (m EntityMessages[K]) Update(k K, fn func(K, *EntityMessage)) {
em, ok := m[k]
fn(k, &em)
if em.IsConsumed || em.IsProduced {
m[k] = em
} else if ok {
delete(m, k)
}
}
func (m EntityMessages[K]) merge(n EntityMessages[K]) {
for k, em := range n {
x, ok := m[k]
if !ok {
x.Kind = em.Kind
} else if x.Kind != em.Kind {
panic(fmt.Sprintf("message %v has conflicting kinds %s and %s", k, x.Kind, em.Kind))
}
if em.IsProduced {
x.IsProduced = true
}
if em.IsConsumed {
x.IsConsumed = true
}
m[k] = x
}
}
func asMessageNames(types EntityMessages[message.Type]) EntityMessages[message.Name] {
names := make(EntityMessages[message.Name], len(types))
for t, em := range types {
names[t.Name()] = em
}
return names
}