...

Source file src/golang.org/x/text/secure/precis/options.go

Documentation: golang.org/x/text/secure/precis

     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  	repeat        bool
    32  
    33  	// Comparison options
    34  	ignorecase bool
    35  }
    36  
    37  func getOpts(o ...Option) (res options) {
    38  	for _, f := range o {
    39  		f(&res)
    40  	}
    41  	// Using a SpanningTransformer, instead of norm.Form prevents an allocation
    42  	// down the road.
    43  	if res.norm == nil {
    44  		res.norm = norm.NFC
    45  	}
    46  	return
    47  }
    48  
    49  var (
    50  	// The IgnoreCase option causes the profile to perform a case insensitive
    51  	// comparison during the PRECIS comparison step.
    52  	IgnoreCase Option = ignoreCase
    53  
    54  	// The FoldWidth option causes the profile to map non-canonical wide and
    55  	// narrow variants to their decomposition mapping. This is useful for
    56  	// profiles that are based on the identifier class which would otherwise
    57  	// disallow such characters.
    58  	FoldWidth Option = foldWidth
    59  
    60  	// The DisallowEmpty option causes the enforcement step to return an error if
    61  	// the resulting string would be empty.
    62  	DisallowEmpty Option = disallowEmpty
    63  
    64  	// The BidiRule option causes the Bidi Rule defined in RFC 5893 to be
    65  	// applied.
    66  	BidiRule Option = bidiRule
    67  )
    68  
    69  var (
    70  	ignoreCase = func(o *options) {
    71  		o.ignorecase = true
    72  	}
    73  	foldWidth = func(o *options) {
    74  		o.foldWidth = true
    75  	}
    76  	disallowEmpty = func(o *options) {
    77  		o.disallowEmpty = true
    78  	}
    79  	bidiRule = func(o *options) {
    80  		o.bidiRule = true
    81  	}
    82  	repeat = func(o *options) {
    83  		o.repeat = true
    84  	}
    85  )
    86  
    87  // TODO: move this logic to package transform
    88  
    89  type spanWrap struct{ transform.Transformer }
    90  
    91  func (s spanWrap) Span(src []byte, atEOF bool) (n int, err error) {
    92  	return 0, transform.ErrEndOfSpan
    93  }
    94  
    95  // TODO: allow different types? For instance:
    96  //     func() transform.Transformer
    97  //     func() transform.SpanningTransformer
    98  //     func([]byte) bool  // validation only
    99  //
   100  // Also, would be great if we could detect if a transformer is reentrant.
   101  
   102  // The AdditionalMapping option defines the additional mapping rule for the
   103  // Profile by applying Transformer's in sequence.
   104  func AdditionalMapping(t ...func() transform.Transformer) Option {
   105  	return func(o *options) {
   106  		for _, f := range t {
   107  			sf := func() transform.SpanningTransformer {
   108  				return f().(transform.SpanningTransformer)
   109  			}
   110  			if _, ok := f().(transform.SpanningTransformer); !ok {
   111  				sf = func() transform.SpanningTransformer {
   112  					return spanWrap{f()}
   113  				}
   114  			}
   115  			o.additional = append(o.additional, sf)
   116  		}
   117  	}
   118  }
   119  
   120  // The Norm option defines a Profile's normalization rule. Defaults to NFC.
   121  func Norm(f norm.Form) Option {
   122  	return func(o *options) {
   123  		o.norm = f
   124  	}
   125  }
   126  
   127  // The FoldCase option defines a Profile's case mapping rule. Options can be
   128  // provided to determine the type of case folding used.
   129  func FoldCase(opts ...cases.Option) Option {
   130  	return func(o *options) {
   131  		o.asciiLower = true
   132  		o.cases = cases.Fold(opts...)
   133  	}
   134  }
   135  
   136  // The LowerCase option defines a Profile's case mapping rule. Options can be
   137  // provided to determine the type of case folding used.
   138  func LowerCase(opts ...cases.Option) Option {
   139  	return func(o *options) {
   140  		o.asciiLower = true
   141  		if len(opts) == 0 {
   142  			o.cases = cases.Lower(language.Und, cases.HandleFinalSigma(false))
   143  			return
   144  		}
   145  
   146  		opts = append([]cases.Option{cases.HandleFinalSigma(false)}, opts...)
   147  		o.cases = cases.Lower(language.Und, opts...)
   148  	}
   149  }
   150  
   151  // The Disallow option further restricts a Profile's allowed characters beyond
   152  // what is disallowed by the underlying string class.
   153  func Disallow(set runes.Set) Option {
   154  	return func(o *options) {
   155  		o.disallow = set
   156  	}
   157  }
   158  

View as plain text