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  }