pages.go (3247B)
1 // Copyright 2019 The Hugo Authors. All rights reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // http://www.apache.org/licenses/LICENSE-2.0 7 // 8 // Unless required by applicable law or agreed to in writing, software 9 // distributed under the License is distributed on an "AS IS" BASIS, 10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package page 15 16 import ( 17 "fmt" 18 "math/rand" 19 20 "github.com/gohugoio/hugo/compare" 21 22 "github.com/gohugoio/hugo/resources/resource" 23 ) 24 25 // Pages is a slice of Page objects. This is the most common list type in Hugo. 26 type Pages []Page 27 28 // String returns a string representation of the list. 29 // For internal use. 30 func (ps Pages) String() string { 31 return fmt.Sprintf("Pages(%d)", len(ps)) 32 } 33 34 // Used in tests. 35 func (ps Pages) shuffle() { 36 for i := range ps { 37 j := rand.Intn(i + 1) 38 ps[i], ps[j] = ps[j], ps[i] 39 } 40 } 41 42 // ToResources wraps resource.ResourcesConverter. 43 // For internal use. 44 func (pages Pages) ToResources() resource.Resources { 45 r := make(resource.Resources, len(pages)) 46 for i, p := range pages { 47 r[i] = p 48 } 49 return r 50 } 51 52 // ToPages tries to convert seq into Pages. 53 func ToPages(seq any) (Pages, error) { 54 if seq == nil { 55 return Pages{}, nil 56 } 57 58 switch v := seq.(type) { 59 case Pages: 60 return v, nil 61 case *Pages: 62 return *(v), nil 63 case WeightedPages: 64 return v.Pages(), nil 65 case PageGroup: 66 return v.Pages, nil 67 case []Page: 68 pages := make(Pages, len(v)) 69 for i, vv := range v { 70 pages[i] = vv 71 } 72 return pages, nil 73 case []any: 74 pages := make(Pages, len(v)) 75 success := true 76 for i, vv := range v { 77 p, ok := vv.(Page) 78 if !ok { 79 success = false 80 break 81 } 82 pages[i] = p 83 } 84 if success { 85 return pages, nil 86 } 87 } 88 89 return nil, fmt.Errorf("cannot convert type %T to Pages", seq) 90 } 91 92 // Group groups the pages in in by key. 93 // This implements collections.Grouper. 94 func (p Pages) Group(key any, in any) (any, error) { 95 pages, err := ToPages(in) 96 if err != nil { 97 return PageGroup{}, err 98 } 99 return PageGroup{Key: key, Pages: pages}, nil 100 } 101 102 // Len returns the number of pages in the list. 103 func (p Pages) Len() int { 104 return len(p) 105 } 106 107 // ProbablyEq wraps compare.ProbablyEqer 108 // For internal use. 109 func (pages Pages) ProbablyEq(other any) bool { 110 otherPages, ok := other.(Pages) 111 if !ok { 112 return false 113 } 114 115 if len(pages) != len(otherPages) { 116 return false 117 } 118 119 step := 1 120 121 for i := 0; i < len(pages); i += step { 122 if !pages[i].Eq(otherPages[i]) { 123 return false 124 } 125 126 if i > 50 { 127 // This is most likely the same. 128 step = 50 129 } 130 } 131 132 return true 133 } 134 135 func (ps Pages) removeFirstIfFound(p Page) Pages { 136 ii := -1 137 for i, pp := range ps { 138 if p.Eq(pp) { 139 ii = i 140 break 141 } 142 } 143 144 if ii != -1 { 145 ps = append(ps[:ii], ps[ii+1:]...) 146 } 147 return ps 148 } 149 150 // PagesFactory somehow creates some Pages. 151 // We do a lot of lazy Pages initialization in Hugo, so we need a type. 152 type PagesFactory func() Pages 153 154 var ( 155 _ resource.ResourcesConverter = Pages{} 156 _ compare.ProbablyEqer = Pages{} 157 )