func (m *modeKinds) FromProto(proto *api.ModeKinds) error {
	if proto.UserPrefixes != nil {
		m.userPrefixes = make([][2]rune, len(proto.UserPrefixes))
		for i, prefix := range proto.UserPrefixes {
			if len(prefix.Char) != 1 || len(prefix.Symbol) != 1 {
				return errors.New("user_prefixes is an array of length 2 of 1 character strings")
			}
			m.userPrefixes[i] = [2]rune{
				rune(prefix.Symbol[0]),
				rune(prefix.Char[0]),
			}
		}
	}
	if proto.ChannelModes != nil {
		m.channelModes = make(map[rune]int, len(proto.ChannelModes))
		for k, v := range proto.ChannelModes {
			if len(k) != 1 {
				return errors.New("channel_modes is a map of characters to integers")
			}
			m.channelModes[rune(k[0])] = int(v)
		}
	}
	return nil
}
FromProto turns API struct -> modeKinds
package data
import (
	"encoding/json"
	"errors"
	"fmt"
	"strings"
	"sync"
	"github.com/aarondl/ultimateq/api"
)
const (
	ARGS_NONE    = 0x1
	ARGS_ALWAYS  = 0x2
	ARGS_ONSET   = 0x3
	ARGS_ADDRESS = 0x4
)
const (
	fmtErrCsvParse = "data: Could not parse csv string (%v)"
	fmtErrCouldNotParsePrefix = "data: Could not parse prefix (%v)"
	errMsgMoreThanEight = "data: UserModeKinds supports maximum 8 modes (%v)"
	BITS_IN_BYTE = 8
)
type modeKinds struct {
	userPrefixes [][2]rune
	channelModes map[rune]int
	sync.RWMutex
}
type modeKindJSON struct {
	UserPrefixes [][]string     `json:"user_prefixes"`
	ChannelModes map[string]int `json:"channel_modes"`
}
type userMode struct {
	Mode rune
	Arg  string
}
func newModeKinds(prefix, chanModes string) (*modeKinds, error) {
	userPrefixes, err := parsePrefixString(prefix)
	if err != nil {
		return nil, err
	}
	channelModes, err := parseChannelModeKindsCSV(chanModes)
	if err != nil {
		return nil, err
	}
	return &modeKinds{
		userPrefixes: userPrefixes,
		channelModes: channelModes,
	}, nil
}
func (m *modeKinds) MarshalJSON() ([]byte, error) {
	if m == nil {
		return []byte(`null`), nil
	}
	var toJSON modeKindJSON
	m.RLock()
	defer m.RUnlock()
	if m.userPrefixes != nil {
		toJSON.UserPrefixes = make([][]string, len(m.userPrefixes))
		for i, prefix := range m.userPrefixes {
			toJSON.UserPrefixes[i] = []string{
				string(prefix[0]), string(prefix[1]),
			}
		}
	}
	if m.channelModes != nil {
		toJSON.ChannelModes = make(map[string]int, len(m.channelModes))
		for k, v := range m.channelModes {
			toJSON.ChannelModes[string(k)] = v
		}
	}
	return json.Marshal(toJSON)
}
func (m *modeKinds) UnmarshalJSON(b []byte) error {
	var fromJSON modeKindJSON
	if err := json.Unmarshal(b, &fromJSON); err != nil {
		return err
	}
	if fromJSON.UserPrefixes != nil {
		m.userPrefixes = make([][2]rune, len(fromJSON.UserPrefixes))
		for i, prefix := range fromJSON.UserPrefixes {
			if len(prefix) != 2 || len(prefix[0]) != 1 || len(prefix[1]) != 1 {
				return errors.New("user_prefixes is an array of length 2 of 1 character strings")
			}
			m.userPrefixes[i] = [2]rune{
				rune(prefix[0][0]),
				rune(prefix[1][0]),
			}
		}
	}
	if fromJSON.ChannelModes != nil {
		m.channelModes = make(map[rune]int, len(fromJSON.ChannelModes))
		for k, v := range fromJSON.ChannelModes {
			if len(k) != 1 {
				return errors.New("channel_modes is a map of characters to integers")
			}
			m.channelModes[rune(k[0])] = v
		}
	}
	return nil
}
func (m *modeKinds) ToProto() *api.ModeKinds {
	if m == nil {
		return nil
	}
	var proto api.ModeKinds
	m.RLock()
	defer m.RUnlock()
	if m.userPrefixes != nil {
		proto.UserPrefixes = make([]*api.ModeKinds_UserPrefix, len(m.userPrefixes))
		for i, prefix := range m.userPrefixes {
			proto.UserPrefixes[i] = &api.ModeKinds_UserPrefix{
				Symbol: string(prefix[0]),
				Char:   string(prefix[1]),
			}
		}
	}
	if m.channelModes != nil {
		proto.ChannelModes = make(map[string]int32, len(m.channelModes))
		for k, v := range m.channelModes {
			proto.ChannelModes[string(k)] = int32(v)
		}
	}
	return &proto
}