gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

options.go (4189B)


      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 }