diff options
Diffstat (limited to 'src/cmd/go/internal/modindex/write.go')
-rw-r--r-- | src/cmd/go/internal/modindex/write.go | 158 |
1 files changed, 158 insertions, 0 deletions
diff --git a/src/cmd/go/internal/modindex/write.go b/src/cmd/go/internal/modindex/write.go new file mode 100644 index 0000000..df1467d --- /dev/null +++ b/src/cmd/go/internal/modindex/write.go @@ -0,0 +1,158 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package modindex + +import ( + "cmd/go/internal/base" + "encoding/binary" + "go/token" + "sort" +) + +const indexVersion = "go index v1" // 11 bytes (plus \n), to align uint32s in index + +// encodeModuleBytes produces the encoded representation of the module index. +// encodeModuleBytes may modify the packages slice. +func encodeModuleBytes(packages []*rawPackage) []byte { + e := newEncoder() + e.Bytes([]byte(indexVersion + "\n")) + stringTableOffsetPos := e.Pos() // fill this at the end + e.Uint32(0) // string table offset + sort.Slice(packages, func(i, j int) bool { + return packages[i].dir < packages[j].dir + }) + e.Int(len(packages)) + packagesPos := e.Pos() + for _, p := range packages { + e.String(p.dir) + e.Int(0) + } + for i, p := range packages { + e.IntAt(e.Pos(), packagesPos+8*i+4) + encodePackage(e, p) + } + e.IntAt(e.Pos(), stringTableOffsetPos) + e.Bytes(e.stringTable) + e.Bytes([]byte{0xFF}) // end of string table marker + return e.b +} + +func encodePackageBytes(p *rawPackage) []byte { + return encodeModuleBytes([]*rawPackage{p}) +} + +func encodePackage(e *encoder, p *rawPackage) { + e.String(p.error) + e.String(p.dir) + e.Int(len(p.sourceFiles)) // number of source files + sourceFileOffsetPos := e.Pos() // the pos of the start of the source file offsets + for range p.sourceFiles { + e.Int(0) + } + for i, f := range p.sourceFiles { + e.IntAt(e.Pos(), sourceFileOffsetPos+4*i) + encodeFile(e, f) + } +} + +func encodeFile(e *encoder, f *rawFile) { + e.String(f.error) + e.String(f.parseError) + e.String(f.synopsis) + e.String(f.name) + e.String(f.pkgName) + e.Bool(f.ignoreFile) + e.Bool(f.binaryOnly) + e.String(f.cgoDirectives) + e.String(f.goBuildConstraint) + + e.Int(len(f.plusBuildConstraints)) + for _, s := range f.plusBuildConstraints { + e.String(s) + } + + e.Int(len(f.imports)) + for _, m := range f.imports { + e.String(m.path) + e.Position(m.position) + } + + e.Int(len(f.embeds)) + for _, embed := range f.embeds { + e.String(embed.pattern) + e.Position(embed.position) + } +} + +func newEncoder() *encoder { + e := &encoder{strings: make(map[string]int)} + + // place the empty string at position 0 in the string table + e.stringTable = append(e.stringTable, 0) + e.strings[""] = 0 + + return e +} + +func (e *encoder) Position(position token.Position) { + e.String(position.Filename) + e.Int(position.Offset) + e.Int(position.Line) + e.Int(position.Column) +} + +type encoder struct { + b []byte + stringTable []byte + strings map[string]int +} + +func (e *encoder) Pos() int { + return len(e.b) +} + +func (e *encoder) Bytes(b []byte) { + e.b = append(e.b, b...) +} + +func (e *encoder) String(s string) { + if n, ok := e.strings[s]; ok { + e.Int(n) + return + } + pos := len(e.stringTable) + e.strings[s] = pos + e.Int(pos) + e.stringTable = binary.AppendUvarint(e.stringTable, uint64(len(s))) + e.stringTable = append(e.stringTable, s...) +} + +func (e *encoder) Bool(b bool) { + if b { + e.Uint32(1) + } else { + e.Uint32(0) + } +} + +func (e *encoder) Uint32(n uint32) { + e.b = binary.LittleEndian.AppendUint32(e.b, n) +} + +// Int encodes n. Note that all ints are written to the index as uint32s, +// and to avoid problems on 32-bit systems we require fitting into a 32-bit int. +func (e *encoder) Int(n int) { + if n < 0 || int(int32(n)) != n { + base.Fatalf("go: attempting to write an int to the index that overflows int32") + } + e.Uint32(uint32(n)) +} + +func (e *encoder) IntAt(n int, at int) { + if n < 0 || int(int32(n)) != n { + base.Fatalf("go: attempting to write an int to the index that overflows int32") + } + binary.LittleEndian.PutUint32(e.b[at:], uint32(n)) +} |