forked from goadesign/goa
-
Notifications
You must be signed in to change notification settings - Fork 0
/
dup.go
97 lines (90 loc) · 2.27 KB
/
dup.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
package expr
import "fmt"
// Dup creates a copy the given data type.
func Dup(d DataType) DataType {
res := newDupper().DupType(d)
if rt, ok := d.(*ResultTypeExpr); ok {
if Root.GeneratedResultType(rt.Identifier) != nil {
*Root.GeneratedTypes = append(*Root.GeneratedTypes, res.(*ResultTypeExpr))
}
}
return res
}
// DupAtt creates a copy of the given attribute.
func DupAtt(att *AttributeExpr) *AttributeExpr {
return newDupper().DupAttribute(att)
}
// dupper implements recursive and cycle safe copy of data types.
type dupper struct {
uts map[string]UserType
ats map[*AttributeExpr]struct{}
}
// newDupper returns a new initialized dupper.
func newDupper() *dupper {
return &dupper{
uts: make(map[string]UserType),
ats: make(map[*AttributeExpr]struct{}),
}
}
// DupAttribute creates a copy of the given attribute.
func (d *dupper) DupAttribute(att *AttributeExpr) *AttributeExpr {
if _, ok := d.ats[att]; ok {
return att
}
var valDup *ValidationExpr
if att.Validation != nil {
valDup = att.Validation.Dup()
}
var metaDup MetaExpr
if att.Meta != nil {
metaDup = att.Meta.Dup()
}
dup := AttributeExpr{
Type: d.DupType(att.Type),
Description: att.Description,
References: att.References,
Bases: att.Bases,
Validation: valDup,
Meta: metaDup,
DefaultValue: att.DefaultValue,
ZeroValue: att.ZeroValue,
DSLFunc: att.DSLFunc,
UserExamples: att.UserExamples,
}
d.ats[&dup] = struct{}{}
return &dup
}
// DupType creates a copy of the given data type.
func (d *dupper) DupType(t DataType) DataType {
if t == Empty {
// Don't dup Empty so that code may check against it.
return t
}
switch actual := t.(type) {
case Primitive:
return t
case *Array:
return &Array{ElemType: d.DupAttribute(actual.ElemType)}
case *Object:
res := &Object{}
for _, nat := range *actual {
res.Set(nat.Name, d.DupAttribute(nat.Attribute))
}
return res
case *Map:
return &Map{
KeyType: d.DupAttribute(actual.KeyType),
ElemType: d.DupAttribute(actual.ElemType),
}
case UserType:
if u, ok := d.uts[actual.ID()]; ok {
return u
}
dp := actual.Dup(nil)
d.uts[actual.ID()] = dp
dupAtt := d.DupAttribute(actual.Attribute())
dp.SetAttribute(dupAtt)
return dp
}
panic("unknown type " + fmt.Sprintf("%T", t))
}