2017-09-29 09:33:29 +02:00
|
|
|
// Copyright (c) 2017 Daniel Oaks <daniel@danieloaks.net>
|
|
|
|
// released under the MIT license
|
|
|
|
|
2017-09-29 09:25:58 +02:00
|
|
|
package caps
|
|
|
|
|
|
|
|
import (
|
2019-08-27 06:51:09 +02:00
|
|
|
"bytes"
|
2017-09-29 09:25:58 +02:00
|
|
|
"sort"
|
2018-06-26 00:08:15 +02:00
|
|
|
|
|
|
|
"github.com/oragono/oragono/irc/utils"
|
2017-09-29 09:25:58 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
// Set holds a set of enabled capabilities.
|
2019-05-27 21:17:28 +02:00
|
|
|
type Set [bitsetLen]uint32
|
2017-09-29 09:25:58 +02:00
|
|
|
|
2019-08-27 06:51:09 +02:00
|
|
|
// Values holds capability values.
|
|
|
|
type Values map[Capability]string
|
|
|
|
|
2017-09-29 09:25:58 +02:00
|
|
|
// NewSet returns a new Set, with the given capabilities enabled.
|
|
|
|
func NewSet(capabs ...Capability) *Set {
|
2018-06-26 00:08:15 +02:00
|
|
|
var newSet Set
|
2017-09-29 09:25:58 +02:00
|
|
|
newSet.Enable(capabs...)
|
|
|
|
return &newSet
|
|
|
|
}
|
|
|
|
|
2019-04-12 06:08:46 +02:00
|
|
|
// NewCompleteSet returns a new Set, with all defined capabilities enabled.
|
|
|
|
func NewCompleteSet() *Set {
|
|
|
|
var newSet Set
|
|
|
|
asSlice := newSet[:]
|
|
|
|
for i := 0; i < numCapabs; i += 1 {
|
|
|
|
utils.BitsetSet(asSlice, uint(i), true)
|
|
|
|
}
|
|
|
|
return &newSet
|
|
|
|
}
|
|
|
|
|
2017-09-29 09:25:58 +02:00
|
|
|
// Enable enables the given capabilities.
|
|
|
|
func (s *Set) Enable(capabs ...Capability) {
|
2018-06-26 00:08:15 +02:00
|
|
|
asSlice := s[:]
|
2017-09-29 09:25:58 +02:00
|
|
|
for _, capab := range capabs {
|
2018-06-26 00:08:15 +02:00
|
|
|
utils.BitsetSet(asSlice, uint(capab), true)
|
2017-09-29 09:25:58 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Disable disables the given capabilities.
|
|
|
|
func (s *Set) Disable(capabs ...Capability) {
|
2018-06-26 00:08:15 +02:00
|
|
|
asSlice := s[:]
|
2017-09-29 09:25:58 +02:00
|
|
|
for _, capab := range capabs {
|
2018-06-26 00:08:15 +02:00
|
|
|
utils.BitsetSet(asSlice, uint(capab), false)
|
2017-09-29 09:25:58 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add adds the given capabilities to this set.
|
|
|
|
// this is just a wrapper to allow more clear use.
|
|
|
|
func (s *Set) Add(capabs ...Capability) {
|
|
|
|
s.Enable(capabs...)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Remove removes the given capabilities from this set.
|
|
|
|
// this is just a wrapper to allow more clear use.
|
|
|
|
func (s *Set) Remove(capabs ...Capability) {
|
|
|
|
s.Disable(capabs...)
|
|
|
|
}
|
|
|
|
|
2018-06-26 00:08:15 +02:00
|
|
|
// Has returns true if this set has the given capability.
|
|
|
|
func (s *Set) Has(capab Capability) bool {
|
|
|
|
return utils.BitsetGet(s[:], uint(capab))
|
2017-09-29 09:25:58 +02:00
|
|
|
}
|
|
|
|
|
2019-04-12 06:08:46 +02:00
|
|
|
// HasAll returns true if the set has all the given capabilities.
|
|
|
|
func (s *Set) HasAll(capabs ...Capability) bool {
|
|
|
|
for _, capab := range capabs {
|
|
|
|
if !s.Has(capab) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2018-06-26 00:08:15 +02:00
|
|
|
// Union adds all the capabilities of another set to this set.
|
|
|
|
func (s *Set) Union(other *Set) {
|
|
|
|
utils.BitsetUnion(s[:], other[:])
|
2017-09-29 09:25:58 +02:00
|
|
|
}
|
|
|
|
|
2019-02-03 02:00:23 +01:00
|
|
|
// Subtract removes all the capabilities of another set from this set.
|
|
|
|
func (s *Set) Subtract(other *Set) {
|
|
|
|
utils.BitsetSubtract(s[:], other[:])
|
|
|
|
}
|
|
|
|
|
2018-06-26 00:08:15 +02:00
|
|
|
// Empty returns whether the set is empty.
|
|
|
|
func (s *Set) Empty() bool {
|
|
|
|
return utils.BitsetEmpty(s[:])
|
2017-09-29 09:25:58 +02:00
|
|
|
}
|
|
|
|
|
2019-08-27 06:51:09 +02:00
|
|
|
const maxPayloadLength = 440
|
|
|
|
|
2019-09-08 12:22:34 +02:00
|
|
|
// Strings returns all of our enabled capabilities as a slice of strings.
|
|
|
|
func (s *Set) Strings(version Version, values Values) (result []string) {
|
2017-09-29 09:25:58 +02:00
|
|
|
var strs sort.StringSlice
|
|
|
|
|
2018-06-26 00:08:15 +02:00
|
|
|
var capab Capability
|
|
|
|
asSlice := s[:]
|
|
|
|
for capab = 0; capab < numCapabs; capab++ {
|
|
|
|
// skip any capabilities that are not enabled
|
|
|
|
if !utils.BitsetGet(asSlice, uint(capab)) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
capString := capab.Name()
|
2019-09-08 12:22:34 +02:00
|
|
|
if version >= Cap302 {
|
2019-08-27 06:51:09 +02:00
|
|
|
val, exists := values[capab]
|
2017-09-29 09:25:58 +02:00
|
|
|
if exists {
|
|
|
|
capString += "=" + val
|
|
|
|
}
|
|
|
|
}
|
|
|
|
strs = append(strs, capString)
|
|
|
|
}
|
|
|
|
|
2019-08-27 06:51:09 +02:00
|
|
|
if len(strs) == 0 {
|
|
|
|
return []string{""}
|
|
|
|
}
|
|
|
|
|
2017-09-29 09:25:58 +02:00
|
|
|
// sort the cap string before we send it out
|
|
|
|
sort.Sort(strs)
|
|
|
|
|
2019-08-27 06:51:09 +02:00
|
|
|
var buf bytes.Buffer
|
|
|
|
for _, str := range strs {
|
|
|
|
tokenLen := len(str)
|
|
|
|
if buf.Len() != 0 {
|
|
|
|
tokenLen += 1
|
|
|
|
}
|
|
|
|
if maxPayloadLength < buf.Len()+tokenLen {
|
|
|
|
result = append(result, buf.String())
|
|
|
|
buf.Reset()
|
|
|
|
}
|
|
|
|
if buf.Len() != 0 {
|
|
|
|
buf.WriteByte(' ')
|
|
|
|
}
|
|
|
|
buf.WriteString(str)
|
|
|
|
}
|
|
|
|
if buf.Len() != 0 {
|
|
|
|
result = append(result, buf.String())
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
2017-09-29 09:25:58 +02:00
|
|
|
}
|