Fixing race conditions in the code base (#5966)

* Adding initial race detector

* Remove setting of config twice

* Fixing config file watch and config reload on license save

* Fixing config file watch and config reload on license save

* Fixing build error

* Fixing locking issue

* Fixing makefile

* Fixing race in config

* Fixing race in status unit test

* Adding EE race tests

* Fixing race in cluster info

* Removing code that's isn't needed

* Fixing some more races

* Fixing govet issue
This commit is contained in:
Corey Hulen
2017-04-04 11:42:07 -07:00
committed by Harrison Healey
parent 32460bf63b
commit 6bf080393d
26 changed files with 1438 additions and 207 deletions

View File

@@ -190,6 +190,39 @@ check-server-style: govet
check-style: check-client-style check-server-style
test-te-race: start-docker prepare-enterprise
@echo Testing TE race conditions
@echo "Packages to test: "$(TE_PACKAGES)
@for package in $(TE_PACKAGES); do \
echo "Testing "$$package; \
$(GO) test $(GOFLAGS) -race -run=$(TESTS) -test.v -test.timeout=3000s $$package || exit 1; \
done
test-ee-race: start-docker prepare-enterprise
@echo Testing EE race conditions
ifeq ($(BUILD_ENTERPRISE_READY),true)
@echo "Packages to test: "$(EE_PACKAGES)
for package in $(EE_PACKAGES); do \
echo "Testing "$$package; \
$(GO) test $(GOFLAGS) -race -run=$(TESTS) -c $$package; \
if [ -f $$(basename $$package).test ]; then \
echo "Testing "$$package; \
./$$(basename $$package).test -test.v -test.timeout=2000s || exit 1; \
rm -r $$(basename $$package).test; \
fi; \
done
rm -f config/*.crt
rm -f config/*.key
endif
test-server-race: test-te-race test-ee-race
test-te: start-docker prepare-enterprise
@echo Testing TE

View File

@@ -86,6 +86,18 @@ func Setup() *TestHelper {
return &TestHelper{}
}
func ReloadConfigForSetup() {
utils.LoadConfig("config.json")
utils.InitTranslations(utils.Cfg.LocalizationSettings)
utils.Cfg.TeamSettings.MaxUsersPerTeam = 50
*utils.Cfg.RateLimitSettings.Enable = false
utils.Cfg.EmailSettings.SendEmailNotifications = true
utils.Cfg.EmailSettings.SMTPServer = "dockerhost"
utils.Cfg.EmailSettings.SMTPPort = "2500"
utils.Cfg.EmailSettings.FeedbackEmail = "test@example.com"
*utils.Cfg.TeamSettings.EnableOpenServer = true
}
func (me *TestHelper) InitBasic() *TestHelper {
me.BasicClient = me.CreateClient()
me.BasicUser = me.CreateUser(me.BasicClient)

View File

@@ -205,6 +205,7 @@ func TestStatuses(t *testing.T) {
}
func TestGetStatusesByIds(t *testing.T) {
ReloadConfigForSetup()
th := Setup().InitBasic()
Client := th.BasicClient

View File

@@ -61,7 +61,6 @@ func TestSendChangeUsernameEmail(t *testing.T) {
func TestSendEmailChangeVerifyEmail(t *testing.T) {
Setup()
utils.LoadConfig("config.json")
var userId string = "5349853498543jdfvndf9834"
var newUserEmail string = "newtest@example.com"
@@ -113,7 +112,6 @@ func TestSendEmailChangeVerifyEmail(t *testing.T) {
func TestSendEmailChangeEmail(t *testing.T) {
Setup()
utils.LoadConfig("config.json")
var oldEmail string = "test@example.com"
var newUserEmail string = "newtest@example.com"
@@ -161,7 +159,6 @@ func TestSendEmailChangeEmail(t *testing.T) {
func TestSendVerifyEmail(t *testing.T) {
Setup()
utils.LoadConfig("config.json")
var userId string = "5349853498543jdfvndf9834"
var userEmail string = "test@example.com"
@@ -213,7 +210,6 @@ func TestSendVerifyEmail(t *testing.T) {
func TestSendSignInChangeEmail(t *testing.T) {
Setup()
utils.LoadConfig("config.json")
var email string = "test@example.com"
var locale string = "en"
@@ -261,7 +257,6 @@ func TestSendSignInChangeEmail(t *testing.T) {
func TestSendWelcomeEmail(t *testing.T) {
Setup()
utils.LoadConfig("config.json")
var userId string = "32432nkjnijn432uj32"
var email string = "test@example.com"
@@ -355,7 +350,6 @@ func TestSendWelcomeEmail(t *testing.T) {
func TestSendPasswordChangeEmail(t *testing.T) {
Setup()
utils.LoadConfig("config.json")
var email string = "test@example.com"
var locale string = "en"
@@ -403,7 +397,6 @@ func TestSendPasswordChangeEmail(t *testing.T) {
func TestSendMfaChangeEmail(t *testing.T) {
Setup()
utils.LoadConfig("config.json")
var email string = "test@example.com"
var locale string = "en"
@@ -488,7 +481,6 @@ func TestSendMfaChangeEmail(t *testing.T) {
func TestSendInviteEmails(t *testing.T) {
th := Setup().InitBasic()
utils.LoadConfig("config.json")
var email1 string = "test1@example.com"
var email2 string = "test2@example.com"
@@ -564,7 +556,6 @@ func TestSendInviteEmails(t *testing.T) {
func TestSendPasswordReset(t *testing.T) {
th := Setup().InitBasic()
utils.LoadConfig("config.json")
var siteURL string = "http://test.mattermost.io"
// var locale string = "en"

View File

@@ -8,6 +8,7 @@ import (
"hash/fnv"
"runtime"
"runtime/debug"
"sync/atomic"
l4g "github.com/alecthomas/log4go"
@@ -18,6 +19,7 @@ import (
type Hub struct {
connections []*WebConn
count int64
register chan *WebConn
unregister chan *WebConn
broadcast chan *model.WebSocketEvent
@@ -43,12 +45,12 @@ func NewWebHub() *Hub {
func TotalWebsocketConnections() int {
// This is racy, but it's only used for reporting information
// so it's probably OK
count := 0
count := int64(0)
for _, hub := range hubs {
count = count + len(hub.connections)
count = count + atomic.LoadInt64(&hub.count)
}
return count
return int(count)
}
func HubStart() {
@@ -248,6 +250,7 @@ func (h *Hub) Start() {
select {
case webCon := <-h.register:
h.connections = append(h.connections, webCon)
atomic.StoreInt64(&h.count, int64(len(h.connections)))
case webCon := <-h.unregister:
userId := webCon.UserId

11
glide.lock generated
View File

@@ -1,8 +1,9 @@
hash: a64cfc8472f6345146f4d111d841cca8b8efb25e3d4872865670a3f7db63b23b
updated: 2017-03-24T16:11:53.990600794-07:00
hash: 193ce14426dc6d4ae2da1c1aad08389a157529f829ed12948095239e18e045a5
updated: 2017-03-30T22:26:27.084209918-07:00
imports:
- name: github.com/alecthomas/log4go
version: e5dc62318d9bd58682f1dceb53a4b24e8253682f
version: 3fbce08846379ec7f4f6bc7fce6dd01ce28fae4c
repo: https://github.com/mattermost/log4go.git
- name: github.com/beorn7/perks
version: 4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9
subpackages:
@@ -104,7 +105,7 @@ imports:
- name: github.com/pelletier/go-buffruneio
version: c37440a7cf42ac63b919c752ca73a85067e05992
- name: github.com/pelletier/go-toml
version: f6e7596e8daafd44dc9e5c208dc73035020c8481
version: e32a2e04744250647a72bf17da1b09befc03b6b1
- name: github.com/prometheus/client_golang
version: c5b7fccd204277076155f10851dad72b76a49317
subpackages:
@@ -178,7 +179,7 @@ imports:
subpackages:
- unix
- name: golang.org/x/text
version: fc7fa097411d30e6708badff276c4c164425590c
version: 65f4f820a7954b82e5c9325e1e088a4fda098f36
subpackages:
- transform
- unicode/norm

View File

@@ -2,6 +2,7 @@ package: github.com/mattermost/platform
import:
- package: github.com/NYTimes/gziphandler
- package: github.com/alecthomas/log4go
repo: https://github.com/mattermost/log4go.git
- package: github.com/dgryski/dgoogauth
- package: github.com/disintegration/imaging
version: v1.0.0

View File

@@ -6,19 +6,25 @@ package model
import (
"encoding/json"
"io"
"strings"
"sync"
"sync/atomic"
)
type ClusterInfo struct {
Id string `json:"id"`
Version string `json:"version"`
ConfigHash string `json:"config_hash"`
InterNodeUrl string `json:"internode_url"`
Hostname string `json:"hostname"`
LastSuccessfulPing int64 `json:"last_ping"`
IsAlive bool `json:"is_alive"`
Id string `json:"id"`
Version string `json:"version"`
ConfigHash string `json:"config_hash"`
InterNodeUrl string `json:"internode_url"`
Hostname string `json:"hostname"`
LastSuccessfulPing int64 `json:"last_ping"`
Alive int32 `json:"is_alive"`
Mutex sync.RWMutex `json:"-"`
}
func (me *ClusterInfo) ToJson() string {
me.Mutex.RLock()
defer me.Mutex.RUnlock()
b, err := json.Marshal(me)
if err != nil {
return ""
@@ -27,9 +33,15 @@ func (me *ClusterInfo) ToJson() string {
}
}
func (me *ClusterInfo) Copy() *ClusterInfo {
json := me.ToJson()
return ClusterInfoFromJson(strings.NewReader(json))
}
func ClusterInfoFromJson(data io.Reader) *ClusterInfo {
decoder := json.NewDecoder(data)
var me ClusterInfo
me.Mutex = sync.RWMutex{}
err := decoder.Decode(&me)
if err == nil {
return &me
@@ -38,7 +50,21 @@ func ClusterInfoFromJson(data io.Reader) *ClusterInfo {
}
}
func (me *ClusterInfo) SetAlive(alive bool) {
if alive {
atomic.StoreInt32(&me.Alive, 1)
} else {
atomic.StoreInt32(&me.Alive, 0)
}
}
func (me *ClusterInfo) IsAlive() bool {
return atomic.LoadInt32(&me.Alive) == 1
}
func (me *ClusterInfo) HaveEstablishedInitialContact() bool {
me.Mutex.RLock()
defer me.Mutex.RUnlock()
if me.Id != "" {
return true
}
@@ -46,6 +72,16 @@ func (me *ClusterInfo) HaveEstablishedInitialContact() bool {
return false
}
func (me *ClusterInfo) IdEqualTo(in string) bool {
me.Mutex.RLock()
defer me.Mutex.RUnlock()
if me.Id == in {
return true
}
return false
}
func ClusterInfosToJson(objmap []*ClusterInfo) string {
if b, err := json.Marshal(objmap); err != nil {
return ""

View File

@@ -16,6 +16,16 @@ func TestClusterInfoJson(t *testing.T) {
if cluster.Id != result.Id {
t.Fatal("Ids do not match")
}
cluster.SetAlive(true)
if !cluster.IsAlive() {
t.Fatal("should be live")
}
cluster.SetAlive(false)
if cluster.IsAlive() {
t.Fatal("should be not live")
}
}
func TestClusterInfosJson(t *testing.T) {

View File

@@ -5,6 +5,7 @@ package model
import (
"fmt"
"sync"
"time"
)
@@ -18,17 +19,24 @@ type ScheduledTask struct {
timer *time.Timer
}
var taskMutex = sync.Mutex{}
var tasks = make(map[string]*ScheduledTask)
func addTask(task *ScheduledTask) {
taskMutex.Lock()
defer taskMutex.Unlock()
tasks[task.Name] = task
}
func removeTaskByName(name string) {
taskMutex.Lock()
defer taskMutex.Unlock()
delete(tasks, name)
}
func GetTaskByName(name string) *ScheduledTask {
taskMutex.Lock()
defer taskMutex.Unlock()
if task, ok := tasks[name]; ok {
return task
}
@@ -36,6 +44,8 @@ func GetTaskByName(name string) *ScheduledTask {
}
func GetAllTasks() *map[string]*ScheduledTask {
taskMutex.Lock()
defer taskMutex.Unlock()
return &tasks
}

View File

@@ -72,6 +72,8 @@ func FindDir(dir string) string {
}
func DisableDebugLogForTest() {
cfgMutex.Lock()
defer cfgMutex.Unlock()
if l4g.Global["stdout"] != nil {
originalDisableDebugLvl = l4g.Global["stdout"].Level
l4g.Global["stdout"].Level = l4g.ERROR
@@ -79,6 +81,8 @@ func DisableDebugLogForTest() {
}
func EnableDebugLogForTest() {
cfgMutex.Lock()
defer cfgMutex.Unlock()
if l4g.Global["stdout"] != nil {
l4g.Global["stdout"].Level = originalDisableDebugLvl
}

View File

@@ -47,7 +47,6 @@ func (w *FileLogWriter) LogWrite(rec *LogRecord) {
func (w *FileLogWriter) Close() {
close(w.rec)
w.file.Sync()
}
// NewFileLogWriter creates a new LogWriter which writes to the given file and
@@ -79,6 +78,7 @@ func NewFileLogWriter(fname string, rotate bool) *FileLogWriter {
defer func() {
if w.file != nil {
fmt.Fprint(w.file, FormatLogRecord(w.trailer, &LogRecord{Created: time.Now()}))
w.file.Sync()
w.file.Close()
}
}()

View File

@@ -7,6 +7,7 @@ import (
"fmt"
"io"
"strings"
"sync"
)
const (
@@ -22,6 +23,7 @@ type formatCacheType struct {
}
var formatCache = &formatCacheType{}
var mutex sync.Mutex
// Known format codes:
// %T - Time (15:04:05 MST)
@@ -44,6 +46,7 @@ func FormatLogRecord(format string, rec *LogRecord) string {
out := bytes.NewBuffer(make([]byte, 0, 64))
secs := rec.Created.UnixNano() / 1e9
mutex.Lock()
cache := *formatCache
if cache.LastUpdateSeconds != secs {
month, day, year := rec.Created.Month(), rec.Created.Day(), rec.Created.Year()
@@ -59,6 +62,7 @@ func FormatLogRecord(format string, rec *LogRecord) string {
cache = *updated
formatCache = updated
}
mutex.Unlock()
// Split the string into pieces by % signs
pieces := bytes.Split([]byte(format), []byte{'%'})

459
vendor/github.com/pelletier/go-toml/marshal.go generated vendored Normal file
View File

@@ -0,0 +1,459 @@
package toml
import (
"errors"
"fmt"
"reflect"
"strings"
"time"
)
/*
TomlTree structural types and corresponding marshal types
-------------------------------------------------------------------------------
*TomlTree (*)struct, (*)map[string]interface{}
[]*TomlTree (*)[](*)struct, (*)[](*)map[string]interface{}
[]interface{} (as interface{}) (*)[]primitive, (*)[]([]interface{})
interface{} (*)primitive
TomlTree primitive types and corresponding marshal types
-----------------------------------------------------------
uint64 uint, uint8-uint64, pointers to same
int64 int, int8-uint64, pointers to same
float64 float32, float64, pointers to same
string string, pointers to same
bool bool, pointers to same
time.Time time.Time{}, pointers to same
*/
type tomlOpts struct {
name string
include bool
omitempty bool
}
var timeType = reflect.TypeOf(time.Time{})
// Check if the given marshall type maps to a TomlTree primitive
func isPrimitive(mtype reflect.Type) bool {
switch mtype.Kind() {
case reflect.Ptr:
return isPrimitive(mtype.Elem())
case reflect.Bool:
return true
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return true
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return true
case reflect.Float32, reflect.Float64:
return true
case reflect.String:
return true
case reflect.Struct:
return mtype == timeType
default:
return false
}
}
// Check if the given marshall type maps to a TomlTree slice
func isTreeSlice(mtype reflect.Type) bool {
switch mtype.Kind() {
case reflect.Slice:
return !isOtherSlice(mtype)
default:
return false
}
}
// Check if the given marshall type maps to a non-TomlTree slice
func isOtherSlice(mtype reflect.Type) bool {
switch mtype.Kind() {
case reflect.Ptr:
return isOtherSlice(mtype.Elem())
case reflect.Slice:
return isPrimitive(mtype.Elem()) || isOtherSlice(mtype.Elem())
default:
return false
}
}
// Check if the given marshall type maps to a TomlTree
func isTree(mtype reflect.Type) bool {
switch mtype.Kind() {
case reflect.Map:
return true
case reflect.Struct:
return !isPrimitive(mtype)
default:
return false
}
}
/*
Marshal returns the TOML encoding of v. Behavior is similar to the Go json
encoder, except that there is no concept of a Marshaler interface or MarshalTOML
function for sub-structs, and currently only definite types can be marshaled
(i.e. no `interface{}`).
Note that pointers are automatically assigned the "omitempty" option, as TOML
explicity does not handle null values (saying instead the label should be
dropped).
*/
func Marshal(v interface{}) ([]byte, error) {
mtype := reflect.TypeOf(v)
if mtype.Kind() != reflect.Struct {
return []byte{}, errors.New("Only a struct can be marshaled to TOML")
}
sval := reflect.ValueOf(v)
t, err := valueToTree(mtype, sval)
if err != nil {
return []byte{}, err
}
s, err := t.ToTomlString()
return []byte(s), err
}
// Convert given marshal struct or map value to toml tree
func valueToTree(mtype reflect.Type, mval reflect.Value) (*TomlTree, error) {
if mtype.Kind() == reflect.Ptr {
return valueToTree(mtype.Elem(), mval.Elem())
}
tval := newTomlTree()
switch mtype.Kind() {
case reflect.Struct:
for i := 0; i < mtype.NumField(); i++ {
mtypef, mvalf := mtype.Field(i), mval.Field(i)
opts := tomlOptions(mtypef)
if opts.include && (!opts.omitempty || !isZero(mvalf)) {
val, err := valueToToml(mtypef.Type, mvalf)
if err != nil {
return nil, err
}
tval.Set(opts.name, val)
}
}
case reflect.Map:
for _, key := range mval.MapKeys() {
mvalf := mval.MapIndex(key)
val, err := valueToToml(mtype.Elem(), mvalf)
if err != nil {
return nil, err
}
tval.Set(key.String(), val)
}
}
return tval, nil
}
// Convert given marshal slice to slice of Toml trees
func valueToTreeSlice(mtype reflect.Type, mval reflect.Value) ([]*TomlTree, error) {
tval := make([]*TomlTree, mval.Len(), mval.Len())
for i := 0; i < mval.Len(); i++ {
val, err := valueToTree(mtype.Elem(), mval.Index(i))
if err != nil {
return nil, err
}
tval[i] = val
}
return tval, nil
}
// Convert given marshal slice to slice of toml values
func valueToOtherSlice(mtype reflect.Type, mval reflect.Value) (interface{}, error) {
tval := make([]interface{}, mval.Len(), mval.Len())
for i := 0; i < mval.Len(); i++ {
val, err := valueToToml(mtype.Elem(), mval.Index(i))
if err != nil {
return nil, err
}
tval[i] = val
}
return tval, nil
}
// Convert given marshal value to toml value
func valueToToml(mtype reflect.Type, mval reflect.Value) (interface{}, error) {
if mtype.Kind() == reflect.Ptr {
return valueToToml(mtype.Elem(), mval.Elem())
}
switch {
case isTree(mtype):
return valueToTree(mtype, mval)
case isTreeSlice(mtype):
return valueToTreeSlice(mtype, mval)
case isOtherSlice(mtype):
return valueToOtherSlice(mtype, mval)
default:
switch mtype.Kind() {
case reflect.Bool:
return mval.Bool(), nil
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return mval.Int(), nil
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return mval.Uint(), nil
case reflect.Float32, reflect.Float64:
return mval.Float(), nil
case reflect.String:
return mval.String(), nil
case reflect.Struct:
return mval.Interface().(time.Time), nil
default:
return nil, fmt.Errorf("Marshal can't handle %v(%v)", mtype, mtype.Kind())
}
}
}
/*
Unmarshal parses the TOML-encoded data and stores the result in the value
pointed to by v. Behavior is similar to the Go json encoder, except that there
is no concept of an Unmarshaler interface or UnmarshalTOML function for
sub-structs, and currently only definite types can be unmarshaled to (i.e. no
`interface{}`).
*/
func Unmarshal(data []byte, v interface{}) error {
mtype := reflect.TypeOf(v)
if mtype.Kind() != reflect.Ptr || mtype.Elem().Kind() != reflect.Struct {
return errors.New("Only a pointer to struct can be unmarshaled from TOML")
}
t, err := Load(string(data))
if err != nil {
return err
}
sval, err := valueFromTree(mtype.Elem(), t)
if err != nil {
return err
}
reflect.ValueOf(v).Elem().Set(sval)
return nil
}
// Convert toml tree to marshal struct or map, using marshal type
func valueFromTree(mtype reflect.Type, tval *TomlTree) (reflect.Value, error) {
if mtype.Kind() == reflect.Ptr {
return unwrapPointer(mtype, tval)
}
var mval reflect.Value
switch mtype.Kind() {
case reflect.Struct:
mval = reflect.New(mtype).Elem()
for i := 0; i < mtype.NumField(); i++ {
mtypef := mtype.Field(i)
opts := tomlOptions(mtypef)
if opts.include {
key := opts.name
exists := tval.Has(key)
if exists {
val := tval.Get(key)
mvalf, err := valueFromToml(mtypef.Type, val)
if err != nil {
return mval, formatError(err, tval.GetPosition(key))
}
mval.Field(i).Set(mvalf)
}
}
}
case reflect.Map:
mval = reflect.MakeMap(mtype)
for _, key := range tval.Keys() {
val := tval.Get(key)
mvalf, err := valueFromToml(mtype.Elem(), val)
if err != nil {
return mval, formatError(err, tval.GetPosition(key))
}
mval.SetMapIndex(reflect.ValueOf(key), mvalf)
}
}
return mval, nil
}
// Convert toml value to marshal struct/map slice, using marshal type
func valueFromTreeSlice(mtype reflect.Type, tval []*TomlTree) (reflect.Value, error) {
mval := reflect.MakeSlice(mtype, len(tval), len(tval))
for i := 0; i < len(tval); i++ {
val, err := valueFromTree(mtype.Elem(), tval[i])
if err != nil {
return mval, err
}
mval.Index(i).Set(val)
}
return mval, nil
}
// Convert toml value to marshal primitive slice, using marshal type
func valueFromOtherSlice(mtype reflect.Type, tval []interface{}) (reflect.Value, error) {
mval := reflect.MakeSlice(mtype, len(tval), len(tval))
for i := 0; i < len(tval); i++ {
val, err := valueFromToml(mtype.Elem(), tval[i])
if err != nil {
return mval, err
}
mval.Index(i).Set(val)
}
return mval, nil
}
// Convert toml value to marshal value, using marshal type
func valueFromToml(mtype reflect.Type, tval interface{}) (reflect.Value, error) {
if mtype.Kind() == reflect.Ptr {
return unwrapPointer(mtype, tval)
}
switch {
case isTree(mtype):
return valueFromTree(mtype, tval.(*TomlTree))
case isTreeSlice(mtype):
return valueFromTreeSlice(mtype, tval.([]*TomlTree))
case isOtherSlice(mtype):
return valueFromOtherSlice(mtype, tval.([]interface{}))
default:
switch mtype.Kind() {
case reflect.Bool:
val, ok := tval.(bool)
if !ok {
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to bool", tval, tval)
}
return reflect.ValueOf(val), nil
case reflect.Int:
val, ok := tval.(int64)
if !ok {
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to int", tval, tval)
}
return reflect.ValueOf(int(val)), nil
case reflect.Int8:
val, ok := tval.(int64)
if !ok {
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to int", tval, tval)
}
return reflect.ValueOf(int8(val)), nil
case reflect.Int16:
val, ok := tval.(int64)
if !ok {
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to int", tval, tval)
}
return reflect.ValueOf(int16(val)), nil
case reflect.Int32:
val, ok := tval.(int64)
if !ok {
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to int", tval, tval)
}
return reflect.ValueOf(int32(val)), nil
case reflect.Int64:
val, ok := tval.(int64)
if !ok {
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to int", tval, tval)
}
return reflect.ValueOf(val), nil
case reflect.Uint:
val, ok := tval.(int64)
if !ok {
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to uint", tval, tval)
}
return reflect.ValueOf(uint(val)), nil
case reflect.Uint8:
val, ok := tval.(int64)
if !ok {
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to uint", tval, tval)
}
return reflect.ValueOf(uint8(val)), nil
case reflect.Uint16:
val, ok := tval.(int64)
if !ok {
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to uint", tval, tval)
}
return reflect.ValueOf(uint16(val)), nil
case reflect.Uint32:
val, ok := tval.(int64)
if !ok {
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to uint", tval, tval)
}
return reflect.ValueOf(uint32(val)), nil
case reflect.Uint64:
val, ok := tval.(int64)
if !ok {
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to uint", tval, tval)
}
return reflect.ValueOf(uint64(val)), nil
case reflect.Float32:
val, ok := tval.(float64)
if !ok {
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to float", tval, tval)
}
return reflect.ValueOf(float32(val)), nil
case reflect.Float64:
val, ok := tval.(float64)
if !ok {
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to float", tval, tval)
}
return reflect.ValueOf(val), nil
case reflect.String:
val, ok := tval.(string)
if !ok {
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to string", tval, tval)
}
return reflect.ValueOf(val), nil
case reflect.Struct:
val, ok := tval.(time.Time)
if !ok {
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to time", tval, tval)
}
return reflect.ValueOf(val), nil
default:
return reflect.ValueOf(nil), fmt.Errorf("Unmarshal can't handle %v(%v)", mtype, mtype.Kind())
}
}
}
func unwrapPointer(mtype reflect.Type, tval interface{}) (reflect.Value, error) {
val, err := valueFromToml(mtype.Elem(), tval)
if err != nil {
return reflect.ValueOf(nil), err
}
mval := reflect.New(mtype.Elem())
mval.Elem().Set(val)
return mval, nil
}
func tomlOptions(vf reflect.StructField) tomlOpts {
tag := vf.Tag.Get("toml")
parse := strings.Split(tag, ",")
result := tomlOpts{vf.Name, true, false}
if parse[0] != "" {
if parse[0] == "-" && len(parse) == 1 {
result.include = false
} else {
result.name = strings.Trim(parse[0], " ")
}
}
if vf.PkgPath != "" {
result.include = false
}
if len(parse) > 1 && strings.Trim(parse[1], " ") == "omitempty" {
result.omitempty = true
}
if vf.Type.Kind() == reflect.Ptr {
result.omitempty = true
}
return result
}
func isZero(val reflect.Value) bool {
switch val.Type().Kind() {
case reflect.Map:
fallthrough
case reflect.Array:
fallthrough
case reflect.Slice:
return val.Len() == 0
default:
return reflect.DeepEqual(val.Interface(), reflect.Zero(val.Type()).Interface())
}
}
func formatError(err error, pos Position) error {
if err.Error()[0] == '(' { // Error already contains position information
return err
}
return fmt.Errorf("%s: %s", pos, err)
}

535
vendor/github.com/pelletier/go-toml/marshal_test.go generated vendored Normal file
View File

@@ -0,0 +1,535 @@
package toml
import (
"bytes"
"encoding/json"
"io/ioutil"
"reflect"
"testing"
"time"
)
type basicMarshalTestStruct struct {
String string `toml:"string"`
StringList []string `toml:"strlist"`
Sub basicMarshalTestSubStruct `toml:"subdoc"`
SubList []basicMarshalTestSubStruct `toml:"sublist"`
}
type basicMarshalTestSubStruct struct {
String2 string
}
var basicTestData = basicMarshalTestStruct{
String: "Hello",
StringList: []string{"Howdy", "Hey There"},
Sub: basicMarshalTestSubStruct{"One"},
SubList: []basicMarshalTestSubStruct{{"Two"}, {"Three"}},
}
var basicTestToml = []byte(`string = "Hello"
strlist = ["Howdy","Hey There"]
[subdoc]
String2 = "One"
[[sublist]]
String2 = "Two"
[[sublist]]
String2 = "Three"
`)
func TestBasicMarshal(t *testing.T) {
result, err := Marshal(basicTestData)
if err != nil {
t.Fatal(err)
}
expected := basicTestToml
if !bytes.Equal(result, expected) {
t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result)
}
}
func TestBasicUnmarshal(t *testing.T) {
result := basicMarshalTestStruct{}
err := Unmarshal(basicTestToml, &result)
expected := basicTestData
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(result, expected) {
t.Errorf("Bad unmarshal: expected %v, got %v", expected, result)
}
}
type testDoc struct {
Title string `toml:"title"`
Basics testDocBasics `toml:"basic"`
BasicLists testDocBasicLists `toml:"basic_lists"`
BasicMap map[string]string `toml:"basic_map"`
Subdocs testDocSubs `toml:"subdoc"`
SubDocList []testSubDoc `toml:"subdoclist"`
SubDocPtrs []*testSubDoc `toml:"subdocptrs"`
err int `toml:"shouldntBeHere"`
unexported int `toml:"shouldntBeHere"`
Unexported2 int `toml:"-"`
}
type testDocBasics struct {
Bool bool `toml:"bool"`
Date time.Time `toml:"date"`
Float float32 `toml:"float"`
Int int `toml:"int"`
Uint uint `toml:"uint"`
String *string `toml:"string"`
unexported int `toml:"shouldntBeHere"`
}
type testDocBasicLists struct {
Bools []bool `toml:"bools"`
Dates []time.Time `toml:"dates"`
Floats []*float32 `toml:"floats"`
Ints []int `toml:"ints"`
Strings []string `toml:"strings"`
UInts []uint `toml:"uints"`
}
type testDocSubs struct {
First testSubDoc `toml:"first"`
Second *testSubDoc `toml:"second"`
}
type testSubDoc struct {
Name string `toml:"name"`
unexported int `toml:"shouldntBeHere"`
}
var biteMe = "Bite me"
var float1 float32 = 12.3
var float2 float32 = 45.6
var float3 float32 = 78.9
var subdoc = testSubDoc{"Second", 0}
var docData = testDoc{
Title: "TOML Marshal Testing",
unexported: 0,
Unexported2: 0,
Basics: testDocBasics{
Bool: true,
Date: time.Date(1979, 5, 27, 7, 32, 0, 0, time.UTC),
Float: 123.4,
Int: 5000,
Uint: 5001,
String: &biteMe,
unexported: 0,
},
BasicLists: testDocBasicLists{
Bools: []bool{true, false, true},
Dates: []time.Time{
time.Date(1979, 5, 27, 7, 32, 0, 0, time.UTC),
time.Date(1980, 5, 27, 7, 32, 0, 0, time.UTC),
},
Floats: []*float32{&float1, &float2, &float3},
Ints: []int{8001, 8001, 8002},
Strings: []string{"One", "Two", "Three"},
UInts: []uint{5002, 5003},
},
BasicMap: map[string]string{
"one": "one",
"two": "two",
},
Subdocs: testDocSubs{
First: testSubDoc{"First", 0},
Second: &subdoc,
},
SubDocList: []testSubDoc{
testSubDoc{"List.First", 0},
testSubDoc{"List.Second", 0},
},
SubDocPtrs: []*testSubDoc{&subdoc},
}
func TestDocMarshal(t *testing.T) {
result, err := Marshal(docData)
if err != nil {
t.Fatal(err)
}
expected, _ := ioutil.ReadFile("marshal_test.toml")
if !bytes.Equal(result, expected) {
t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result)
}
}
func TestDocUnmarshal(t *testing.T) {
result := testDoc{}
tomlData, _ := ioutil.ReadFile("marshal_test.toml")
err := Unmarshal(tomlData, &result)
expected := docData
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(result, expected) {
resStr, _ := json.MarshalIndent(result, "", " ")
expStr, _ := json.MarshalIndent(expected, "", " ")
t.Errorf("Bad unmarshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expStr, resStr)
}
}
type tomlTypeCheckTest struct {
name string
item interface{}
typ int //0=primitive, 1=otherslice, 2=treeslice, 3=tree
}
func TestTypeChecks(t *testing.T) {
tests := []tomlTypeCheckTest{
{"integer", 2, 0},
{"time", time.Date(2015, 1, 1, 0, 0, 0, 0, time.UTC), 0},
{"stringlist", []string{"hello", "hi"}, 1},
{"timelist", []time.Time{time.Date(2015, 1, 1, 0, 0, 0, 0, time.UTC)}, 1},
{"objectlist", []tomlTypeCheckTest{}, 2},
{"object", tomlTypeCheckTest{}, 3},
}
for _, test := range tests {
expected := []bool{false, false, false, false}
expected[test.typ] = true
result := []bool{
isPrimitive(reflect.TypeOf(test.item)),
isOtherSlice(reflect.TypeOf(test.item)),
isTreeSlice(reflect.TypeOf(test.item)),
isTree(reflect.TypeOf(test.item)),
}
if !reflect.DeepEqual(expected, result) {
t.Errorf("Bad type check on %q: expected %v, got %v", test.name, expected, result)
}
}
}
type unexportedMarshalTestStruct struct {
String string `toml:"string"`
StringList []string `toml:"strlist"`
Sub basicMarshalTestSubStruct `toml:"subdoc"`
SubList []basicMarshalTestSubStruct `toml:"sublist"`
unexported int `toml:"shouldntBeHere"`
Unexported2 int `toml:"-"`
}
var unexportedTestData = unexportedMarshalTestStruct{
String: "Hello",
StringList: []string{"Howdy", "Hey There"},
Sub: basicMarshalTestSubStruct{"One"},
SubList: []basicMarshalTestSubStruct{{"Two"}, {"Three"}},
unexported: 0,
Unexported2: 0,
}
var unexportedTestToml = []byte(`string = "Hello"
strlist = ["Howdy","Hey There"]
unexported = 1
shouldntBeHere = 2
[subdoc]
String2 = "One"
[[sublist]]
String2 = "Two"
[[sublist]]
String2 = "Three"
`)
func TestUnexportedUnmarshal(t *testing.T) {
result := unexportedMarshalTestStruct{}
err := Unmarshal(unexportedTestToml, &result)
expected := unexportedTestData
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(result, expected) {
t.Errorf("Bad unexported unmarshal: expected %v, got %v", expected, result)
}
}
type errStruct struct {
Bool bool `toml:"bool"`
Date time.Time `toml:"date"`
Float float64 `toml:"float"`
Int int16 `toml:"int"`
String *string `toml:"string"`
}
var errTomls = []string{
"bool = truly\ndate = 1979-05-27T07:32:00Z\nfloat = 123.4\nint = 5000\nstring = \"Bite me\"",
"bool = true\ndate = 1979-05-27T07:3200Z\nfloat = 123.4\nint = 5000\nstring = \"Bite me\"",
"bool = true\ndate = 1979-05-27T07:32:00Z\nfloat = 123a4\nint = 5000\nstring = \"Bite me\"",
"bool = true\ndate = 1979-05-27T07:32:00Z\nfloat = 123.4\nint = j000\nstring = \"Bite me\"",
"bool = true\ndate = 1979-05-27T07:32:00Z\nfloat = 123.4\nint = 5000\nstring = Bite me",
"bool = true\ndate = 1979-05-27T07:32:00Z\nfloat = 123.4\nint = 5000\nstring = Bite me",
"bool = 1\ndate = 1979-05-27T07:32:00Z\nfloat = 123.4\nint = 5000\nstring = \"Bite me\"",
"bool = true\ndate = 1\nfloat = 123.4\nint = 5000\nstring = \"Bite me\"",
"bool = true\ndate = 1979-05-27T07:32:00Z\n\"sorry\"\nint = 5000\nstring = \"Bite me\"",
"bool = true\ndate = 1979-05-27T07:32:00Z\nfloat = 123.4\nint = \"sorry\"\nstring = \"Bite me\"",
"bool = true\ndate = 1979-05-27T07:32:00Z\nfloat = 123.4\nint = 5000\nstring = 1",
}
type mapErr struct {
Vals map[string]float64
}
type intErr struct {
Int1 int
Int2 int8
Int3 int16
Int4 int32
Int5 int64
UInt1 uint
UInt2 uint8
UInt3 uint16
UInt4 uint32
UInt5 uint64
Flt1 float32
Flt2 float64
}
var intErrTomls = []string{
"Int1 = []\nInt2 = 2\nInt3 = 3\nInt4 = 4\nInt5 = 5\nUInt1 = 1\nUInt2 = 2\nUInt3 = 3\nUInt4 = 4\nUInt5 = 5\nFlt1 = 1.0\nFlt2 = 2.0",
"Int1 = 1\nInt2 = []\nInt3 = 3\nInt4 = 4\nInt5 = 5\nUInt1 = 1\nUInt2 = 2\nUInt3 = 3\nUInt4 = 4\nUInt5 = 5\nFlt1 = 1.0\nFlt2 = 2.0",
"Int1 = 1\nInt2 = 2\nInt3 = []\nInt4 = 4\nInt5 = 5\nUInt1 = 1\nUInt2 = 2\nUInt3 = 3\nUInt4 = 4\nUInt5 = 5\nFlt1 = 1.0\nFlt2 = 2.0",
"Int1 = 1\nInt2 = 2\nInt3 = 3\nInt4 = []\nInt5 = 5\nUInt1 = 1\nUInt2 = 2\nUInt3 = 3\nUInt4 = 4\nUInt5 = 5\nFlt1 = 1.0\nFlt2 = 2.0",
"Int1 = 1\nInt2 = 2\nInt3 = 3\nInt4 = 4\nInt5 = []\nUInt1 = 1\nUInt2 = 2\nUInt3 = 3\nUInt4 = 4\nUInt5 = 5\nFlt1 = 1.0\nFlt2 = 2.0",
"Int1 = 1\nInt2 = 2\nInt3 = 3\nInt4 = 4\nInt5 = 5\nUInt1 = []\nUInt2 = 2\nUInt3 = 3\nUInt4 = 4\nUInt5 = 5\nFlt1 = 1.0\nFlt2 = 2.0",
"Int1 = 1\nInt2 = 2\nInt3 = 3\nInt4 = 4\nInt5 = 5\nUInt1 = 1\nUInt2 = []\nUInt3 = 3\nUInt4 = 4\nUInt5 = 5\nFlt1 = 1.0\nFlt2 = 2.0",
"Int1 = 1\nInt2 = 2\nInt3 = 3\nInt4 = 4\nInt5 = 5\nUInt1 = 1\nUInt2 = 2\nUInt3 = []\nUInt4 = 4\nUInt5 = 5\nFlt1 = 1.0\nFlt2 = 2.0",
"Int1 = 1\nInt2 = 2\nInt3 = 3\nInt4 = 4\nInt5 = 5\nUInt1 = 1\nUInt2 = 2\nUInt3 = 3\nUInt4 = []\nUInt5 = 5\nFlt1 = 1.0\nFlt2 = 2.0",
"Int1 = 1\nInt2 = 2\nInt3 = 3\nInt4 = 4\nInt5 = 5\nUInt1 = 1\nUInt2 = 2\nUInt3 = 3\nUInt4 = 4\nUInt5 = []\nFlt1 = 1.0\nFlt2 = 2.0",
"Int1 = 1\nInt2 = 2\nInt3 = 3\nInt4 = 4\nInt5 = 5\nUInt1 = 1\nUInt2 = 2\nUInt3 = 3\nUInt4 = 4\nUInt5 = 5\nFlt1 = []\nFlt2 = 2.0",
"Int1 = 1\nInt2 = 2\nInt3 = 3\nInt4 = 4\nInt5 = 5\nUInt1 = 1\nUInt2 = 2\nUInt3 = 3\nUInt4 = 4\nUInt5 = 5\nFlt1 = 1.0\nFlt2 = []",
}
func TestErrUnmarshal(t *testing.T) {
for ind, toml := range errTomls {
result := errStruct{}
err := Unmarshal([]byte(toml), &result)
if err == nil {
t.Errorf("Expected err from case %d\n", ind)
}
}
result2 := mapErr{}
err := Unmarshal([]byte("[Vals]\nfred=\"1.2\""), &result2)
if err == nil {
t.Errorf("Expected err from map")
}
for ind, toml := range intErrTomls {
result3 := intErr{}
err := Unmarshal([]byte(toml), &result3)
if err == nil {
t.Errorf("Expected int err from case %d\n", ind)
}
}
}
type emptyMarshalTestStruct struct {
Title string `toml:"title"`
Bool bool `toml:"bool"`
Int int `toml:"int"`
String string `toml:"string"`
StringList []string `toml:"stringlist"`
Ptr *basicMarshalTestStruct `toml:"ptr"`
Map map[string]string `toml:"map"`
}
var emptyTestData = emptyMarshalTestStruct{
Title: "Placeholder",
Bool: false,
Int: 0,
String: "",
StringList: []string{},
Ptr: nil,
Map: map[string]string{},
}
var emptyTestToml = []byte(`bool = false
int = 0
string = ""
stringlist = []
title = "Placeholder"
[map]
`)
type emptyMarshalTestStruct2 struct {
Title string `toml:"title"`
Bool bool `toml:"bool,omitempty"`
Int int `toml:"int, omitempty"`
String string `toml:"string,omitempty "`
StringList []string `toml:"stringlist,omitempty"`
Ptr *basicMarshalTestStruct `toml:"ptr,omitempty"`
Map map[string]string `toml:"map,omitempty"`
}
var emptyTestData2 = emptyMarshalTestStruct2{
Title: "Placeholder",
Bool: false,
Int: 0,
String: "",
StringList: []string{},
Ptr: nil,
Map: map[string]string{},
}
var emptyTestToml2 = []byte(`title = "Placeholder"
`)
func TestEmptyMarshal(t *testing.T) {
result, err := Marshal(emptyTestData)
if err != nil {
t.Fatal(err)
}
expected := emptyTestToml
if !bytes.Equal(result, expected) {
t.Errorf("Bad empty marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result)
}
}
func TestEmptyMarshalOmit(t *testing.T) {
result, err := Marshal(emptyTestData2)
if err != nil {
t.Fatal(err)
}
expected := emptyTestToml2
if !bytes.Equal(result, expected) {
t.Errorf("Bad empty omit marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result)
}
}
func TestEmptyUnmarshal(t *testing.T) {
result := emptyMarshalTestStruct{}
err := Unmarshal(emptyTestToml, &result)
expected := emptyTestData
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(result, expected) {
t.Errorf("Bad empty unmarshal: expected %v, got %v", expected, result)
}
}
func TestEmptyUnmarshalOmit(t *testing.T) {
result := emptyMarshalTestStruct2{}
err := Unmarshal(emptyTestToml, &result)
expected := emptyTestData2
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(result, expected) {
t.Errorf("Bad empty omit unmarshal: expected %v, got %v", expected, result)
}
}
type pointerMarshalTestStruct struct {
Str *string
List *[]string
ListPtr *[]*string
Map *map[string]string
MapPtr *map[string]*string
EmptyStr *string
EmptyList *[]string
EmptyMap *map[string]string
DblPtr *[]*[]*string
}
var pointerStr = "Hello"
var pointerList = []string{"Hello back"}
var pointerListPtr = []*string{&pointerStr}
var pointerMap = map[string]string{"response": "Goodbye"}
var pointerMapPtr = map[string]*string{"alternate": &pointerStr}
var pointerTestData = pointerMarshalTestStruct{
Str: &pointerStr,
List: &pointerList,
ListPtr: &pointerListPtr,
Map: &pointerMap,
MapPtr: &pointerMapPtr,
EmptyStr: nil,
EmptyList: nil,
EmptyMap: nil,
}
var pointerTestToml = []byte(`List = ["Hello back"]
ListPtr = ["Hello"]
Str = "Hello"
[Map]
response = "Goodbye"
[MapPtr]
alternate = "Hello"
`)
func TestPointerMarshal(t *testing.T) {
result, err := Marshal(pointerTestData)
if err != nil {
t.Fatal(err)
}
expected := pointerTestToml
if !bytes.Equal(result, expected) {
t.Errorf("Bad pointer marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result)
}
}
func TestPointerUnmarshal(t *testing.T) {
result := pointerMarshalTestStruct{}
err := Unmarshal(pointerTestToml, &result)
expected := pointerTestData
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(result, expected) {
t.Errorf("Bad pointer unmarshal: expected %v, got %v", expected, result)
}
}
type nestedMarshalTestStruct struct {
String [][]string
//Struct [][]basicMarshalTestSubStruct
StringPtr *[]*[]*string
// StructPtr *[]*[]*basicMarshalTestSubStruct
}
var str1 = "Three"
var str2 = "Four"
var strPtr = []*string{&str1, &str2}
var strPtr2 = []*[]*string{&strPtr}
var nestedTestData = nestedMarshalTestStruct{
String: [][]string{[]string{"Five", "Six"}, []string{"One", "Two"}},
StringPtr: &strPtr2,
}
var nestedTestToml = []byte(`String = [["Five","Six"],["One","Two"]]
StringPtr = [["Three","Four"]]
`)
func TestNestedMarshal(t *testing.T) {
result, err := Marshal(nestedTestData)
if err != nil {
t.Fatal(err)
}
expected := nestedTestToml
if !bytes.Equal(result, expected) {
t.Errorf("Bad nested marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, result)
}
}
func TestNestedUnmarshal(t *testing.T) {
result := nestedMarshalTestStruct{}
err := Unmarshal(nestedTestToml, &result)
expected := nestedTestData
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(result, expected) {
t.Errorf("Bad nested unmarshal: expected %v, got %v", expected, result)
}
}

38
vendor/github.com/pelletier/go-toml/marshal_test.toml generated vendored Normal file
View File

@@ -0,0 +1,38 @@
title = "TOML Marshal Testing"
[basic]
bool = true
date = 1979-05-27T07:32:00Z
float = 123.4
int = 5000
string = "Bite me"
uint = 5001
[basic_lists]
bools = [true,false,true]
dates = [1979-05-27T07:32:00Z,1980-05-27T07:32:00Z]
floats = [12.3,45.6,78.9]
ints = [8001,8001,8002]
strings = ["One","Two","Three"]
uints = [5002,5003]
[basic_map]
one = "one"
two = "two"
[subdoc]
[subdoc.first]
name = "First"
[subdoc.second]
name = "Second"
[[subdoclist]]
name = "List.First"
[[subdoclist]]
name = "List.Second"
[[subdocptrs]]
name = "Second"

View File

@@ -33,32 +33,32 @@ var (
ISO8859_8I encoding.Encoding = &iso8859_8I
iso8859_6E = internal.Encoding{
ISO8859_6,
"ISO-8859-6E",
identifier.ISO88596E,
Encoding: ISO8859_6,
Name: "ISO-8859-6E",
MIB: identifier.ISO88596E,
}
iso8859_6I = internal.Encoding{
ISO8859_6,
"ISO-8859-6I",
identifier.ISO88596I,
Encoding: ISO8859_6,
Name: "ISO-8859-6I",
MIB: identifier.ISO88596I,
}
iso8859_8E = internal.Encoding{
ISO8859_8,
"ISO-8859-8E",
identifier.ISO88598E,
Encoding: ISO8859_8,
Name: "ISO-8859-8E",
MIB: identifier.ISO88598E,
}
iso8859_8I = internal.Encoding{
ISO8859_8,
"ISO-8859-8I",
identifier.ISO88598I,
Encoding: ISO8859_8,
Name: "ISO-8859-8I",
MIB: identifier.ISO88598I,
}
)
// All is a list of all defined encodings in this package.
var All = listAll
var All []encoding.Encoding = listAll
// TODO: implement these encodings, in order of importance.
// ASCII, ISO8859_1: Rather common. Close to Windows 1252.
@@ -70,8 +70,8 @@ type utf8Enc struct {
data [3]byte
}
// charmap describes an 8-bit character set encoding.
type charmap struct {
// Charmap is an 8-bit character set encoding.
type Charmap struct {
// name is the encoding's name.
name string
// mib is the encoding type of this encoder.
@@ -79,7 +79,7 @@ type charmap struct {
// asciiSuperset states whether the encoding is a superset of ASCII.
asciiSuperset bool
// low is the lower bound of the encoded byte for a non-ASCII rune. If
// charmap.asciiSuperset is true then this will be 0x80, otherwise 0x00.
// Charmap.asciiSuperset is true then this will be 0x80, otherwise 0x00.
low uint8
// replacement is the encoded replacement character.
replacement byte
@@ -91,26 +91,30 @@ type charmap struct {
encode [256]uint32
}
func (m *charmap) NewDecoder() *encoding.Decoder {
// NewDecoder implements the encoding.Encoding interface.
func (m *Charmap) NewDecoder() *encoding.Decoder {
return &encoding.Decoder{Transformer: charmapDecoder{charmap: m}}
}
func (m *charmap) NewEncoder() *encoding.Encoder {
// NewEncoder implements the encoding.Encoding interface.
func (m *Charmap) NewEncoder() *encoding.Encoder {
return &encoding.Encoder{Transformer: charmapEncoder{charmap: m}}
}
func (m *charmap) String() string {
// String returns the Charmap's name.
func (m *Charmap) String() string {
return m.name
}
func (m *charmap) ID() (mib identifier.MIB, other string) {
// ID implements an internal interface.
func (m *Charmap) ID() (mib identifier.MIB, other string) {
return m.mib, ""
}
// charmapDecoder implements transform.Transformer by decoding to UTF-8.
type charmapDecoder struct {
transform.NopResetter
charmap *charmap
charmap *Charmap
}
func (m charmapDecoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
@@ -142,10 +146,22 @@ func (m charmapDecoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int,
return nDst, nSrc, err
}
// DecodeByte returns the Charmap's rune decoding of the byte b.
func (m *Charmap) DecodeByte(b byte) rune {
switch x := &m.decode[b]; x.len {
case 1:
return rune(x.data[0])
case 2:
return rune(x.data[0]&0x1f)<<6 | rune(x.data[1]&0x3f)
default:
return rune(x.data[0]&0x0f)<<12 | rune(x.data[1]&0x3f)<<6 | rune(x.data[2]&0x3f)
}
}
// charmapEncoder implements transform.Transformer by encoding from UTF-8.
type charmapEncoder struct {
transform.NopResetter
charmap *charmap
charmap *Charmap
}
func (m charmapEncoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
@@ -207,3 +223,27 @@ loop:
}
return nDst, nSrc, err
}
// EncodeRune returns the Charmap's byte encoding of the rune r. ok is whether
// r is in the Charmap's repertoire. If not, b is set to the Charmap's
// replacement byte. This is often the ASCII substitute character '\x1a'.
func (m *Charmap) EncodeRune(r rune) (b byte, ok bool) {
if r < utf8.RuneSelf && m.asciiSuperset {
return byte(r), true
}
for low, high := int(m.low), 0x100; ; {
if low >= high {
return m.replacement, false
}
mid := (low + high) / 2
got := m.encode[mid]
gotRune := rune(got & (1<<24 - 1))
if gotRune < r {
low = mid + 1
} else if gotRune > r {
high = mid
} else {
return byte(got >> 24), true
}
}
}

View File

@@ -16,9 +16,11 @@ import (
func dec(e encoding.Encoding) (dir string, t transform.Transformer, err error) {
return "Decode", e.NewDecoder(), nil
}
func encASCIISuperset(e encoding.Encoding) (dir string, t transform.Transformer, err error) {
return "Encode", e.NewEncoder(), internal.ErrASCIIReplacement
}
func encEBCDIC(e encoding.Encoding) (dir string, t transform.Transformer, err error) {
return "Encode", e.NewEncoder(), internal.RepertoireError(0x3f)
}
@@ -200,6 +202,57 @@ func TestBasics(t *testing.T) {
}
}
var windows1255TestCases = []struct {
b byte
ok bool
r rune
}{
{'\x00', true, '\u0000'},
{'\x1a', true, '\u001a'},
{'\x61', true, '\u0061'},
{'\x7f', true, '\u007f'},
{'\x80', true, '\u20ac'},
{'\x95', true, '\u2022'},
{'\xa0', true, '\u00a0'},
{'\xc0', true, '\u05b0'},
{'\xfc', true, '\ufffd'},
{'\xfd', true, '\u200e'},
{'\xfe', true, '\u200f'},
{'\xff', true, '\ufffd'},
{encoding.ASCIISub, false, '\u0400'},
{encoding.ASCIISub, false, '\u2603'},
{encoding.ASCIISub, false, '\U0001f4a9'},
}
func TestDecodeByte(t *testing.T) {
for _, tc := range windows1255TestCases {
if !tc.ok {
continue
}
got := Windows1255.DecodeByte(tc.b)
want := tc.r
if got != want {
t.Errorf("DecodeByte(%#02x): got %#08x, want %#08x", tc.b, got, want)
}
}
}
func TestEncodeRune(t *testing.T) {
for _, tc := range windows1255TestCases {
// There can be multiple tc.b values that map to tc.r = '\ufffd'.
if tc.r == '\ufffd' {
continue
}
gotB, gotOK := Windows1255.EncodeRune(tc.r)
wantB, wantOK := tc.b, tc.ok
if gotB != wantB || gotOK != wantOK {
t.Errorf("EncodeRune(%#08x): got (%#02x, %t), want (%#02x, %t)", tc.r, gotB, gotOK, wantB, wantOK)
}
}
}
func TestFiles(t *testing.T) { enctest.TestFile(t, Windows1252) }
func BenchmarkEncoding(b *testing.B) { enctest.Benchmark(b, Windows1252) }

View File

@@ -494,7 +494,7 @@ func main() {
if e.comment != "" {
printf("//\n// %s\n", e.comment)
}
printf("var %s encoding.Encoding = &%s\n\nvar %s = charmap{\nname: %q,\n",
printf("var %s *Charmap = &%s\n\nvar %s = Charmap{\nname: %q,\n",
varName, lowerVarName, lowerVarName, e.name)
if mibs[e.mib] {
log.Fatalf("MIB type %q declared multiple times.", e.mib)
@@ -540,7 +540,7 @@ func main() {
}
printf("},\n}\n")
// Add an estimate of the size of a single charmap{} struct value, which
// Add an estimate of the size of a single Charmap{} struct value, which
// includes two 256 elem arrays of 4 bytes and some extra fields, which
// align to 3 uint64s on 64-bit architectures.
w.Size += 2*4*256 + 3*8

View File

@@ -1,4 +1,4 @@
// This file was generated by go generate; DO NOT EDIT
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
package charmap
@@ -8,9 +8,9 @@ import (
)
// CodePage037 is the IBM Code Page 037 encoding.
var CodePage037 encoding.Encoding = &codePage037
var CodePage037 *Charmap = &codePage037
var codePage037 = charmap{
var codePage037 = Charmap{
name: "IBM Code Page 037",
mib: identifier.IBM037,
asciiSuperset: false,
@@ -183,9 +183,9 @@ var codePage037 = charmap{
}
// CodePage437 is the IBM Code Page 437 encoding.
var CodePage437 encoding.Encoding = &codePage437
var CodePage437 *Charmap = &codePage437
var codePage437 = charmap{
var codePage437 = Charmap{
name: "IBM Code Page 437",
mib: identifier.PC8CodePage437,
asciiSuperset: true,
@@ -358,9 +358,9 @@ var codePage437 = charmap{
}
// CodePage850 is the IBM Code Page 850 encoding.
var CodePage850 encoding.Encoding = &codePage850
var CodePage850 *Charmap = &codePage850
var codePage850 = charmap{
var codePage850 = Charmap{
name: "IBM Code Page 850",
mib: identifier.PC850Multilingual,
asciiSuperset: true,
@@ -533,9 +533,9 @@ var codePage850 = charmap{
}
// CodePage852 is the IBM Code Page 852 encoding.
var CodePage852 encoding.Encoding = &codePage852
var CodePage852 *Charmap = &codePage852
var codePage852 = charmap{
var codePage852 = Charmap{
name: "IBM Code Page 852",
mib: identifier.PCp852,
asciiSuperset: true,
@@ -708,9 +708,9 @@ var codePage852 = charmap{
}
// CodePage855 is the IBM Code Page 855 encoding.
var CodePage855 encoding.Encoding = &codePage855
var CodePage855 *Charmap = &codePage855
var codePage855 = charmap{
var codePage855 = Charmap{
name: "IBM Code Page 855",
mib: identifier.IBM855,
asciiSuperset: true,
@@ -883,9 +883,9 @@ var codePage855 = charmap{
}
// CodePage858 is the Windows Code Page 858 encoding.
var CodePage858 encoding.Encoding = &codePage858
var CodePage858 *Charmap = &codePage858
var codePage858 = charmap{
var codePage858 = Charmap{
name: "Windows Code Page 858",
mib: identifier.IBM00858,
asciiSuperset: true,
@@ -1058,9 +1058,9 @@ var codePage858 = charmap{
}
// CodePage860 is the IBM Code Page 860 encoding.
var CodePage860 encoding.Encoding = &codePage860
var CodePage860 *Charmap = &codePage860
var codePage860 = charmap{
var codePage860 = Charmap{
name: "IBM Code Page 860",
mib: identifier.IBM860,
asciiSuperset: true,
@@ -1233,9 +1233,9 @@ var codePage860 = charmap{
}
// CodePage862 is the IBM Code Page 862 encoding.
var CodePage862 encoding.Encoding = &codePage862
var CodePage862 *Charmap = &codePage862
var codePage862 = charmap{
var codePage862 = Charmap{
name: "IBM Code Page 862",
mib: identifier.PC862LatinHebrew,
asciiSuperset: true,
@@ -1408,9 +1408,9 @@ var codePage862 = charmap{
}
// CodePage863 is the IBM Code Page 863 encoding.
var CodePage863 encoding.Encoding = &codePage863
var CodePage863 *Charmap = &codePage863
var codePage863 = charmap{
var codePage863 = Charmap{
name: "IBM Code Page 863",
mib: identifier.IBM863,
asciiSuperset: true,
@@ -1583,9 +1583,9 @@ var codePage863 = charmap{
}
// CodePage865 is the IBM Code Page 865 encoding.
var CodePage865 encoding.Encoding = &codePage865
var CodePage865 *Charmap = &codePage865
var codePage865 = charmap{
var codePage865 = Charmap{
name: "IBM Code Page 865",
mib: identifier.IBM865,
asciiSuperset: true,
@@ -1758,9 +1758,9 @@ var codePage865 = charmap{
}
// CodePage866 is the IBM Code Page 866 encoding.
var CodePage866 encoding.Encoding = &codePage866
var CodePage866 *Charmap = &codePage866
var codePage866 = charmap{
var codePage866 = Charmap{
name: "IBM Code Page 866",
mib: identifier.IBM866,
asciiSuperset: true,
@@ -1933,9 +1933,9 @@ var codePage866 = charmap{
}
// CodePage1047 is the IBM Code Page 1047 encoding.
var CodePage1047 encoding.Encoding = &codePage1047
var CodePage1047 *Charmap = &codePage1047
var codePage1047 = charmap{
var codePage1047 = Charmap{
name: "IBM Code Page 1047",
mib: identifier.IBM1047,
asciiSuperset: false,
@@ -2108,9 +2108,9 @@ var codePage1047 = charmap{
}
// CodePage1140 is the IBM Code Page 1140 encoding.
var CodePage1140 encoding.Encoding = &codePage1140
var CodePage1140 *Charmap = &codePage1140
var codePage1140 = charmap{
var codePage1140 = Charmap{
name: "IBM Code Page 1140",
mib: identifier.IBM01140,
asciiSuperset: false,
@@ -2283,9 +2283,9 @@ var codePage1140 = charmap{
}
// ISO8859_1 is the ISO 8859-1 encoding.
var ISO8859_1 encoding.Encoding = &iso8859_1
var ISO8859_1 *Charmap = &iso8859_1
var iso8859_1 = charmap{
var iso8859_1 = Charmap{
name: "ISO 8859-1",
mib: identifier.ISOLatin1,
asciiSuperset: true,
@@ -2458,9 +2458,9 @@ var iso8859_1 = charmap{
}
// ISO8859_2 is the ISO 8859-2 encoding.
var ISO8859_2 encoding.Encoding = &iso8859_2
var ISO8859_2 *Charmap = &iso8859_2
var iso8859_2 = charmap{
var iso8859_2 = Charmap{
name: "ISO 8859-2",
mib: identifier.ISOLatin2,
asciiSuperset: true,
@@ -2633,9 +2633,9 @@ var iso8859_2 = charmap{
}
// ISO8859_3 is the ISO 8859-3 encoding.
var ISO8859_3 encoding.Encoding = &iso8859_3
var ISO8859_3 *Charmap = &iso8859_3
var iso8859_3 = charmap{
var iso8859_3 = Charmap{
name: "ISO 8859-3",
mib: identifier.ISOLatin3,
asciiSuperset: true,
@@ -2808,9 +2808,9 @@ var iso8859_3 = charmap{
}
// ISO8859_4 is the ISO 8859-4 encoding.
var ISO8859_4 encoding.Encoding = &iso8859_4
var ISO8859_4 *Charmap = &iso8859_4
var iso8859_4 = charmap{
var iso8859_4 = Charmap{
name: "ISO 8859-4",
mib: identifier.ISOLatin4,
asciiSuperset: true,
@@ -2983,9 +2983,9 @@ var iso8859_4 = charmap{
}
// ISO8859_5 is the ISO 8859-5 encoding.
var ISO8859_5 encoding.Encoding = &iso8859_5
var ISO8859_5 *Charmap = &iso8859_5
var iso8859_5 = charmap{
var iso8859_5 = Charmap{
name: "ISO 8859-5",
mib: identifier.ISOLatinCyrillic,
asciiSuperset: true,
@@ -3158,9 +3158,9 @@ var iso8859_5 = charmap{
}
// ISO8859_6 is the ISO 8859-6 encoding.
var ISO8859_6 encoding.Encoding = &iso8859_6
var ISO8859_6 *Charmap = &iso8859_6
var iso8859_6 = charmap{
var iso8859_6 = Charmap{
name: "ISO 8859-6",
mib: identifier.ISOLatinArabic,
asciiSuperset: true,
@@ -3333,9 +3333,9 @@ var iso8859_6 = charmap{
}
// ISO8859_7 is the ISO 8859-7 encoding.
var ISO8859_7 encoding.Encoding = &iso8859_7
var ISO8859_7 *Charmap = &iso8859_7
var iso8859_7 = charmap{
var iso8859_7 = Charmap{
name: "ISO 8859-7",
mib: identifier.ISOLatinGreek,
asciiSuperset: true,
@@ -3508,9 +3508,9 @@ var iso8859_7 = charmap{
}
// ISO8859_8 is the ISO 8859-8 encoding.
var ISO8859_8 encoding.Encoding = &iso8859_8
var ISO8859_8 *Charmap = &iso8859_8
var iso8859_8 = charmap{
var iso8859_8 = Charmap{
name: "ISO 8859-8",
mib: identifier.ISOLatinHebrew,
asciiSuperset: true,
@@ -3683,9 +3683,9 @@ var iso8859_8 = charmap{
}
// ISO8859_9 is the ISO 8859-9 encoding.
var ISO8859_9 encoding.Encoding = &iso8859_9
var ISO8859_9 *Charmap = &iso8859_9
var iso8859_9 = charmap{
var iso8859_9 = Charmap{
name: "ISO 8859-9",
mib: identifier.ISOLatin5,
asciiSuperset: true,
@@ -3858,9 +3858,9 @@ var iso8859_9 = charmap{
}
// ISO8859_10 is the ISO 8859-10 encoding.
var ISO8859_10 encoding.Encoding = &iso8859_10
var ISO8859_10 *Charmap = &iso8859_10
var iso8859_10 = charmap{
var iso8859_10 = Charmap{
name: "ISO 8859-10",
mib: identifier.ISOLatin6,
asciiSuperset: true,
@@ -4033,9 +4033,9 @@ var iso8859_10 = charmap{
}
// ISO8859_13 is the ISO 8859-13 encoding.
var ISO8859_13 encoding.Encoding = &iso8859_13
var ISO8859_13 *Charmap = &iso8859_13
var iso8859_13 = charmap{
var iso8859_13 = Charmap{
name: "ISO 8859-13",
mib: identifier.ISO885913,
asciiSuperset: true,
@@ -4208,9 +4208,9 @@ var iso8859_13 = charmap{
}
// ISO8859_14 is the ISO 8859-14 encoding.
var ISO8859_14 encoding.Encoding = &iso8859_14
var ISO8859_14 *Charmap = &iso8859_14
var iso8859_14 = charmap{
var iso8859_14 = Charmap{
name: "ISO 8859-14",
mib: identifier.ISO885914,
asciiSuperset: true,
@@ -4383,9 +4383,9 @@ var iso8859_14 = charmap{
}
// ISO8859_15 is the ISO 8859-15 encoding.
var ISO8859_15 encoding.Encoding = &iso8859_15
var ISO8859_15 *Charmap = &iso8859_15
var iso8859_15 = charmap{
var iso8859_15 = Charmap{
name: "ISO 8859-15",
mib: identifier.ISO885915,
asciiSuperset: true,
@@ -4558,9 +4558,9 @@ var iso8859_15 = charmap{
}
// ISO8859_16 is the ISO 8859-16 encoding.
var ISO8859_16 encoding.Encoding = &iso8859_16
var ISO8859_16 *Charmap = &iso8859_16
var iso8859_16 = charmap{
var iso8859_16 = Charmap{
name: "ISO 8859-16",
mib: identifier.ISO885916,
asciiSuperset: true,
@@ -4733,9 +4733,9 @@ var iso8859_16 = charmap{
}
// KOI8R is the KOI8-R encoding.
var KOI8R encoding.Encoding = &koi8R
var KOI8R *Charmap = &koi8R
var koi8R = charmap{
var koi8R = Charmap{
name: "KOI8-R",
mib: identifier.KOI8R,
asciiSuperset: true,
@@ -4908,9 +4908,9 @@ var koi8R = charmap{
}
// KOI8U is the KOI8-U encoding.
var KOI8U encoding.Encoding = &koi8U
var KOI8U *Charmap = &koi8U
var koi8U = charmap{
var koi8U = Charmap{
name: "KOI8-U",
mib: identifier.KOI8U,
asciiSuperset: true,
@@ -5083,9 +5083,9 @@ var koi8U = charmap{
}
// Macintosh is the Macintosh encoding.
var Macintosh encoding.Encoding = &macintosh
var Macintosh *Charmap = &macintosh
var macintosh = charmap{
var macintosh = Charmap{
name: "Macintosh",
mib: identifier.Macintosh,
asciiSuperset: true,
@@ -5258,9 +5258,9 @@ var macintosh = charmap{
}
// MacintoshCyrillic is the Macintosh Cyrillic encoding.
var MacintoshCyrillic encoding.Encoding = &macintoshCyrillic
var MacintoshCyrillic *Charmap = &macintoshCyrillic
var macintoshCyrillic = charmap{
var macintoshCyrillic = Charmap{
name: "Macintosh Cyrillic",
mib: identifier.MacintoshCyrillic,
asciiSuperset: true,
@@ -5433,9 +5433,9 @@ var macintoshCyrillic = charmap{
}
// Windows874 is the Windows 874 encoding.
var Windows874 encoding.Encoding = &windows874
var Windows874 *Charmap = &windows874
var windows874 = charmap{
var windows874 = Charmap{
name: "Windows 874",
mib: identifier.Windows874,
asciiSuperset: true,
@@ -5608,9 +5608,9 @@ var windows874 = charmap{
}
// Windows1250 is the Windows 1250 encoding.
var Windows1250 encoding.Encoding = &windows1250
var Windows1250 *Charmap = &windows1250
var windows1250 = charmap{
var windows1250 = Charmap{
name: "Windows 1250",
mib: identifier.Windows1250,
asciiSuperset: true,
@@ -5783,9 +5783,9 @@ var windows1250 = charmap{
}
// Windows1251 is the Windows 1251 encoding.
var Windows1251 encoding.Encoding = &windows1251
var Windows1251 *Charmap = &windows1251
var windows1251 = charmap{
var windows1251 = Charmap{
name: "Windows 1251",
mib: identifier.Windows1251,
asciiSuperset: true,
@@ -5958,9 +5958,9 @@ var windows1251 = charmap{
}
// Windows1252 is the Windows 1252 encoding.
var Windows1252 encoding.Encoding = &windows1252
var Windows1252 *Charmap = &windows1252
var windows1252 = charmap{
var windows1252 = Charmap{
name: "Windows 1252",
mib: identifier.Windows1252,
asciiSuperset: true,
@@ -6133,9 +6133,9 @@ var windows1252 = charmap{
}
// Windows1253 is the Windows 1253 encoding.
var Windows1253 encoding.Encoding = &windows1253
var Windows1253 *Charmap = &windows1253
var windows1253 = charmap{
var windows1253 = Charmap{
name: "Windows 1253",
mib: identifier.Windows1253,
asciiSuperset: true,
@@ -6308,9 +6308,9 @@ var windows1253 = charmap{
}
// Windows1254 is the Windows 1254 encoding.
var Windows1254 encoding.Encoding = &windows1254
var Windows1254 *Charmap = &windows1254
var windows1254 = charmap{
var windows1254 = Charmap{
name: "Windows 1254",
mib: identifier.Windows1254,
asciiSuperset: true,
@@ -6483,9 +6483,9 @@ var windows1254 = charmap{
}
// Windows1255 is the Windows 1255 encoding.
var Windows1255 encoding.Encoding = &windows1255
var Windows1255 *Charmap = &windows1255
var windows1255 = charmap{
var windows1255 = Charmap{
name: "Windows 1255",
mib: identifier.Windows1255,
asciiSuperset: true,
@@ -6593,7 +6593,7 @@ var windows1255 = charmap{
{2, [3]byte{0xd6, 0xb4, 0x00}}, {2, [3]byte{0xd6, 0xb5, 0x00}},
{2, [3]byte{0xd6, 0xb6, 0x00}}, {2, [3]byte{0xd6, 0xb7, 0x00}},
{2, [3]byte{0xd6, 0xb8, 0x00}}, {2, [3]byte{0xd6, 0xb9, 0x00}},
{3, [3]byte{0xef, 0xbf, 0xbd}}, {2, [3]byte{0xd6, 0xbb, 0x00}},
{2, [3]byte{0xd6, 0xba, 0x00}}, {2, [3]byte{0xd6, 0xbb, 0x00}},
{2, [3]byte{0xd6, 0xbc, 0x00}}, {2, [3]byte{0xd6, 0xbd, 0x00}},
{2, [3]byte{0xd6, 0xbe, 0x00}}, {2, [3]byte{0xd6, 0xbf, 0x00}},
{2, [3]byte{0xd7, 0x80, 0x00}}, {2, [3]byte{0xd7, 0x81, 0x00}},
@@ -6643,24 +6643,24 @@ var windows1255 = charmap{
0xb20000b2, 0xb30000b3, 0xb40000b4, 0xb50000b5, 0xb60000b6, 0xb70000b7, 0xb80000b8, 0xb90000b9,
0xbb0000bb, 0xbc0000bc, 0xbd0000bd, 0xbe0000be, 0xbf0000bf, 0xaa0000d7, 0xba0000f7, 0x83000192,
0x880002c6, 0x980002dc, 0xc00005b0, 0xc10005b1, 0xc20005b2, 0xc30005b3, 0xc40005b4, 0xc50005b5,
0xc60005b6, 0xc70005b7, 0xc80005b8, 0xc90005b9, 0xcb0005bb, 0xcc0005bc, 0xcd0005bd, 0xce0005be,
0xcf0005bf, 0xd00005c0, 0xd10005c1, 0xd20005c2, 0xd30005c3, 0xe00005d0, 0xe10005d1, 0xe20005d2,
0xe30005d3, 0xe40005d4, 0xe50005d5, 0xe60005d6, 0xe70005d7, 0xe80005d8, 0xe90005d9, 0xea0005da,
0xeb0005db, 0xec0005dc, 0xed0005dd, 0xee0005de, 0xef0005df, 0xf00005e0, 0xf10005e1, 0xf20005e2,
0xf30005e3, 0xf40005e4, 0xf50005e5, 0xf60005e6, 0xf70005e7, 0xf80005e8, 0xf90005e9, 0xfa0005ea,
0xd40005f0, 0xd50005f1, 0xd60005f2, 0xd70005f3, 0xd80005f4, 0xfd00200e, 0xfe00200f, 0x96002013,
0x97002014, 0x91002018, 0x92002019, 0x8200201a, 0x9300201c, 0x9400201d, 0x8400201e, 0x86002020,
0x87002021, 0x95002022, 0x85002026, 0x89002030, 0x8b002039, 0x9b00203a, 0xa40020aa, 0x800020ac,
0x99002122, 0x99002122, 0x99002122, 0x99002122, 0x99002122, 0x99002122, 0x99002122, 0x99002122,
0xc60005b6, 0xc70005b7, 0xc80005b8, 0xc90005b9, 0xca0005ba, 0xcb0005bb, 0xcc0005bc, 0xcd0005bd,
0xce0005be, 0xcf0005bf, 0xd00005c0, 0xd10005c1, 0xd20005c2, 0xd30005c3, 0xe00005d0, 0xe10005d1,
0xe20005d2, 0xe30005d3, 0xe40005d4, 0xe50005d5, 0xe60005d6, 0xe70005d7, 0xe80005d8, 0xe90005d9,
0xea0005da, 0xeb0005db, 0xec0005dc, 0xed0005dd, 0xee0005de, 0xef0005df, 0xf00005e0, 0xf10005e1,
0xf20005e2, 0xf30005e3, 0xf40005e4, 0xf50005e5, 0xf60005e6, 0xf70005e7, 0xf80005e8, 0xf90005e9,
0xfa0005ea, 0xd40005f0, 0xd50005f1, 0xd60005f2, 0xd70005f3, 0xd80005f4, 0xfd00200e, 0xfe00200f,
0x96002013, 0x97002014, 0x91002018, 0x92002019, 0x8200201a, 0x9300201c, 0x9400201d, 0x8400201e,
0x86002020, 0x87002021, 0x95002022, 0x85002026, 0x89002030, 0x8b002039, 0x9b00203a, 0xa40020aa,
0x800020ac, 0x99002122, 0x99002122, 0x99002122, 0x99002122, 0x99002122, 0x99002122, 0x99002122,
0x99002122, 0x99002122, 0x99002122, 0x99002122, 0x99002122, 0x99002122, 0x99002122, 0x99002122,
0x99002122, 0x99002122, 0x99002122, 0x99002122, 0x99002122, 0x99002122, 0x99002122, 0x99002122,
},
}
// Windows1256 is the Windows 1256 encoding.
var Windows1256 encoding.Encoding = &windows1256
var Windows1256 *Charmap = &windows1256
var windows1256 = charmap{
var windows1256 = Charmap{
name: "Windows 1256",
mib: identifier.Windows1256,
asciiSuperset: true,
@@ -6833,9 +6833,9 @@ var windows1256 = charmap{
}
// Windows1257 is the Windows 1257 encoding.
var Windows1257 encoding.Encoding = &windows1257
var Windows1257 *Charmap = &windows1257
var windows1257 = charmap{
var windows1257 = Charmap{
name: "Windows 1257",
mib: identifier.Windows1257,
asciiSuperset: true,
@@ -7008,9 +7008,9 @@ var windows1257 = charmap{
}
// Windows1258 is the Windows 1258 encoding.
var Windows1258 encoding.Encoding = &windows1258
var Windows1258 *Charmap = &windows1258
var windows1258 = charmap{
var windows1258 = Charmap{
name: "Windows 1258",
mib: identifier.Windows1258,
asciiSuperset: true,
@@ -7185,9 +7185,9 @@ var windows1258 = charmap{
// XUserDefined is the X-User-Defined encoding.
//
// It is defined at http://encoding.spec.whatwg.org/#x-user-defined
var XUserDefined encoding.Encoding = &xUserDefined
var XUserDefined *Charmap = &xUserDefined
var xUserDefined = charmap{
var xUserDefined = Charmap{
name: "X-User-Defined",
mib: identifier.XUserDefined,
asciiSuperset: true,

View File

@@ -364,7 +364,7 @@ func genFormats(w *gen.CodeWriter, data *cldr.CLDR) {
}
// Fill the first slot with a dummy so we can identify unspecified tags.
formats := []number.Format{{}}
formats := []number.Pattern{{}}
patterns := map[string]int{}
// TODO: It would be possible to eliminate two of these slices by having

View File

@@ -136,7 +136,7 @@ func (n Info) Symbol(t SymbolType) string {
return symData.Elem(int(symIndex[n.symIndex][t]))
}
func formatForLang(t language.Tag, index []byte) *Format {
func formatForLang(t language.Tag, index []byte) *Pattern {
for ; ; t = t.Parent() {
if x, ok := language.CompactIndex(t); ok {
return &formats[index[x]]

View File

@@ -31,14 +31,14 @@ import (
// TODO: replace special characters in affixes (-, +, ¤) with control codes.
// Format holds information for formatting numbers. It is designed to hold
// Pattern holds information for formatting numbers. It is designed to hold
// information from CLDR number patterns.
//
// This pattern is precompiled for all patterns for all languages. Even though
// the number of patterns is not very large, we want to keep this small.
//
// This type is only intended for internal use.
type Format struct {
type Pattern struct {
// TODO: this struct can be packed a lot better than it is now. Should be
// possible to make it 32 bytes.
@@ -53,7 +53,7 @@ type Format struct {
FormatWidth uint16
GroupingSize [2]uint8
Flags FormatFlag
Flags PatternFlag
// Number of digits.
MinIntegerDigits uint8
@@ -65,11 +65,11 @@ type Format struct {
MinExponentDigits uint8
}
// A FormatFlag is a bit mask for the flag field of a Format.
type FormatFlag uint8
// A PatternFlag is a bit mask for the flag field of a Format.
type PatternFlag uint8
const (
AlwaysSign FormatFlag = 1 << iota
AlwaysSign PatternFlag = 1 << iota
AlwaysExpSign
AlwaysDecimalSeparator
ParenthesisForNegative // Common pattern. Saves space.
@@ -85,7 +85,7 @@ const (
)
type parser struct {
*Format
*Pattern
leadingSharps int
@@ -126,8 +126,8 @@ var (
// ParsePattern extracts formatting information from a CLDR number pattern.
//
// See http://unicode.org/reports/tr35/tr35-numbers.html#Number_Format_Patterns.
func ParsePattern(s string) (f *Format, err error) {
p := parser{Format: &Format{}}
func ParsePattern(s string) (f *Pattern, err error) {
p := parser{Pattern: &Pattern{}}
s = p.parseSubPattern(s)
@@ -137,7 +137,7 @@ func ParsePattern(s string) (f *Format, err error) {
p.setError(errors.New("format: error parsing first sub pattern"))
return nil, p.err
}
neg := parser{Format: &Format{}} // just for extracting the affixes.
neg := parser{Pattern: &Pattern{}} // just for extracting the affixes.
s = neg.parseSubPattern(s[len(";"):])
p.NegOffset = uint16(len(p.buf))
p.buf = append(p.buf, neg.buf...)
@@ -154,7 +154,7 @@ func ParsePattern(s string) (f *Format, err error) {
} else {
p.Affix = affix
}
return p.Format, nil
return p.Pattern, nil
}
func (p *parser) parseSubPattern(s string) string {
@@ -170,7 +170,7 @@ func (p *parser) parseSubPattern(s string) string {
return s
}
func (p *parser) parsePad(s string, f FormatFlag) (tail string) {
func (p *parser) parsePad(s string, f PatternFlag) (tail string) {
if len(s) >= 2 && s[0] == '*' {
r, sz := utf8.DecodeRuneInString(s[1:])
if p.PadRune != 0 {

View File

@@ -12,48 +12,48 @@ import (
var testCases = []struct {
pat string
want *Format
want *Pattern
}{{
"#",
&Format{
&Pattern{
FormatWidth: 1,
// TODO: Should MinIntegerDigits be 1?
},
}, {
"0",
&Format{
&Pattern{
FormatWidth: 1,
MinIntegerDigits: 1,
},
}, {
"0000",
&Format{
&Pattern{
FormatWidth: 4,
MinIntegerDigits: 4,
},
}, {
".#",
&Format{
&Pattern{
FormatWidth: 2,
MaxFractionDigits: 1,
},
}, {
"#0.###",
&Format{
&Pattern{
FormatWidth: 6,
MinIntegerDigits: 1,
MaxFractionDigits: 3,
},
}, {
"#0.######",
&Format{
&Pattern{
FormatWidth: 9,
MinIntegerDigits: 1,
MaxFractionDigits: 6,
},
}, {
"#,##0.###",
&Format{
&Pattern{
FormatWidth: 9,
GroupingSize: [2]uint8{3, 0},
MinIntegerDigits: 1,
@@ -61,7 +61,7 @@ var testCases = []struct {
},
}, {
"#,##,##0.###",
&Format{
&Pattern{
FormatWidth: 12,
GroupingSize: [2]uint8{3, 2},
MinIntegerDigits: 1,
@@ -70,7 +70,7 @@ var testCases = []struct {
}, {
// Ignore additional separators.
"#,####,##,##0.###",
&Format{
&Pattern{
FormatWidth: 17,
GroupingSize: [2]uint8{3, 2},
MinIntegerDigits: 1,
@@ -78,21 +78,21 @@ var testCases = []struct {
},
}, {
"#E0",
&Format{
&Pattern{
FormatWidth: 3,
MaxIntegerDigits: 1,
MinExponentDigits: 1,
},
}, {
"0E0",
&Format{
&Pattern{
FormatWidth: 3,
MinIntegerDigits: 1,
MinExponentDigits: 1,
},
}, {
"##00.0#E0",
&Format{
&Pattern{
FormatWidth: 9,
MinIntegerDigits: 2,
MaxIntegerDigits: 4,
@@ -102,7 +102,7 @@ var testCases = []struct {
},
}, {
"#00.0E+0",
&Format{
&Pattern{
FormatWidth: 8,
Flags: AlwaysExpSign,
MinIntegerDigits: 2,
@@ -120,7 +120,7 @@ var testCases = []struct {
}, {
// significant digits
"@",
&Format{
&Pattern{
FormatWidth: 1,
MinSignificantDigits: 1,
MaxSignificantDigits: 1,
@@ -128,14 +128,14 @@ var testCases = []struct {
}, {
// significant digits
"@@@@",
&Format{
&Pattern{
FormatWidth: 4,
MinSignificantDigits: 4,
MaxSignificantDigits: 4,
},
}, {
"@###",
&Format{
&Pattern{
FormatWidth: 4,
MinSignificantDigits: 1,
MaxSignificantDigits: 4,
@@ -143,7 +143,7 @@ var testCases = []struct {
}, {
// Exponents in significant digits mode gets normalized.
"@@E0",
&Format{
&Pattern{
FormatWidth: 4,
MinIntegerDigits: 1,
MaxIntegerDigits: 1,
@@ -153,7 +153,7 @@ var testCases = []struct {
},
}, {
"@###E00",
&Format{
&Pattern{
FormatWidth: 7,
MinIntegerDigits: 1,
MaxIntegerDigits: 1,
@@ -168,7 +168,7 @@ var testCases = []struct {
}, {
//alternative negative pattern
"#0.###;(#0.###)",
&Format{
&Pattern{
Affix: "\x00\x00\x01(\x01)",
NegOffset: 2,
FormatWidth: 6,
@@ -178,7 +178,7 @@ var testCases = []struct {
}, {
// Rounding increments
"1.05",
&Format{
&Pattern{
RoundIncrement: 105,
FormatWidth: 4,
MinIntegerDigits: 1,
@@ -187,7 +187,7 @@ var testCases = []struct {
},
}, {
"0.0%",
&Format{
&Pattern{
Affix: "\x00\x01%",
Multiplier: 100,
FormatWidth: 4,
@@ -197,7 +197,7 @@ var testCases = []struct {
},
}, {
"0.0‰",
&Format{
&Pattern{
Affix: "\x00\x03‰",
Multiplier: 1000,
FormatWidth: 4,
@@ -207,7 +207,7 @@ var testCases = []struct {
},
}, {
"#,##0.00¤",
&Format{
&Pattern{
Affix: "\x00\x02¤",
FormatWidth: 9,
GroupingSize: [2]uint8{3, 0},
@@ -217,7 +217,7 @@ var testCases = []struct {
},
}, {
"#,##0.00 ¤;(#,##0.00 ¤)",
&Format{Affix: "\x00\x04\u00a0¤\x01(\x05\u00a0¤)",
&Pattern{Affix: "\x00\x04\u00a0¤\x01(\x05\u00a0¤)",
NegOffset: 6,
Multiplier: 0,
FormatWidth: 10,
@@ -229,28 +229,28 @@ var testCases = []struct {
}, {
// padding
"*x#",
&Format{
&Pattern{
PadRune: 'x',
FormatWidth: 1,
},
}, {
// padding
"#*x",
&Format{
&Pattern{
PadRune: 'x',
FormatWidth: 1,
Flags: PadBeforeSuffix,
},
}, {
"*xpre#suf",
&Format{
&Pattern{
Affix: "\x03pre\x03suf",
PadRune: 'x',
FormatWidth: 7,
},
}, {
"pre*x#suf",
&Format{
&Pattern{
Affix: "\x03pre\x03suf",
PadRune: 'x',
FormatWidth: 7,
@@ -258,7 +258,7 @@ var testCases = []struct {
},
}, {
"pre#*xsuf",
&Format{
&Pattern{
Affix: "\x03pre\x03suf",
PadRune: 'x',
FormatWidth: 7,
@@ -266,7 +266,7 @@ var testCases = []struct {
},
}, {
"pre#suf*x",
&Format{
&Pattern{
Affix: "\x03pre\x03suf",
PadRune: 'x',
FormatWidth: 7,
@@ -293,7 +293,7 @@ func TestParsePattern(t *testing.T) {
}
func TestPatternSize(t *testing.T) {
if sz := unsafe.Sizeof(Format{}); sz > 48 {
if sz := unsafe.Sizeof(Pattern{}); sz > 48 {
t.Errorf("got %d; want 48", sz)
}

View File

@@ -1376,7 +1376,7 @@ var tagToPercent = []uint8{ // 752 elements
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
} // Size: 776 bytes
var formats = []Format{Format{Affix: "",
var formats = []Pattern{Pattern{Affix: "",
Offset: 0x0,
NegOffset: 0x0,
Multiplier: 0x0,
@@ -1393,7 +1393,7 @@ var formats = []Format{Format{Affix: "",
MinSignificantDigits: 0x0,
MaxSignificantDigits: 0x0,
MinExponentDigits: 0x0},
Format{Affix: "",
Pattern{Affix: "",
Offset: 0x0,
NegOffset: 0x0,
Multiplier: 0x0,
@@ -1410,7 +1410,7 @@ var formats = []Format{Format{Affix: "",
MinSignificantDigits: 0x0,
MaxSignificantDigits: 0x0,
MinExponentDigits: 0x0},
Format{Affix: "",
Pattern{Affix: "",
Offset: 0x0,
NegOffset: 0x0,
Multiplier: 0x0,
@@ -1427,7 +1427,7 @@ var formats = []Format{Format{Affix: "",
MinSignificantDigits: 0x0,
MaxSignificantDigits: 0x0,
MinExponentDigits: 0x1},
Format{Affix: "\x00\x03\u00a0%",
Pattern{Affix: "\x00\x03\u00a0%",
Offset: 0x0,
NegOffset: 0x0,
Multiplier: 0x64,
@@ -1444,7 +1444,7 @@ var formats = []Format{Format{Affix: "",
MinSignificantDigits: 0x0,
MaxSignificantDigits: 0x0,
MinExponentDigits: 0x0},
Format{Affix: "\x00\x01%",
Pattern{Affix: "\x00\x01%",
Offset: 0x0,
NegOffset: 0x0,
Multiplier: 0x64,
@@ -1461,7 +1461,7 @@ var formats = []Format{Format{Affix: "",
MinSignificantDigits: 0x0,
MaxSignificantDigits: 0x0,
MinExponentDigits: 0x0},
Format{Affix: "",
Pattern{Affix: "",
Offset: 0x0,
NegOffset: 0x0,
Multiplier: 0x0,
@@ -1478,7 +1478,7 @@ var formats = []Format{Format{Affix: "",
MinSignificantDigits: 0x0,
MaxSignificantDigits: 0x0,
MinExponentDigits: 0x0},
Format{Affix: "\x00\x01%",
Pattern{Affix: "\x00\x01%",
Offset: 0x0,
NegOffset: 0x0,
Multiplier: 0x64,
@@ -1495,7 +1495,7 @@ var formats = []Format{Format{Affix: "",
MinSignificantDigits: 0x0,
MaxSignificantDigits: 0x0,
MinExponentDigits: 0x0},
Format{Affix: "\x00\x03\u00a0%",
Pattern{Affix: "\x00\x03\u00a0%",
Offset: 0x0,
NegOffset: 0x0,
Multiplier: 0x64,
@@ -1512,7 +1512,7 @@ var formats = []Format{Format{Affix: "",
MinSignificantDigits: 0x0,
MaxSignificantDigits: 0x0,
MinExponentDigits: 0x0},
Format{Affix: "",
Pattern{Affix: "",
Offset: 0x0,
NegOffset: 0x0,
Multiplier: 0x0,
@@ -1529,7 +1529,7 @@ var formats = []Format{Format{Affix: "",
MinSignificantDigits: 0x0,
MaxSignificantDigits: 0x0,
MinExponentDigits: 0x0},
Format{Affix: "",
Pattern{Affix: "",
Offset: 0x0,
NegOffset: 0x0,
Multiplier: 0x0,
@@ -1546,7 +1546,7 @@ var formats = []Format{Format{Affix: "",
MinSignificantDigits: 0x0,
MaxSignificantDigits: 0x0,
MinExponentDigits: 0x3},
Format{Affix: "\x00\x01%",
Pattern{Affix: "\x00\x01%",
Offset: 0x0,
NegOffset: 0x0,
Multiplier: 0x64,
@@ -1563,7 +1563,7 @@ var formats = []Format{Format{Affix: "",
MinSignificantDigits: 0x0,
MaxSignificantDigits: 0x0,
MinExponentDigits: 0x0},
Format{Affix: "\x03%\u00a0\x00",
Pattern{Affix: "\x03%\u00a0\x00",
Offset: 0x0,
NegOffset: 0x0,
Multiplier: 0x64,
@@ -1580,7 +1580,7 @@ var formats = []Format{Format{Affix: "",
MinSignificantDigits: 0x0,
MaxSignificantDigits: 0x0,
MinExponentDigits: 0x0},
Format{Affix: "\x03%\u00a0\x00\x04%\u00a0-\x00",
Pattern{Affix: "\x03%\u00a0\x00\x04%\u00a0-\x00",
Offset: 0x0,
NegOffset: 0x5,
Multiplier: 0x64,
@@ -1597,7 +1597,7 @@ var formats = []Format{Format{Affix: "",
MinSignificantDigits: 0x0,
MaxSignificantDigits: 0x0,
MinExponentDigits: 0x0},
Format{Affix: "\x01[\x01]",
Pattern{Affix: "\x01[\x01]",
Offset: 0x0,
NegOffset: 0x0,
Multiplier: 0x0,
@@ -1614,7 +1614,7 @@ var formats = []Format{Format{Affix: "",
MinSignificantDigits: 0x0,
MaxSignificantDigits: 0x0,
MinExponentDigits: 0x1},
Format{Affix: "",
Pattern{Affix: "",
Offset: 0x0,
NegOffset: 0x0,
Multiplier: 0x0,
@@ -1631,7 +1631,7 @@ var formats = []Format{Format{Affix: "",
MinSignificantDigits: 0x0,
MaxSignificantDigits: 0x0,
MinExponentDigits: 0x0},
Format{Affix: "\x01%\x00",
Pattern{Affix: "\x01%\x00",
Offset: 0x0,
NegOffset: 0x0,
Multiplier: 0x64,

View File

@@ -79,7 +79,7 @@ export default class ClusterTable extends React.Component {
clusterInfo.id = Utils.localizeMessage('admin.cluster.unknown', 'unknown');
}
if (clusterInfo.is_alive) {
if (clusterInfo.is_alive > 0) {
status = (
<img
className='cluster-status'