github.com/mdaxf/iac@v0.0.0-20240519030858-58a061660378/vendor_skip/golang.org/x/text/number/format.go (about) 1 // Copyright 2017 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 number 6 7 import ( 8 "fmt" 9 "strings" 10 11 "golang.org/x/text/feature/plural" 12 "golang.org/x/text/internal/format" 13 "golang.org/x/text/internal/number" 14 "golang.org/x/text/language" 15 ) 16 17 // A FormatFunc formats a number. 18 type FormatFunc func(x interface{}, opts ...Option) Formatter 19 20 // NewFormat creates a FormatFunc based on another FormatFunc and new options. 21 // Use NewFormat to cash the creation of formatters. 22 func NewFormat(format FormatFunc, opts ...Option) FormatFunc { 23 o := *format(nil).options 24 n := len(o.options) 25 o.options = append(o.options[:n:n], opts...) 26 return func(x interface{}, opts ...Option) Formatter { 27 return newFormatter(&o, opts, x) 28 } 29 } 30 31 type options struct { 32 verbs string 33 initFunc initFunc 34 options []Option 35 pluralFunc func(t language.Tag, scale int) (f plural.Form, n int) 36 } 37 38 type optionFlag uint16 39 40 const ( 41 hasScale optionFlag = 1 << iota 42 hasPrecision 43 noSeparator 44 exact 45 ) 46 47 type initFunc func(f *number.Formatter, t language.Tag) 48 49 func newFormatter(o *options, opts []Option, value interface{}) Formatter { 50 if len(opts) > 0 { 51 n := *o 52 n.options = opts 53 o = &n 54 } 55 return Formatter{o, value} 56 } 57 58 func newOptions(verbs string, f initFunc) *options { 59 return &options{verbs: verbs, initFunc: f} 60 } 61 62 type Formatter struct { 63 *options 64 value interface{} 65 } 66 67 // Format implements format.Formatter. It is for internal use only for now. 68 func (f Formatter) Format(state format.State, verb rune) { 69 // TODO: consider implementing fmt.Formatter instead and using the following 70 // piece of code. This allows numbers to be rendered mostly as expected 71 // when using fmt. But it may get weird with the spellout options and we 72 // may need more of format.State over time. 73 // lang := language.Und 74 // if s, ok := state.(format.State); ok { 75 // lang = s.Language() 76 // } 77 78 lang := state.Language() 79 if !strings.Contains(f.verbs, string(verb)) { 80 fmt.Fprintf(state, "%%!%s(%T=%v)", string(verb), f.value, f.value) 81 return 82 } 83 var p number.Formatter 84 f.initFunc(&p, lang) 85 for _, o := range f.options.options { 86 o(lang, &p) 87 } 88 if w, ok := state.Width(); ok { 89 p.FormatWidth = uint16(w) 90 } 91 if prec, ok := state.Precision(); ok { 92 switch verb { 93 case 'd': 94 p.SetScale(0) 95 case 'f': 96 p.SetScale(prec) 97 case 'e': 98 p.SetPrecision(prec + 1) 99 case 'g': 100 p.SetPrecision(prec) 101 } 102 } 103 var d number.Decimal 104 d.Convert(p.RoundingContext, f.value) 105 state.Write(p.Format(nil, &d)) 106 } 107 108 // Digits returns information about which logical digits will be presented to 109 // the user. This information is relevant, for instance, to determine plural 110 // forms. 111 func (f Formatter) Digits(buf []byte, tag language.Tag, scale int) number.Digits { 112 var p number.Formatter 113 f.initFunc(&p, tag) 114 if scale >= 0 { 115 // TODO: this only works well for decimal numbers, which is generally 116 // fine. 117 p.SetScale(scale) 118 } 119 var d number.Decimal 120 d.Convert(p.RoundingContext, f.value) 121 return number.FormatDigits(&d, p.RoundingContext) 122 }