package main import ( "errors" "slices" "strings" "hakurei.app/internal/pkg" "hakurei.app/internal/rosa" ) const ( declarationAscending = iota declarationDescending nameAscending nameDescending sortOrderEnd = iota - 1 ) // packageIndex refers to metadata by name and various sort orders. type packageIndex struct { sorts [sortOrderEnd + 1][rosa.PresetUnexportedStart]*metadata names map[string]*metadata // Taken from [rosa.Report] if available. handleAccess func(*error) func() } // metadata holds [rosa.Metadata] extended with additional information. type metadata struct { p rosa.PArtifact *rosa.Metadata // Populated via [rosa.Toolchain.Version], [rosa.Unversioned] is equivalent // to the zero value. Otherwise, the zero value is invalid. Version string `json:"version,omitempty"` // Output data size, available if present in report. Size int64 `json:"size,omitempty"` // Whether the underlying [pkg.Artifact] is present in the report. HasReport bool `json:"report"` // Ident string encoded ahead of time. ids string // Backed by [rosa.Report], access must be prepared by HandleAccess. status []byte } // populate deterministically populates packageIndex, optionally with a report. func (index *packageIndex) populate(cache *pkg.Cache, report *rosa.Report) (err error) { if report != nil { defer report.HandleAccess(&err)() index.handleAccess = report.HandleAccess } var work [rosa.PresetUnexportedStart]*metadata index.names = make(map[string]*metadata) for p := range rosa.PresetUnexportedStart { m := metadata{ p: p, Metadata: rosa.GetMetadata(p), Version: rosa.Std.Version(p), } if m.Version == "" { return errors.New("invalid version from " + m.Name) } if m.Version == rosa.Unversioned { m.Version = "" } if cache != nil && report != nil { id := cache.Ident(rosa.Std.Load(p)) m.ids = pkg.Encode(id.Value()) m.status, m.Size = report.ArtifactOf(id) m.HasReport = m.Size >= 0 } work[p] = &m index.names[m.Name] = &m } index.sorts[declarationAscending] = work index.sorts[declarationDescending] = work slices.Reverse(index.sorts[declarationDescending][:]) index.sorts[nameAscending] = work slices.SortFunc(index.sorts[nameAscending][:], func(a, b *metadata) int { return strings.Compare(a.Name, b.Name) }) index.sorts[nameDescending] = index.sorts[nameAscending] slices.Reverse(index.sorts[nameDescending][:]) return }