...
1
2
3
4
5 package currency
6
7 import (
8 "fmt"
9 "sort"
10
11 "golang.org/x/text/internal/format"
12 "golang.org/x/text/internal/language/compact"
13 "golang.org/x/text/internal/number"
14
15 "golang.org/x/text/language"
16 )
17
18
19 type Amount struct {
20 amount interface{}
21 currency Unit
22 }
23
24
25 func (a Amount) Currency() Unit { return a.currency }
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41 func (a Amount) Format(s fmt.State, verb rune) {
42 v := formattedValue{
43 currency: a.currency,
44 amount: a.amount,
45 format: defaultFormat,
46 }
47 v.Format(s, verb)
48 }
49
50
51
52 type formattedValue struct {
53 currency Unit
54 amount interface{}
55 format *options
56 }
57
58
59
60 func (v formattedValue) Format(s fmt.State, verb rune) {
61 var tag language.Tag
62 var lang compact.ID
63 if state, ok := s.(format.State); ok {
64 tag = state.Language()
65 lang, _ = compact.RegionalID(compact.Tag(tag))
66 }
67
68
69 opt := v.format
70 if opt == nil {
71 opt = defaultFormat
72 }
73 cur := v.currency
74 if cur.index == 0 {
75 cur = opt.currency
76 }
77
78 sym := opt.symbol(lang, cur)
79 if v.amount != nil {
80 var f number.Formatter
81 f.InitDecimal(tag)
82
83 scale, increment := opt.kind.Rounding(cur)
84 f.RoundingContext.SetScale(scale)
85 f.RoundingContext.Increment = uint32(increment)
86 f.RoundingContext.IncrementScale = uint8(scale)
87 f.RoundingContext.Mode = number.ToNearestAway
88
89 d := f.Append(nil, v.amount)
90
91 fmt.Fprint(s, sym, " ", string(d))
92 } else {
93 fmt.Fprint(s, sym)
94 }
95 }
96
97
98 type Formatter func(amount interface{}) formattedValue
99
100
101
102
103
104 var dummy = USD.Amount(0)
105
106
107 func (f Formatter) adjust(fn func(*options)) Formatter {
108 var o options = *(f(dummy).format)
109 fn(&o)
110 return o.format
111 }
112
113
114
115 func (f Formatter) Default(currency Unit) Formatter {
116 return f.adjust(func(o *options) { o.currency = currency })
117 }
118
119
120 func (f Formatter) Kind(k Kind) Formatter {
121 return f.adjust(func(o *options) { o.kind = k })
122 }
123
124 var defaultFormat *options = ISO(dummy).format
125
126 var (
127
128 NarrowSymbol Formatter = Formatter(formNarrow)
129
130
131 Symbol Formatter = Formatter(formSymbol)
132
133
134 ISO Formatter = Formatter(formISO)
135
136
137
138
139 )
140
141
142 type options struct {
143 currency Unit
144 kind Kind
145
146 symbol func(compactIndex compact.ID, c Unit) string
147 }
148
149 func (o *options) format(amount interface{}) formattedValue {
150 v := formattedValue{format: o}
151 switch x := amount.(type) {
152 case Amount:
153 v.amount = x.amount
154 v.currency = x.currency
155 case *Amount:
156 v.amount = x.amount
157 v.currency = x.currency
158 case Unit:
159 v.currency = x
160 case *Unit:
161 v.currency = *x
162 default:
163 if o.currency.index == 0 {
164 panic("cannot format number without a currency being set")
165 }
166
167 v.amount = x
168 v.currency = o.currency
169 }
170 return v
171 }
172
173 var (
174 optISO = options{symbol: lookupISO}
175 optSymbol = options{symbol: lookupSymbol}
176 optNarrow = options{symbol: lookupNarrow}
177 )
178
179
180
181 func formISO(x interface{}) formattedValue { return optISO.format(x) }
182 func formSymbol(x interface{}) formattedValue { return optSymbol.format(x) }
183 func formNarrow(x interface{}) formattedValue { return optNarrow.format(x) }
184
185 func lookupISO(x compact.ID, c Unit) string { return c.String() }
186 func lookupSymbol(x compact.ID, c Unit) string { return normalSymbol.lookup(x, c) }
187 func lookupNarrow(x compact.ID, c Unit) string { return narrowSymbol.lookup(x, c) }
188
189 type symbolIndex struct {
190 index []uint16
191 data []curToIndex
192 }
193
194 var (
195 normalSymbol = symbolIndex{normalLangIndex, normalSymIndex}
196 narrowSymbol = symbolIndex{narrowLangIndex, narrowSymIndex}
197 )
198
199 func (x *symbolIndex) lookup(lang compact.ID, c Unit) string {
200 for {
201 index := x.data[x.index[lang]:x.index[lang+1]]
202 i := sort.Search(len(index), func(i int) bool {
203 return index[i].cur >= c.index
204 })
205 if i < len(index) && index[i].cur == c.index {
206 x := index[i].idx
207 start := x + 1
208 end := start + uint16(symbols[x])
209 if start == end {
210 return c.String()
211 }
212 return symbols[start:end]
213 }
214 if lang == 0 {
215 break
216 }
217 lang = lang.Parent()
218 }
219 return c.String()
220 }
221
View as plain text