1 // Copyright 2015 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.
8 "golang.org/x/text/cases"
9 "golang.org/x/text/language"
10 "golang.org/x/text/runes"
11 "golang.org/x/text/transform"
12 "golang.org/x/text/unicode/norm"
15 // An Option is used to define the behavior and rules of a Profile.
16 type Option func(*options)
19 // Preparation options
22 // Enforcement options
24 cases transform.SpanningTransformer
26 norm transform.SpanningTransformer
27 additional []func() transform.SpanningTransformer
28 width transform.SpanningTransformer
36 func getOpts(o ...Option) (res options) {
40 // Using a SpanningTransformer, instead of norm.Form prevents an allocation
49 // The IgnoreCase option causes the profile to perform a case insensitive
50 // comparison during the PRECIS comparison step.
51 IgnoreCase Option = ignoreCase
53 // The FoldWidth option causes the profile to map non-canonical wide and
54 // narrow variants to their decomposition mapping. This is useful for
55 // profiles that are based on the identifier class which would otherwise
56 // disallow such characters.
57 FoldWidth Option = foldWidth
59 // The DisallowEmpty option causes the enforcement step to return an error if
60 // the resulting string would be empty.
61 DisallowEmpty Option = disallowEmpty
63 // The BidiRule option causes the Bidi Rule defined in RFC 5893 to be
65 BidiRule Option = bidiRule
69 ignoreCase = func(o *options) {
72 foldWidth = func(o *options) {
75 disallowEmpty = func(o *options) {
76 o.disallowEmpty = true
78 bidiRule = func(o *options) {
83 // TODO: move this logic to package transform
85 type spanWrap struct{ transform.Transformer }
87 func (s spanWrap) Span(src []byte, atEOF bool) (n int, err error) {
88 return 0, transform.ErrEndOfSpan
91 // TODO: allow different types? For instance:
92 // func() transform.Transformer
93 // func() transform.SpanningTransformer
94 // func([]byte) bool // validation only
96 // Also, would be great if we could detect if a transformer is reentrant.
98 // The AdditionalMapping option defines the additional mapping rule for the
99 // Profile by applying Transformer's in sequence.
100 func AdditionalMapping(t ...func() transform.Transformer) Option {
101 return func(o *options) {
102 for _, f := range t {
103 sf := func() transform.SpanningTransformer {
104 return f().(transform.SpanningTransformer)
106 if _, ok := f().(transform.SpanningTransformer); !ok {
107 sf = func() transform.SpanningTransformer {
111 o.additional = append(o.additional, sf)
116 // The Norm option defines a Profile's normalization rule. Defaults to NFC.
117 func Norm(f norm.Form) Option {
118 return func(o *options) {
123 // The FoldCase option defines a Profile's case mapping rule. Options can be
124 // provided to determine the type of case folding used.
125 func FoldCase(opts ...cases.Option) Option {
126 return func(o *options) {
128 o.cases = cases.Fold(opts...)
132 // The LowerCase option defines a Profile's case mapping rule. Options can be
133 // provided to determine the type of case folding used.
134 func LowerCase(opts ...cases.Option) Option {
135 return func(o *options) {
138 o.cases = cases.Lower(language.Und, cases.HandleFinalSigma(false))
142 opts = append([]cases.Option{cases.HandleFinalSigma(false)}, opts...)
143 o.cases = cases.Lower(language.Und, opts...)
147 // The Disallow option further restricts a Profile's allowed characters beyond
148 // what is disallowed by the underlying string class.
149 func Disallow(set runes.Set) Option {
150 return func(o *options) {