OSDN Git Service

new repo
[bytom/vapor.git] / vendor / golang.org / x / text / secure / precis / options.go
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.
4
5 package precis
6
7 import (
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"
13 )
14
15 // An Option is used to define the behavior and rules of a Profile.
16 type Option func(*options)
17
18 type options struct {
19         // Preparation options
20         foldWidth bool
21
22         // Enforcement options
23         asciiLower    bool
24         cases         transform.SpanningTransformer
25         disallow      runes.Set
26         norm          transform.SpanningTransformer
27         additional    []func() transform.SpanningTransformer
28         width         transform.SpanningTransformer
29         disallowEmpty bool
30         bidiRule      bool
31
32         // Comparison options
33         ignorecase bool
34 }
35
36 func getOpts(o ...Option) (res options) {
37         for _, f := range o {
38                 f(&res)
39         }
40         // Using a SpanningTransformer, instead of norm.Form prevents an allocation
41         // down the road.
42         if res.norm == nil {
43                 res.norm = norm.NFC
44         }
45         return
46 }
47
48 var (
49         // The IgnoreCase option causes the profile to perform a case insensitive
50         // comparison during the PRECIS comparison step.
51         IgnoreCase Option = ignoreCase
52
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
58
59         // The DisallowEmpty option causes the enforcement step to return an error if
60         // the resulting string would be empty.
61         DisallowEmpty Option = disallowEmpty
62
63         // The BidiRule option causes the Bidi Rule defined in RFC 5893 to be
64         // applied.
65         BidiRule Option = bidiRule
66 )
67
68 var (
69         ignoreCase = func(o *options) {
70                 o.ignorecase = true
71         }
72         foldWidth = func(o *options) {
73                 o.foldWidth = true
74         }
75         disallowEmpty = func(o *options) {
76                 o.disallowEmpty = true
77         }
78         bidiRule = func(o *options) {
79                 o.bidiRule = true
80         }
81 )
82
83 // TODO: move this logic to package transform
84
85 type spanWrap struct{ transform.Transformer }
86
87 func (s spanWrap) Span(src []byte, atEOF bool) (n int, err error) {
88         return 0, transform.ErrEndOfSpan
89 }
90
91 // TODO: allow different types? For instance:
92 //     func() transform.Transformer
93 //     func() transform.SpanningTransformer
94 //     func([]byte) bool  // validation only
95 //
96 // Also, would be great if we could detect if a transformer is reentrant.
97
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)
105                         }
106                         if _, ok := f().(transform.SpanningTransformer); !ok {
107                                 sf = func() transform.SpanningTransformer {
108                                         return spanWrap{f()}
109                                 }
110                         }
111                         o.additional = append(o.additional, sf)
112                 }
113         }
114 }
115
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) {
119                 o.norm = f
120         }
121 }
122
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) {
127                 o.asciiLower = true
128                 o.cases = cases.Fold(opts...)
129         }
130 }
131
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) {
136                 o.asciiLower = true
137                 if len(opts) == 0 {
138                         o.cases = cases.Lower(language.Und, cases.HandleFinalSigma(false))
139                         return
140                 }
141
142                 opts = append([]cases.Option{cases.HandleFinalSigma(false)}, opts...)
143                 o.cases = cases.Lower(language.Und, opts...)
144         }
145 }
146
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) {
151                 o.disallow = set
152         }
153 }