diff options
Diffstat (limited to 'vendor/maunium.net/go/mautrix/util')
-rw-r--r-- | vendor/maunium.net/go/mautrix/util/base58/README.md | 9 | ||||
-rw-r--r-- | vendor/maunium.net/go/mautrix/util/base58/alphabet.go | 49 | ||||
-rw-r--r-- | vendor/maunium.net/go/mautrix/util/base58/base58.go | 138 | ||||
-rw-r--r-- | vendor/maunium.net/go/mautrix/util/base58/base58check.go | 52 | ||||
-rw-r--r-- | vendor/maunium.net/go/mautrix/util/base58/doc.go | 29 | ||||
-rw-r--r-- | vendor/maunium.net/go/mautrix/util/dualerror.go | 33 | ||||
-rw-r--r-- | vendor/maunium.net/go/mautrix/util/gjson.go | 31 | ||||
-rw-r--r-- | vendor/maunium.net/go/mautrix/util/jsontime/jsontime.go | 86 | ||||
-rw-r--r-- | vendor/maunium.net/go/mautrix/util/marshal.go | 30 | ||||
-rw-r--r-- | vendor/maunium.net/go/mautrix/util/mimetypes.go | 50 | ||||
-rw-r--r-- | vendor/maunium.net/go/mautrix/util/random.go | 65 | ||||
-rw-r--r-- | vendor/maunium.net/go/mautrix/util/returnonce.go | 23 | ||||
-rw-r--r-- | vendor/maunium.net/go/mautrix/util/ringbuffer.go | 77 | ||||
-rw-r--r-- | vendor/maunium.net/go/mautrix/util/syncmap.go | 94 |
14 files changed, 766 insertions, 0 deletions
diff --git a/vendor/maunium.net/go/mautrix/util/base58/README.md b/vendor/maunium.net/go/mautrix/util/base58/README.md new file mode 100644 index 00000000..50954507 --- /dev/null +++ b/vendor/maunium.net/go/mautrix/util/base58/README.md @@ -0,0 +1,9 @@ +base58 +========== + +This is a copy of <https://github.com/btcsuite/btcd/tree/master/btcutil/base58>. + +## License + +Package base58 is licensed under the [copyfree](http://copyfree.org) ISC +License. diff --git a/vendor/maunium.net/go/mautrix/util/base58/alphabet.go b/vendor/maunium.net/go/mautrix/util/base58/alphabet.go new file mode 100644 index 00000000..6bb39fef --- /dev/null +++ b/vendor/maunium.net/go/mautrix/util/base58/alphabet.go @@ -0,0 +1,49 @@ +// Copyright (c) 2015 The btcsuite developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +// AUTOGENERATED by genalphabet.go; do not edit. + +package base58 + +const ( + // alphabet is the modified base58 alphabet used by Bitcoin. + alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" + + alphabetIdx0 = '1' +) + +var b58 = [256]byte{ + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 0, 1, 2, 3, 4, 5, 6, + 7, 8, 255, 255, 255, 255, 255, 255, + 255, 9, 10, 11, 12, 13, 14, 15, + 16, 255, 17, 18, 19, 20, 21, 255, + 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 255, 255, 255, 255, 255, + 255, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 255, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, +} diff --git a/vendor/maunium.net/go/mautrix/util/base58/base58.go b/vendor/maunium.net/go/mautrix/util/base58/base58.go new file mode 100644 index 00000000..8ee59567 --- /dev/null +++ b/vendor/maunium.net/go/mautrix/util/base58/base58.go @@ -0,0 +1,138 @@ +// Copyright (c) 2013-2015 The btcsuite developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package base58 + +import ( + "math/big" +) + +//go:generate go run genalphabet.go + +var bigRadix = [...]*big.Int{ + big.NewInt(0), + big.NewInt(58), + big.NewInt(58 * 58), + big.NewInt(58 * 58 * 58), + big.NewInt(58 * 58 * 58 * 58), + big.NewInt(58 * 58 * 58 * 58 * 58), + big.NewInt(58 * 58 * 58 * 58 * 58 * 58), + big.NewInt(58 * 58 * 58 * 58 * 58 * 58 * 58), + big.NewInt(58 * 58 * 58 * 58 * 58 * 58 * 58 * 58), + big.NewInt(58 * 58 * 58 * 58 * 58 * 58 * 58 * 58 * 58), + bigRadix10, +} + +var bigRadix10 = big.NewInt(58 * 58 * 58 * 58 * 58 * 58 * 58 * 58 * 58 * 58) // 58^10 + +// Decode decodes a modified base58 string to a byte slice. +func Decode(b string) []byte { + answer := big.NewInt(0) + scratch := new(big.Int) + + // Calculating with big.Int is slow for each iteration. + // x += b58[b[i]] * j + // j *= 58 + // + // Instead we can try to do as much calculations on int64. + // We can represent a 10 digit base58 number using an int64. + // + // Hence we'll try to convert 10, base58 digits at a time. + // The rough idea is to calculate `t`, such that: + // + // t := b58[b[i+9]] * 58^9 ... + b58[b[i+1]] * 58^1 + b58[b[i]] * 58^0 + // x *= 58^10 + // x += t + // + // Of course, in addition, we'll need to handle boundary condition when `b` is not multiple of 58^10. + // In that case we'll use the bigRadix[n] lookup for the appropriate power. + for t := b; len(t) > 0; { + n := len(t) + if n > 10 { + n = 10 + } + + total := uint64(0) + for _, v := range t[:n] { + tmp := b58[v] + if tmp == 255 { + return []byte("") + } + total = total*58 + uint64(tmp) + } + + answer.Mul(answer, bigRadix[n]) + scratch.SetUint64(total) + answer.Add(answer, scratch) + + t = t[n:] + } + + tmpval := answer.Bytes() + + var numZeros int + for numZeros = 0; numZeros < len(b); numZeros++ { + if b[numZeros] != alphabetIdx0 { + break + } + } + flen := numZeros + len(tmpval) + val := make([]byte, flen) + copy(val[numZeros:], tmpval) + + return val +} + +// Encode encodes a byte slice to a modified base58 string. +func Encode(b []byte) string { + x := new(big.Int) + x.SetBytes(b) + + // maximum length of output is log58(2^(8*len(b))) == len(b) * 8 / log(58) + maxlen := int(float64(len(b))*1.365658237309761) + 1 + answer := make([]byte, 0, maxlen) + mod := new(big.Int) + for x.Sign() > 0 { + // Calculating with big.Int is slow for each iteration. + // x, mod = x / 58, x % 58 + // + // Instead we can try to do as much calculations on int64. + // x, mod = x / 58^10, x % 58^10 + // + // Which will give us mod, which is 10 digit base58 number. + // We'll loop that 10 times to convert to the answer. + + x.DivMod(x, bigRadix10, mod) + if x.Sign() == 0 { + // When x = 0, we need to ensure we don't add any extra zeros. + m := mod.Int64() + for m > 0 { + answer = append(answer, alphabet[m%58]) + m /= 58 + } + } else { + m := mod.Int64() + for i := 0; i < 10; i++ { + answer = append(answer, alphabet[m%58]) + m /= 58 + } + } + } + + // leading zero bytes + for _, i := range b { + if i != 0 { + break + } + answer = append(answer, alphabetIdx0) + } + + // reverse + alen := len(answer) + for i := 0; i < alen/2; i++ { + answer[i], answer[alen-1-i] = answer[alen-1-i], answer[i] + } + + return string(answer) +} diff --git a/vendor/maunium.net/go/mautrix/util/base58/base58check.go b/vendor/maunium.net/go/mautrix/util/base58/base58check.go new file mode 100644 index 00000000..402c3233 --- /dev/null +++ b/vendor/maunium.net/go/mautrix/util/base58/base58check.go @@ -0,0 +1,52 @@ +// Copyright (c) 2013-2014 The btcsuite developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package base58 + +import ( + "crypto/sha256" + "errors" +) + +// ErrChecksum indicates that the checksum of a check-encoded string does not verify against +// the checksum. +var ErrChecksum = errors.New("checksum error") + +// ErrInvalidFormat indicates that the check-encoded string has an invalid format. +var ErrInvalidFormat = errors.New("invalid format: version and/or checksum bytes missing") + +// checksum: first four bytes of sha256^2 +func checksum(input []byte) (cksum [4]byte) { + h := sha256.Sum256(input) + h2 := sha256.Sum256(h[:]) + copy(cksum[:], h2[:4]) + return +} + +// CheckEncode prepends a version byte and appends a four byte checksum. +func CheckEncode(input []byte, version byte) string { + b := make([]byte, 0, 1+len(input)+4) + b = append(b, version) + b = append(b, input...) + cksum := checksum(b) + b = append(b, cksum[:]...) + return Encode(b) +} + +// CheckDecode decodes a string that was encoded with CheckEncode and verifies the checksum. +func CheckDecode(input string) (result []byte, version byte, err error) { + decoded := Decode(input) + if len(decoded) < 5 { + return nil, 0, ErrInvalidFormat + } + version = decoded[0] + var cksum [4]byte + copy(cksum[:], decoded[len(decoded)-4:]) + if checksum(decoded[:len(decoded)-4]) != cksum { + return nil, 0, ErrChecksum + } + payload := decoded[1 : len(decoded)-4] + result = append(result, payload...) + return +} diff --git a/vendor/maunium.net/go/mautrix/util/base58/doc.go b/vendor/maunium.net/go/mautrix/util/base58/doc.go new file mode 100644 index 00000000..d657f050 --- /dev/null +++ b/vendor/maunium.net/go/mautrix/util/base58/doc.go @@ -0,0 +1,29 @@ +// Copyright (c) 2014 The btcsuite developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +/* +Package base58 provides an API for working with modified base58 and Base58Check +encodings. + +# Modified Base58 Encoding + +Standard base58 encoding is similar to standard base64 encoding except, as the +name implies, it uses a 58 character alphabet which results in an alphanumeric +string and allows some characters which are problematic for humans to be +excluded. Due to this, there can be various base58 alphabets. + +The modified base58 alphabet used by Bitcoin, and hence this package, omits the +0, O, I, and l characters that look the same in many fonts and are therefore +hard to humans to distinguish. + +# Base58Check Encoding Scheme + +The Base58Check encoding scheme is primarily used for Bitcoin addresses at the +time of this writing, however it can be used to generically encode arbitrary +byte arrays into human-readable strings along with a version byte that can be +used to differentiate the same payload. For Bitcoin addresses, the extra +version is used to differentiate the network of otherwise identical public keys +which helps prevent using an address intended for one network on another. +*/ +package base58 diff --git a/vendor/maunium.net/go/mautrix/util/dualerror.go b/vendor/maunium.net/go/mautrix/util/dualerror.go new file mode 100644 index 00000000..b153d432 --- /dev/null +++ b/vendor/maunium.net/go/mautrix/util/dualerror.go @@ -0,0 +1,33 @@ +// Copyright (c) 2022 Tulir Asokan +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package util + +import ( + "errors" + "fmt" +) + +type DualError struct { + High error + Low error +} + +func NewDualError(high, low error) DualError { + return DualError{high, low} +} + +func (err DualError) Is(other error) bool { + return errors.Is(other, err.High) || errors.Is(other, err.Low) +} + +func (err DualError) Unwrap() error { + return err.Low +} + +func (err DualError) Error() string { + return fmt.Sprintf("%v: %v", err.High, err.Low) +} diff --git a/vendor/maunium.net/go/mautrix/util/gjson.go b/vendor/maunium.net/go/mautrix/util/gjson.go new file mode 100644 index 00000000..05ef8277 --- /dev/null +++ b/vendor/maunium.net/go/mautrix/util/gjson.go @@ -0,0 +1,31 @@ +// Copyright (c) 2022 Tulir Asokan +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package util + +import ( + "strings" +) + +var GJSONEscaper = strings.NewReplacer( + `\`, `\\`, + ".", `\.`, + "|", `\|`, + "#", `\#`, + "@", `\@`, + "*", `\*`, + "?", `\?`) + +func GJSONPath(path ...string) string { + var result strings.Builder + for i, part := range path { + _, _ = GJSONEscaper.WriteString(&result, part) + if i < len(path)-1 { + result.WriteRune('.') + } + } + return result.String() +} diff --git a/vendor/maunium.net/go/mautrix/util/jsontime/jsontime.go b/vendor/maunium.net/go/mautrix/util/jsontime/jsontime.go new file mode 100644 index 00000000..b3282338 --- /dev/null +++ b/vendor/maunium.net/go/mautrix/util/jsontime/jsontime.go @@ -0,0 +1,86 @@ +// Copyright (c) 2022 Tulir Asokan +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package jsontime + +import ( + "encoding/json" + "time" +) + +func UM(time time.Time) UnixMilli { + return UnixMilli{Time: time} +} + +func UMInt(ts int64) UnixMilli { + return UM(time.UnixMilli(ts)) +} + +func UnixMilliNow() UnixMilli { + return UM(time.Now()) +} + +type UnixMilli struct { + time.Time +} + +func (um UnixMilli) MarshalJSON() ([]byte, error) { + if um.IsZero() { + return []byte{'0'}, nil + } + return json.Marshal(um.UnixMilli()) +} + +func (um *UnixMilli) UnmarshalJSON(data []byte) error { + var val int64 + err := json.Unmarshal(data, &val) + if err != nil { + return err + } + if val == 0 { + um.Time = time.Time{} + } else { + um.Time = time.UnixMilli(val) + } + return nil +} + +func U(time time.Time) Unix { + return Unix{Time: time} +} + +func UInt(ts int64) Unix { + return U(time.Unix(ts, 0)) +} + +func UnixNow() Unix { + return U(time.Now()) +} + +type Unix struct { + time.Time +} + +func (u Unix) MarshalJSON() ([]byte, error) { + if u.IsZero() { + return []byte{'0'}, nil + } + return json.Marshal(u.Unix()) +} + +func (u *Unix) UnmarshalJSON(data []byte) error { + var val int64 + err := json.Unmarshal(data, &val) + if err != nil { + return err + } + if val == 0 { + u.Time = time.Time{} + } else { + u.Time = time.Unix(val, 0) + } + return nil +} diff --git a/vendor/maunium.net/go/mautrix/util/marshal.go b/vendor/maunium.net/go/mautrix/util/marshal.go new file mode 100644 index 00000000..180adef2 --- /dev/null +++ b/vendor/maunium.net/go/mautrix/util/marshal.go @@ -0,0 +1,30 @@ +package util + +import ( + "encoding/json" + "fmt" + + "github.com/tidwall/gjson" + "github.com/tidwall/sjson" +) + +// MarshalAndDeleteEmpty marshals a JSON object, then uses gjson to delete empty objects at the given gjson paths. +// +// This can be used as a convenient way to create a marshaler that omits empty non-pointer structs. +// See mautrix.RespSync for example. +func MarshalAndDeleteEmpty(marshalable interface{}, paths []string) ([]byte, error) { + data, err := json.Marshal(marshalable) + if err != nil { + return nil, err + } + for _, path := range paths { + res := gjson.GetBytes(data, path) + if res.IsObject() && len(res.Raw) == 2 { + data, err = sjson.DeleteBytes(data, path) + if err != nil { + return nil, fmt.Errorf("failed to delete empty %s: %w", path, err) + } + } + } + return data, nil +} diff --git a/vendor/maunium.net/go/mautrix/util/mimetypes.go b/vendor/maunium.net/go/mautrix/util/mimetypes.go new file mode 100644 index 00000000..9877c3d3 --- /dev/null +++ b/vendor/maunium.net/go/mautrix/util/mimetypes.go @@ -0,0 +1,50 @@ +// Copyright (c) 2022 Sumner Evans +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package util + +import ( + "mime" + "strings" +) + +// MimeExtensionSanityOverrides includes extensions for various common mimetypes. +// +// This is necessary because sometimes the OS mimetype database and Go interact in weird ways, +// which causes very obscure extensions to be first in the array for common mimetypes +// (e.g. image/jpeg -> .jpe, text/plain -> ,v). +var MimeExtensionSanityOverrides = map[string]string{ + "image/png": ".png", + "image/webp": ".webp", + "image/jpeg": ".jpg", + "image/tiff": ".tiff", + "image/heif": ".heic", + "image/heic": ".heic", + + "audio/mpeg": ".mp3", + "audio/ogg": ".ogg", + "audio/webm": ".webm", + "audio/x-caf": ".caf", + "video/mp4": ".mp4", + "video/mpeg": ".mpeg", + "video/webm": ".webm", + + "text/plain": ".txt", + "text/html": ".html", + + "application/xml": ".xml", +} + +func ExtensionFromMimetype(mimetype string) string { + ext, ok := MimeExtensionSanityOverrides[strings.Split(mimetype, ";")[0]] + if !ok { + exts, _ := mime.ExtensionsByType(mimetype) + if len(exts) > 0 { + ext = exts[0] + } + } + return ext +} diff --git a/vendor/maunium.net/go/mautrix/util/random.go b/vendor/maunium.net/go/mautrix/util/random.go new file mode 100644 index 00000000..944dd034 --- /dev/null +++ b/vendor/maunium.net/go/mautrix/util/random.go @@ -0,0 +1,65 @@ +// Copyright (c) 2022 Tulir Asokan +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package util + +import ( + "crypto/rand" + "encoding/base64" + "hash/crc32" + "strings" + "unsafe" +) + +func RandomBytes(n int) []byte { + data := make([]byte, n) + _, err := rand.Read(data) + if err != nil { + panic(err) + } + return data +} + +var letters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + +// RandomString generates a random string of the given length. +func RandomString(n int) string { + if n <= 0 { + return "" + } + base64Len := n + if n%4 != 0 { + base64Len += 4 - (n % 4) + } + decodedLength := base64.RawStdEncoding.DecodedLen(base64Len) + output := make([]byte, base64Len) + base64.RawStdEncoding.Encode(output, RandomBytes(decodedLength)) + for i, char := range output { + if char == '+' || char == '/' { + _, err := rand.Read(output[i : i+1]) + if err != nil { + panic(err) + } + output[i] = letters[int(output[i])%len(letters)] + } + } + return (*(*string)(unsafe.Pointer(&output)))[:n] +} + +func base62Encode(val uint32, minWidth int) string { + var buf strings.Builder + for val > 0 { + buf.WriteByte(letters[val%62]) + val /= 62 + } + return strings.Repeat("0", minWidth-buf.Len()) + buf.String() +} + +func RandomToken(namespace string, randomLength int) string { + token := namespace + "_" + RandomString(randomLength) + checksum := base62Encode(crc32.ChecksumIEEE([]byte(token)), 6) + return token + "_" + checksum +} diff --git a/vendor/maunium.net/go/mautrix/util/returnonce.go b/vendor/maunium.net/go/mautrix/util/returnonce.go new file mode 100644 index 00000000..c85aae0a --- /dev/null +++ b/vendor/maunium.net/go/mautrix/util/returnonce.go @@ -0,0 +1,23 @@ +// Copyright (c) 2023 Tulir Asokan +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package util + +import "sync" + +// ReturnableOnce is a wrapper for sync.Once that can return a value +type ReturnableOnce[Value any] struct { + once sync.Once + output Value + err error +} + +func (ronce *ReturnableOnce[Value]) Do(fn func() (Value, error)) (Value, error) { + ronce.once.Do(func() { + ronce.output, ronce.err = fn() + }) + return ronce.output, ronce.err +} diff --git a/vendor/maunium.net/go/mautrix/util/ringbuffer.go b/vendor/maunium.net/go/mautrix/util/ringbuffer.go new file mode 100644 index 00000000..ddb4c79f --- /dev/null +++ b/vendor/maunium.net/go/mautrix/util/ringbuffer.go @@ -0,0 +1,77 @@ +// Copyright (c) 2023 Tulir Asokan +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package util + +import ( + "sync" +) + +type pair[Key comparable, Value any] struct { + Key Key + Value Value +} + +type RingBuffer[Key comparable, Value any] struct { + ptr int + data []pair[Key, Value] + lock sync.RWMutex +} + +func NewRingBuffer[Key comparable, Value any](size int) *RingBuffer[Key, Value] { + return &RingBuffer[Key, Value]{ + data: make([]pair[Key, Value], size), + } +} + +func (rb *RingBuffer[Key, Value]) Contains(val Key) bool { + _, ok := rb.Get(val) + return ok +} + +func (rb *RingBuffer[Key, Value]) Get(key Key) (val Value, found bool) { + rb.lock.RLock() + end := rb.ptr + for i := clamp(end-1, len(rb.data)); i != end; i = clamp(i-1, len(rb.data)) { + if rb.data[i].Key == key { + val = rb.data[i].Value + found = true + break + } + } + rb.lock.RUnlock() + return +} + +func (rb *RingBuffer[Key, Value]) Replace(key Key, val Value) bool { + rb.lock.Lock() + defer rb.lock.Unlock() + end := rb.ptr + for i := clamp(end-1, len(rb.data)); i != end; i = clamp(i-1, len(rb.data)) { + if rb.data[i].Key == key { + rb.data[i].Value = val + return true + } + } + return false +} + +func (rb *RingBuffer[Key, Value]) Push(key Key, val Value) { + rb.lock.Lock() + rb.data[rb.ptr] = pair[Key, Value]{Key: key, Value: val} + rb.ptr = (rb.ptr + 1) % len(rb.data) + rb.lock.Unlock() +} + +func clamp(index, len int) int { + if index < 0 { + return len + index + } else if index >= len { + return len - index + } else { + return index + } +} diff --git a/vendor/maunium.net/go/mautrix/util/syncmap.go b/vendor/maunium.net/go/mautrix/util/syncmap.go new file mode 100644 index 00000000..a6b20d3b --- /dev/null +++ b/vendor/maunium.net/go/mautrix/util/syncmap.go @@ -0,0 +1,94 @@ +// Copyright (c) 2023 Tulir Asokan +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package util + +import "sync" + +// SyncMap is a simple map with a built-in mutex. +type SyncMap[Key comparable, Value any] struct { + data map[Key]Value + lock sync.RWMutex +} + +func NewSyncMap[Key comparable, Value any]() *SyncMap[Key, Value] { + return &SyncMap[Key, Value]{ + data: make(map[Key]Value), + } +} + +// Set stores a value in the map. +func (sm *SyncMap[Key, Value]) Set(key Key, value Value) { + sm.Swap(key, value) +} + +// Swap sets a value in the map and returns the old value. +// +// The boolean return parameter is true if the value already existed, false if not. +func (sm *SyncMap[Key, Value]) Swap(key Key, value Value) (oldValue Value, wasReplaced bool) { + sm.lock.Lock() + oldValue, wasReplaced = sm.data[key] + sm.data[key] = value + sm.lock.Unlock() + return +} + +// Delete removes a key from the map. +func (sm *SyncMap[Key, Value]) Delete(key Key) { + sm.Pop(key) +} + +// Pop removes a key from the map and returns the old value. +// +// The boolean return parameter is the same as with normal Go map access (true if the key exists, false if not). +func (sm *SyncMap[Key, Value]) Pop(key Key) (value Value, ok bool) { + sm.lock.Lock() + value, ok = sm.data[key] + delete(sm.data, key) + sm.lock.Unlock() + return +} + +// Get gets a value in the map. +// +// The boolean return parameter is the same as with normal Go map access (true if the key exists, false if not). +func (sm *SyncMap[Key, Value]) Get(key Key) (value Value, ok bool) { + sm.lock.RLock() + value, ok = sm.data[key] + sm.lock.RUnlock() + return +} + +// GetOrSet gets a value in the map if the key already exists, otherwise inserts the given value and returns it. +// +// The boolean return parameter is true if the key already exists, and false if the given value was inserted. +func (sm *SyncMap[Key, Value]) GetOrSet(key Key, value Value) (actual Value, wasGet bool) { + sm.lock.Lock() + defer sm.lock.Unlock() + actual, wasGet = sm.data[key] + if wasGet { + return + } + sm.data[key] = value + actual = value + return +} + +// Clone returns a copy of the map. +func (sm *SyncMap[Key, Value]) Clone() *SyncMap[Key, Value] { + return &SyncMap[Key, Value]{data: sm.CopyData()} +} + +// CopyData returns a copy of the data in the map as a normal (non-atomic) map. +func (sm *SyncMap[Key, Value]) CopyData() map[Key]Value { + sm.lock.RLock() + copied := make(map[Key]Value, len(sm.data)) + for key, value := range sm.data { + copied[key] = value + } + sm.lock.RUnlock() + return copied +} |