main 602baa7

values.go RawHistoryFolder

1package main
2
3import (
4	"fmt"
5	"sort"
6	"strings"
7)
8
9type ValueField struct {
10	Field Field
11	Bit   string
12	Value int64
13}
14type ValueList struct {
15	Mask   Field
16	Fields []ValueField
17}
18
19func resolveValues(m *Module, req *Node, name string) (*ValueList, error) {
20	var sw *Node
21	for _, n := range req.Children {
22		if n.Kind == "switch" {
23			if sw != nil {
24				return nil, n.fail("multiple value switches are unsupported")
25			}
26			sw = n
27		}
28	}
29	if sw == nil {
30		return nil, nil
31	}
32	if len(sw.Children) < 2 || sw.Children[0].Kind != "fieldref" {
33		return nil, sw.fail("value switch requires a mask fieldref and bitcases")
34	}
35	var mask *Node
36	seenSwitch := false
37	for _, n := range req.Children {
38		if n == sw {
39			seenSwitch = true
40			continue
41		}
42		if seenSwitch && n.Kind != "doc" && n.Kind != "reply" {
43			return nil, n.fail("value switch must be trailing")
44		}
45		if n.Kind == "list" {
46			return nil, n.fail("lists combined with value switches are unsupported")
47		}
48		if !seenSwitch && n.Kind == "field" && n.Attr["name"] == sw.Children[0].Text {
49			mask = n
50		}
51	}
52	if mask == nil || mask.Attr["mask"] == "" {
53		return nil, sw.fail("value switch requires a preceding typed mask")
54	}
55	mt, err := lookup(m, mask.Attr["type"])
56	if err != nil {
57		return nil, mask.fail("%v", err)
58	}
59	e, owner := findEnum(m, mask.Attr["mask"])
60	if e == nil {
61		return nil, mask.fail("unknown mask %s", mask.Attr["mask"])
62	}
63	if mt.Size > 4 || !isScalar(mt) {
64		return nil, mask.fail("value mask must fit in 32 bits")
65	}
66	v := &ValueList{Mask: Field{Node: mask, GoType: qualified(m, owner, e.Name)}}
67	used := map[int64]bool{}
68	names := map[string]bool{"Mask": true}
69	for _, bc := range sw.Children[1:] {
70		var members []*Node
71		for _, c := range bc.Children {
72			if c.Kind != "doc" {
73				members = append(members, c)
74			}
75		}
76		if bc.Kind != "bitcase" || len(members) != 2 || members[0].Kind != "enumref" || members[1].Kind != "field" {
77			return nil, bc.fail("value switch requires one enumref and one 4-byte field per bitcase")
78		}
79		bit, n := members[0], members[1]
80		be, bo := findEnum(m, bit.Attr["ref"])
81		if be != e || bo != owner {
82			return nil, bit.fail("bitcase enum must match value mask")
83		}
84		var value int64
85		found := false
86		for _, item := range e.Items {
87			if item.Name == e.Name+goName(bit.Text) {
88				value = item.Value
89				found = true
90			}
91		}
92		if !found || value <= 0 || value&(value-1) != 0 || uint64(value) >= uint64(1)<<(8*mt.Size) || used[value] {
93			return nil, bit.fail("bitcase requires a unique mask bit")
94		}
95		used[value] = true
96		typ, err := lookup(m, n.Attr["type"])
97		if err != nil {
98			return nil, n.fail("%v", err)
99		}
100		if typ.Size != 4 || !isScalar(typ) {
101			return nil, n.fail("value-list bitcase requires a 4-byte scalar field")
102		}
103		f := Field{Name: goName(n.Attr["name"]), GoType: qualified(m, typ.Module, typ.GoType), Type: typ, Node: n}
104		for _, attr := range []string{"enum", "mask"} {
105			if ref := n.Attr[attr]; ref != "" {
106				fe, fo := findEnum(m, ref)
107				if fe == nil {
108					return nil, n.fail("unknown enum %s", ref)
109				}
110				f.GoType = qualified(m, fo, fe.Name)
111			}
112		}
113		if names[f.Name] {
114			return nil, n.fail("value field name collision %s", f.Name)
115		}
116		names[f.Name] = true
117		v.Fields = append(v.Fields, ValueField{Field: f, Bit: qualified(m, owner, e.Name+goName(bit.Text)), Value: value})
118	}
119	sort.Slice(v.Fields, func(i, j int) bool { return v.Fields[i].Value < v.Fields[j].Value })
120	if err := m.claim(name+"Values", sw); err != nil {
121		return nil, err
122	}
123	return v, nil
124}
125func valuesDecl(name string, v *ValueList) string {
126	var b strings.Builder
127	fmt.Fprintf(&b, "type %sValues struct { Mask %s;", name, v.Mask.GoType)
128	for _, f := range v.Fields {
129		fmt.Fprintf(&b, "%s %s;", f.Field.Name, f.Field.GoType)
130	}
131	b.WriteString("};\n")
132	for _, f := range v.Fields {
133		fmt.Fprintf(&b, "func(v *%sValues) Set%s(x %s) *%sValues { v.Mask |= %s; v.%s=x; return v };\n", name, f.Field.Name, f.Field.GoType, name, f.Bit, f.Field.Name)
134	}
135	return b.String()
136}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 1

Tags 1

↑↓ moveenter openesc close