garm/vendor/github.com/go-openapi/swag/jsonutils/adapters/registry.go
Gabriel Adrian Samfira 47537fb8b6 Update all dependencies
Update all deps.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
2026-01-06 01:13:34 +02:00

229 lines
7.3 KiB
Go

// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
// SPDX-License-Identifier: Apache-2.0
package adapters
import (
"fmt"
"reflect"
"slices"
"sync"
"github.com/go-openapi/swag/jsonutils/adapters/ifaces"
stdlib "github.com/go-openapi/swag/jsonutils/adapters/stdlib/json"
)
// Registry holds the global registry for registered adapters.
var Registry = NewRegistrar()
var (
defaultRegistered = stdlib.Register
_ ifaces.Registrar = &Registrar{}
)
type registryError string
func (e registryError) Error() string {
return string(e)
}
// ErrRegistry indicates an error returned by the [Registrar].
var ErrRegistry registryError = "JSON adapters registry error"
type registry []*ifaces.RegistryEntry
// Registrar holds registered [ifaces.Adapters] for different serialization capabilities.
//
// Internally, it maintains a cache for data types that favor a given adapter.
type Registrar struct {
marshalerRegistry registry
unmarshalerRegistry registry
orderedMarshalerRegistry registry
orderedUnmarshalerRegistry registry
orderedMapRegistry registry
gmx sync.RWMutex
// cache indexed by value type, so we don't have to lookup
marshalerCache map[reflect.Type]*ifaces.RegistryEntry
unmarshalerCache map[reflect.Type]*ifaces.RegistryEntry
orderedMarshalerCache map[reflect.Type]*ifaces.RegistryEntry
orderedUnmarshalerCache map[reflect.Type]*ifaces.RegistryEntry
orderedMapCache map[reflect.Type]*ifaces.RegistryEntry
}
func NewRegistrar() *Registrar {
r := &Registrar{}
r.marshalerRegistry = make(registry, 0, 1)
r.unmarshalerRegistry = make(registry, 0, 1)
r.orderedMarshalerRegistry = make(registry, 0, 1)
r.orderedUnmarshalerRegistry = make(registry, 0, 1)
r.orderedMapRegistry = make(registry, 0, 1)
r.marshalerCache = make(map[reflect.Type]*ifaces.RegistryEntry)
r.unmarshalerCache = make(map[reflect.Type]*ifaces.RegistryEntry)
r.orderedMarshalerCache = make(map[reflect.Type]*ifaces.RegistryEntry)
r.orderedUnmarshalerCache = make(map[reflect.Type]*ifaces.RegistryEntry)
r.orderedMapCache = make(map[reflect.Type]*ifaces.RegistryEntry)
defaultRegistered(r)
return r
}
// ClearCache resets the internal type cache.
func (r *Registrar) ClearCache() {
r.gmx.Lock()
r.clearCache()
r.gmx.Unlock()
}
// Reset the [Registrar] to its defaults.
func (r *Registrar) Reset() {
r.gmx.Lock()
r.clearCache()
r.marshalerRegistry = r.marshalerRegistry[:0]
r.unmarshalerRegistry = r.unmarshalerRegistry[:0]
r.orderedMarshalerRegistry = r.orderedMarshalerRegistry[:0]
r.orderedUnmarshalerRegistry = r.orderedUnmarshalerRegistry[:0]
r.orderedMapRegistry = r.orderedMapRegistry[:0]
r.gmx.Unlock()
defaultRegistered(r)
}
// RegisterFor registers an adapter for some JSON capabilities.
func (r *Registrar) RegisterFor(entry ifaces.RegistryEntry) {
r.gmx.Lock()
if entry.What.Has(ifaces.CapabilityMarshalJSON) {
e := entry
e.What &= ifaces.Capabilities(ifaces.CapabilityMarshalJSON)
r.marshalerRegistry = slices.Insert(r.marshalerRegistry, 0, &e)
}
if entry.What.Has(ifaces.CapabilityUnmarshalJSON) {
e := entry
e.What &= ifaces.Capabilities(ifaces.CapabilityUnmarshalJSON)
r.unmarshalerRegistry = slices.Insert(r.unmarshalerRegistry, 0, &e)
}
if entry.What.Has(ifaces.CapabilityOrderedMarshalJSON) {
e := entry
e.What &= ifaces.Capabilities(ifaces.CapabilityOrderedMarshalJSON)
r.orderedMarshalerRegistry = slices.Insert(r.orderedMarshalerRegistry, 0, &e)
}
if entry.What.Has(ifaces.CapabilityOrderedUnmarshalJSON) {
e := entry
e.What &= ifaces.Capabilities(ifaces.CapabilityOrderedUnmarshalJSON)
r.orderedUnmarshalerRegistry = slices.Insert(r.orderedUnmarshalerRegistry, 0, &e)
}
if entry.What.Has(ifaces.CapabilityOrderedMap) {
e := entry
e.What &= ifaces.Capabilities(ifaces.CapabilityOrderedMap)
r.orderedMapRegistry = slices.Insert(r.orderedMapRegistry, 0, &e)
}
r.gmx.Unlock()
}
// AdapterFor returns an [ifaces.Adapter] that supports this capability for this type of value.
//
// The [ifaces.Adapter] may be redeemed to its pool using its Redeem() method, for adapters that support global
// pooling. When this is not the case, the redeem function is just a no-operation.
func (r *Registrar) AdapterFor(capability ifaces.Capability, value any) ifaces.Adapter {
entry := r.findFirstFor(capability, value)
if entry == nil {
return nil
}
return entry.Constructor()
}
func (r *Registrar) clearCache() {
clear(r.marshalerCache)
clear(r.unmarshalerCache)
clear(r.orderedMarshalerCache)
clear(r.orderedUnmarshalerCache)
clear(r.orderedMapCache)
}
func (r *Registrar) findFirstFor(capability ifaces.Capability, value any) *ifaces.RegistryEntry {
switch capability {
case ifaces.CapabilityMarshalJSON:
return r.findFirstInRegistryFor(r.marshalerRegistry, r.marshalerCache, capability, value)
case ifaces.CapabilityUnmarshalJSON:
return r.findFirstInRegistryFor(r.unmarshalerRegistry, r.unmarshalerCache, capability, value)
case ifaces.CapabilityOrderedMarshalJSON:
return r.findFirstInRegistryFor(r.orderedMarshalerRegistry, r.orderedMarshalerCache, capability, value)
case ifaces.CapabilityOrderedUnmarshalJSON:
return r.findFirstInRegistryFor(r.orderedUnmarshalerRegistry, r.orderedUnmarshalerCache, capability, value)
case ifaces.CapabilityOrderedMap:
return r.findFirstInRegistryFor(r.orderedMapRegistry, r.orderedMapCache, capability, value)
default:
panic(fmt.Errorf("unsupported capability %d: %w", capability, ErrRegistry))
}
}
func (r *Registrar) findFirstInRegistryFor(reg registry, cache map[reflect.Type]*ifaces.RegistryEntry, capability ifaces.Capability, value any) *ifaces.RegistryEntry {
r.gmx.RLock()
if len(reg) > 1 {
if entry, ok := cache[reflect.TypeOf(value)]; ok {
// cache hit
r.gmx.RUnlock()
return entry
}
}
for _, entry := range reg {
if !entry.Support(capability, value) {
continue
}
r.gmx.RUnlock()
// update the internal cache
r.gmx.Lock()
cache[reflect.TypeOf(value)] = entry
r.gmx.Unlock()
return entry
}
// no adapter found
r.gmx.RUnlock()
return nil
}
// MarshalAdapterFor returns the first adapter that knows how to Marshal this type of value.
func MarshalAdapterFor(value any) ifaces.MarshalAdapter {
return Registry.AdapterFor(ifaces.CapabilityMarshalJSON, value)
}
// OrderedMarshalAdapterFor returns the first adapter that knows how to OrderedMarshal this type of value.
func OrderedMarshalAdapterFor(value ifaces.Ordered) ifaces.OrderedMarshalAdapter {
return Registry.AdapterFor(ifaces.CapabilityOrderedMarshalJSON, value)
}
// UnmarshalAdapterFor returns the first adapter that knows how to Unmarshal this type of value.
func UnmarshalAdapterFor(value any) ifaces.UnmarshalAdapter {
return Registry.AdapterFor(ifaces.CapabilityUnmarshalJSON, value)
}
// OrderedUnmarshalAdapterFor provides the first adapter that knows how to OrderedUnmarshal this type of value.
func OrderedUnmarshalAdapterFor(value ifaces.SetOrdered) ifaces.OrderedUnmarshalAdapter {
return Registry.AdapterFor(ifaces.CapabilityOrderedUnmarshalJSON, value)
}
// NewOrderedMap provides the "ordered map" implementation provided by the registry.
func NewOrderedMap(capacity int) ifaces.OrderedMap {
var v any
adapter := Registry.AdapterFor(ifaces.CapabilityOrderedUnmarshalJSON, v)
if adapter == nil {
return nil
}
defer adapter.Redeem()
return adapter.NewOrderedMap(capacity)
}
func noopRedeemer() {}