mirror of
https://github.com/PretendoNetwork/nex-go.git
synced 2025-04-02 11:02:14 -04:00
175 lines
4 KiB
Go
175 lines
4 KiB
Go
package types
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
// Map represents a Quazal Rendez-Vous/NEX Map type.
|
|
// Type alias of map[K]V.
|
|
// There is not an official type in either the rdv or nn::nex namespaces.
|
|
// May have any RVType as both a key and value. If either they key or
|
|
// value types are not an RVType, they are ignored.
|
|
//
|
|
// Incompatible with RVType pointers!
|
|
type Map[K comparable, V RVType] map[K]V
|
|
|
|
func (m Map[K, V]) writeType(t any, writable Writable) {
|
|
// * This just makes Map.WriteTo() a bit cleaner
|
|
// * since it doesn't have to type check
|
|
if rvt, ok := t.(interface{ WriteTo(writable Writable) }); ok {
|
|
rvt.WriteTo(writable)
|
|
}
|
|
}
|
|
|
|
// WriteTo writes the Map to the given writable
|
|
func (m Map[K, V]) WriteTo(writable Writable) {
|
|
writable.WriteUInt32LE(uint32(len(m)))
|
|
|
|
for key, value := range m {
|
|
m.writeType(key, writable)
|
|
m.writeType(value, writable)
|
|
}
|
|
}
|
|
|
|
func (m Map[K, V]) extractType(t any, readable Readable) error {
|
|
// * This just makes Map.ExtractFrom() a bit cleaner
|
|
// * since it doesn't have to type check
|
|
if ptr, ok := t.(RVTypePtr); ok {
|
|
return ptr.ExtractFrom(readable)
|
|
}
|
|
|
|
// * Maybe support other types..?
|
|
|
|
return fmt.Errorf("Unsupported Map type %T", t)
|
|
}
|
|
|
|
// ExtractFrom extracts the Map from the given readable
|
|
func (m *Map[K, V]) ExtractFrom(readable Readable) error {
|
|
length, err := readable.ReadUInt32LE()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
extracted := make(Map[K, V])
|
|
|
|
for i := 0; i < int(length); i++ {
|
|
var key K
|
|
if err := m.extractType(&key, readable); err != nil {
|
|
return err
|
|
}
|
|
|
|
var value V
|
|
if err := m.extractType(&value, readable); err != nil {
|
|
return err
|
|
}
|
|
|
|
extracted[key] = value
|
|
}
|
|
|
|
*m = extracted
|
|
|
|
return nil
|
|
}
|
|
|
|
func (m Map[K, V]) copyType(t any) RVType {
|
|
// * This just makes Map.Copy() a bit cleaner
|
|
// * since it doesn't have to type check
|
|
if rvt, ok := t.(RVType); ok {
|
|
return rvt.Copy()
|
|
}
|
|
|
|
// TODO - Improve this, this isn't safe
|
|
return nil
|
|
}
|
|
|
|
// Copy returns a pointer to a copy of the Map. Requires type assertion when used
|
|
func (m Map[K, V]) Copy() RVType {
|
|
copied := make(Map[K, V])
|
|
|
|
for key, value := range m {
|
|
copied[m.copyType(key).(K)] = value.Copy().(V)
|
|
}
|
|
|
|
return copied
|
|
}
|
|
|
|
func (m Map[K, V]) typesEqual(t1, t2 any) bool {
|
|
// * This just makes Map.Equals() a bit cleaner
|
|
// * since it doesn't have to type check
|
|
if rvt1, ok := t1.(RVType); ok {
|
|
if rvt2, ok := t2.(RVType); ok {
|
|
return rvt1.Equals(rvt2)
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
// Equals checks if the input is equal in value to the current instance
|
|
func (m Map[K, V]) Equals(o RVType) bool {
|
|
if _, ok := o.(Map[K, V]); !ok {
|
|
return false
|
|
}
|
|
|
|
other := o.(Map[K, V])
|
|
|
|
if len(m) != len(other) {
|
|
return false
|
|
}
|
|
|
|
for key, value := range m {
|
|
if otherValue, ok := other[key]; !ok || m.typesEqual(&value, &otherValue) {
|
|
return false
|
|
}
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
// CopyRef copies the current value of the Map
|
|
// and returns a pointer to the new copy
|
|
func (m Map[K, V]) CopyRef() RVTypePtr {
|
|
copied := m.Copy().(Map[K, V])
|
|
return &copied
|
|
}
|
|
|
|
// Deref takes a pointer to the Map
|
|
// and dereferences it to the raw value.
|
|
// Only useful when working with an instance of RVTypePtr
|
|
func (m *Map[K, V]) Deref() RVType {
|
|
return *m
|
|
}
|
|
|
|
// String returns a string representation of the struct
|
|
func (m Map[K, V]) String() string {
|
|
return m.FormatToString(0)
|
|
}
|
|
|
|
// FormatToString pretty-prints the struct data using the provided indentation level
|
|
func (m Map[K, V]) FormatToString(indentationLevel int) string {
|
|
indentationValues := strings.Repeat("\t", indentationLevel+1)
|
|
indentationEnd := strings.Repeat("\t", indentationLevel)
|
|
|
|
var b strings.Builder
|
|
|
|
if len(m) == 0 {
|
|
b.WriteString("{}\n")
|
|
} else {
|
|
b.WriteString("{\n")
|
|
|
|
for key, value := range m {
|
|
// TODO - Special handle the the last item to not add the comma on last item
|
|
b.WriteString(fmt.Sprintf("%s%v: %v,\n", indentationValues, key, value))
|
|
}
|
|
|
|
b.WriteString(fmt.Sprintf("%s}\n", indentationEnd))
|
|
}
|
|
|
|
return b.String()
|
|
}
|
|
|
|
// NewMap returns a new Map of the provided type
|
|
func NewMap[K comparable, V RVType]() Map[K, V] {
|
|
return make(Map[K, V])
|
|
}
|