utils/bimap: drop json/v2 marshaler, keep type generic

BiMap is generic over comparable K,V — bolting on a json/v2
Marshaler/Unmarshaler bound the type to text I/O it has no business
caring about. Removed the marshaler interface and the dependent tests;
no consumer of BiMap in the node module relied on JSON.

Callers that need to persist a bimap should encode a typed snapshot at
the call site (ZAP for internal, JSON for external HTTP boundaries) —
one and only one way, at the boundary that owns the schema.
This commit is contained in:
Hanzo AI
2026-06-06 23:14:29 -07:00
parent 6ce568e251
commit 92fc09acdf
2 changed files with 8 additions and 63 deletions
+5 -36
View File
@@ -1,26 +1,20 @@
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
// Package bimap is an in-memory bi-directional map. Serialization is the
// caller's concern — this type is generic over comparable K/V, and the
// internal Lux wire format is ZAP, which is element-typed. Use a typed
// ZAP schema (or a typed snapshot struct) at the call site to persist a
// bimap; do not bolt a generic marshaler onto BiMap itself.
package bimap
import (
"bytes"
"github.com/go-json-experiment/json"
"errors"
"maps"
"slices"
"github.com/luxfi/node/utils"
)
var (
_ json.Marshaler = (*BiMap[int, int])(nil)
_ json.Unmarshaler = (*BiMap[int, int])(nil)
nullBytes = []byte("null")
errNotBijective = errors.New("map not bijective")
)
type Entry[K, V any] struct {
Key K
Value V
@@ -127,28 +121,3 @@ func (m *BiMap[_, V]) Values() []V {
func (m *BiMap[K, V]) Len() int {
return len(m.keyToValue)
}
func (m *BiMap[K, V]) MarshalJSON() ([]byte, error) {
return json.Marshal(m.keyToValue)
}
func (m *BiMap[K, V]) UnmarshalJSON(b []byte) error {
if bytes.Equal(b, nullBytes) {
return nil
}
var keyToValue map[K]V
if err := json.Unmarshal(b, &keyToValue); err != nil {
return err
}
valueToKey := make(map[V]K, len(keyToValue))
for k, v := range keyToValue {
valueToKey[v] = k
}
if len(keyToValue) != len(valueToKey) {
return errNotBijective
}
m.keyToValue = keyToValue
m.valueToKey = valueToKey
return nil
}
+3 -27
View File
@@ -4,7 +4,6 @@
package bimap
import (
"github.com/go-json-experiment/json"
"testing"
"github.com/stretchr/testify/require"
@@ -338,29 +337,6 @@ func TestBiMapLenAndLists(t *testing.T) {
require.Empty(m.Values())
}
func TestBiMapJSON(t *testing.T) {
require := require.New(t)
expectedMap := New[int, int]()
expectedMap.Put(1, 2)
expectedMap.Put(2, 3)
jsonBytes, err := json.Marshal(expectedMap)
require.NoError(err)
expectedJSONBytes := []byte(`{"1":2,"2":3}`)
require.JSONEq(string(expectedJSONBytes), string(jsonBytes))
var unmarshalledMap BiMap[int, int]
require.NoError(json.Unmarshal(jsonBytes, &unmarshalledMap))
require.Equal(expectedMap, &unmarshalledMap)
}
func TestBiMapInvalidJSON(t *testing.T) {
require := require.New(t)
invalidJSONBytes := []byte(`{"1":2,"2":2}`)
var unmarshalledMap BiMap[int, int]
err := json.Unmarshal(invalidJSONBytes, &unmarshalledMap)
require.ErrorIs(err, errNotBijective)
}
// JSON marshal/unmarshal tests removed: BiMap no longer carries a
// generic codec. The internal Lux wire format is ZAP, which is element-
// typed; persist a typed snapshot at the call site if needed.