/** * file: types/tag.go * author: Theo Technicguy * license: Apache 2.0 * * Tag type and functions */ package types import ( "crypto/sha1" "encoding/binary" "errors" ) const ( colorBase = 0xff colorRage = colorBase*colorBase*colorBase + 1 ) var ( ErrTagNameEmpty = errors.New("tag name is empty") ErrTagHasColor = errors.New("tag has valid color") ErrTagInvalidCollor = errors.New("tag has invalid color") ) // A Tag is a simple structure used to categorize products. // Tag names are unique. Tag colors are base 10 RGB notation. type Tag struct { Id uint `json:"id"` Name string `json:"name"` Color uint `json:"color"` } // GenerateColor generates a random tag color using the tag's // name's SHA1. func (t *Tag) GenerateColor() error { if t.Name == "" { return ErrTagNameEmpty } if t.ValidColor() { return ErrTagHasColor } hash := sha1.Sum([]byte(t.Name)) t.Color = uint(binary.BigEndian.Uint64(hash[:])) % colorRage return nil } // RGB converts the base 10 RGB color in an array of color values. func (t *Tag) RGB() ([]uint, error) { if !t.ValidColor() { return nil, ErrTagInvalidCollor } c := t.Color colors := []uint{} for c > 0 { colors = append(colors, c%colorBase) c = c / colorBase } return colors, nil } // ValidColor verifies that the tag's color is valid. func (t *Tag) ValidColor() bool { return t.Color < colorRage } // ValidName verifies that the tag has a name. // Uniqueness verification is the data source's job. func (t *Tag) ValidName() bool { return t.Name != "" } // Valid verifies that the tag is valid. // A valid tag has a valid color and a name. func (t *Tag) Valid() bool { return t.ValidColor() && t.ValidName() }