github.com/octohelm/cuemod@v0.9.4/internal/cmd/go/internals/modindex/write.go (about) 1 // Copyright 2022 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package modindex 6 7 import ( 8 "encoding/binary" 9 "github.com/octohelm/cuemod/internal/cmd/go/internals/base" 10 "go/token" 11 "sort" 12 ) 13 14 const indexVersion = "go index v2" // 11 bytes (plus \n), to align uint32s in index 15 16 // encodeModuleBytes produces the encoded representation of the module index. 17 // encodeModuleBytes may modify the packages slice. 18 func encodeModuleBytes(packages []*rawPackage) []byte { 19 e := newEncoder() 20 e.Bytes([]byte(indexVersion + "\n")) 21 stringTableOffsetPos := e.Pos() // fill this at the end 22 e.Uint32(0) // string table offset 23 sort.Slice(packages, func(i, j int) bool { 24 return packages[i].dir < packages[j].dir 25 }) 26 e.Int(len(packages)) 27 packagesPos := e.Pos() 28 for _, p := range packages { 29 e.String(p.dir) 30 e.Int(0) 31 } 32 for i, p := range packages { 33 e.IntAt(e.Pos(), packagesPos+8*i+4) 34 encodePackage(e, p) 35 } 36 e.IntAt(e.Pos(), stringTableOffsetPos) 37 e.Bytes(e.stringTable) 38 e.Bytes([]byte{0xFF}) // end of string table marker 39 return e.b 40 } 41 42 func encodePackageBytes(p *rawPackage) []byte { 43 return encodeModuleBytes([]*rawPackage{p}) 44 } 45 46 func encodePackage(e *encoder, p *rawPackage) { 47 e.String(p.error) 48 e.String(p.dir) 49 e.Int(len(p.sourceFiles)) // number of source files 50 sourceFileOffsetPos := e.Pos() // the pos of the start of the source file offsets 51 for range p.sourceFiles { 52 e.Int(0) 53 } 54 for i, f := range p.sourceFiles { 55 e.IntAt(e.Pos(), sourceFileOffsetPos+4*i) 56 encodeFile(e, f) 57 } 58 } 59 60 func encodeFile(e *encoder, f *rawFile) { 61 e.String(f.error) 62 e.String(f.parseError) 63 e.String(f.synopsis) 64 e.String(f.name) 65 e.String(f.pkgName) 66 e.Bool(f.ignoreFile) 67 e.Bool(f.binaryOnly) 68 e.String(f.cgoDirectives) 69 e.String(f.goBuildConstraint) 70 71 e.Int(len(f.plusBuildConstraints)) 72 for _, s := range f.plusBuildConstraints { 73 e.String(s) 74 } 75 76 e.Int(len(f.imports)) 77 for _, m := range f.imports { 78 e.String(m.path) 79 e.Position(m.position) 80 } 81 82 e.Int(len(f.embeds)) 83 for _, embed := range f.embeds { 84 e.String(embed.pattern) 85 e.Position(embed.position) 86 } 87 88 e.Int(len(f.directives)) 89 for _, d := range f.directives { 90 e.String(d.Text) 91 e.Position(d.Pos) 92 } 93 } 94 95 func newEncoder() *encoder { 96 e := &encoder{strings: make(map[string]int)} 97 98 // place the empty string at position 0 in the string table 99 e.stringTable = append(e.stringTable, 0) 100 e.strings[""] = 0 101 102 return e 103 } 104 105 func (e *encoder) Position(position token.Position) { 106 e.String(position.Filename) 107 e.Int(position.Offset) 108 e.Int(position.Line) 109 e.Int(position.Column) 110 } 111 112 type encoder struct { 113 b []byte 114 stringTable []byte 115 strings map[string]int 116 } 117 118 func (e *encoder) Pos() int { 119 return len(e.b) 120 } 121 122 func (e *encoder) Bytes(b []byte) { 123 e.b = append(e.b, b...) 124 } 125 126 func (e *encoder) String(s string) { 127 if n, ok := e.strings[s]; ok { 128 e.Int(n) 129 return 130 } 131 pos := len(e.stringTable) 132 e.strings[s] = pos 133 e.Int(pos) 134 e.stringTable = binary.AppendUvarint(e.stringTable, uint64(len(s))) 135 e.stringTable = append(e.stringTable, s...) 136 } 137 138 func (e *encoder) Bool(b bool) { 139 if b { 140 e.Uint32(1) 141 } else { 142 e.Uint32(0) 143 } 144 } 145 146 func (e *encoder) Uint32(n uint32) { 147 e.b = binary.LittleEndian.AppendUint32(e.b, n) 148 } 149 150 // Int encodes n. Note that all ints are written to the index as uint32s, 151 // and to avoid problems on 32-bit systems we require fitting into a 32-bit int. 152 func (e *encoder) Int(n int) { 153 if n < 0 || int(int32(n)) != n { 154 base.Fatalf("go: attempting to write an int to the index that overflows int32") 155 } 156 e.Uint32(uint32(n)) 157 } 158 159 func (e *encoder) IntAt(n int, at int) { 160 if n < 0 || int(int32(n)) != n { 161 base.Fatalf("go: attempting to write an int to the index that overflows int32") 162 } 163 binary.LittleEndian.PutUint32(e.b[at:], uint32(n)) 164 }