115 lines
2.5 KiB
Go
115 lines
2.5 KiB
Go
package nostr
|
|
|
|
import (
|
|
"strconv"
|
|
"strings"
|
|
"sync"
|
|
"unsafe"
|
|
|
|
"golang.org/x/exp/constraints"
|
|
)
|
|
|
|
const MAX_LOCKS = 50
|
|
|
|
var namedMutexPool = make([]sync.Mutex, MAX_LOCKS)
|
|
|
|
//go:noescape
|
|
//go:linkname memhash runtime.memhash
|
|
func memhash(p unsafe.Pointer, h, s uintptr) uintptr
|
|
|
|
func namedLock(name string) (unlock func()) {
|
|
sptr := unsafe.StringData(name)
|
|
idx := uint64(memhash(unsafe.Pointer(sptr), 0, uintptr(len(name)))) % MAX_LOCKS
|
|
namedMutexPool[idx].Lock()
|
|
return namedMutexPool[idx].Unlock
|
|
}
|
|
|
|
func similar[E constraints.Ordered](as, bs []E) bool {
|
|
if len(as) != len(bs) {
|
|
return false
|
|
}
|
|
|
|
for _, a := range as {
|
|
for _, b := range bs {
|
|
if b == a {
|
|
goto next
|
|
}
|
|
}
|
|
// didn't find a B that corresponded to the current A
|
|
return false
|
|
|
|
next:
|
|
continue
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
// Escaping strings for JSON encoding according to RFC8259.
|
|
// Also encloses result in quotation marks "".
|
|
func escapeString(dst []byte, s string) []byte {
|
|
dst = append(dst, '"')
|
|
for i := 0; i < len(s); i++ {
|
|
c := s[i]
|
|
switch {
|
|
case c == '"':
|
|
// quotation mark
|
|
dst = append(dst, []byte{'\\', '"'}...)
|
|
case c == '\\':
|
|
// reverse solidus
|
|
dst = append(dst, []byte{'\\', '\\'}...)
|
|
case c >= 0x20:
|
|
// default, rest below are control chars
|
|
dst = append(dst, c)
|
|
case c == 0x08:
|
|
dst = append(dst, []byte{'\\', 'b'}...)
|
|
case c < 0x09:
|
|
dst = append(dst, []byte{'\\', 'u', '0', '0', '0', '0' + c}...)
|
|
case c == 0x09:
|
|
dst = append(dst, []byte{'\\', 't'}...)
|
|
case c == 0x0a:
|
|
dst = append(dst, []byte{'\\', 'n'}...)
|
|
case c == 0x0c:
|
|
dst = append(dst, []byte{'\\', 'f'}...)
|
|
case c == 0x0d:
|
|
dst = append(dst, []byte{'\\', 'r'}...)
|
|
case c < 0x10:
|
|
dst = append(dst, []byte{'\\', 'u', '0', '0', '0', 0x57 + c}...)
|
|
case c < 0x1a:
|
|
dst = append(dst, []byte{'\\', 'u', '0', '0', '1', 0x20 + c}...)
|
|
case c < 0x20:
|
|
dst = append(dst, []byte{'\\', 'u', '0', '0', '1', 0x47 + c}...)
|
|
}
|
|
}
|
|
dst = append(dst, '"')
|
|
return dst
|
|
}
|
|
|
|
func arePointerValuesEqual[V comparable](a *V, b *V) bool {
|
|
if a == nil && b == nil {
|
|
return true
|
|
}
|
|
if a != nil && b != nil {
|
|
return *a == *b
|
|
}
|
|
return false
|
|
}
|
|
|
|
func subIdToSerial(subId string) int64 {
|
|
n := strings.Index(subId, ":")
|
|
if n < 0 || n > len(subId) {
|
|
return -1
|
|
}
|
|
serialId, _ := strconv.ParseInt(subId[0:n], 10, 64)
|
|
return serialId
|
|
}
|
|
|
|
func isLowerHex(thing string) bool {
|
|
for _, charNumber := range thing {
|
|
if (charNumber >= 48 && charNumber <= 57) || (charNumber >= 97 && charNumber <= 102) {
|
|
continue
|
|
}
|
|
return false
|
|
}
|
|
return true
|
|
}
|