mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-31 05:42:25 -05:00 
			
		
		
		
	
		
			
				
	
	
		
			1012 lines
		
	
	
	
		
			24 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			1012 lines
		
	
	
	
		
			24 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| //go:build validatedebug
 | |
| 
 | |
| package validate
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"runtime"
 | |
| 	"sync"
 | |
| 	"testing"
 | |
| 
 | |
| 	"github.com/go-openapi/spec"
 | |
| )
 | |
| 
 | |
| // This version of the pools is to be used for debugging and testing, with build tag "validatedebug".
 | |
| //
 | |
| // In this mode, the pools are tracked for allocation and redemption of borrowed objects, so we can
 | |
| // verify a few behaviors of the validators. The debug pools panic when an invalid usage pattern is detected.
 | |
| 
 | |
| var pools allPools
 | |
| 
 | |
| func init() {
 | |
| 	resetPools()
 | |
| }
 | |
| 
 | |
| func resetPools() {
 | |
| 	// NOTE: for testing purpose, we might want to reset pools after calling Validate twice.
 | |
| 	// The pool is corrupted in that case: calling Put twice inserts a duplicate in the pool
 | |
| 	// and further calls to Get are mishandled.
 | |
| 
 | |
| 	pools = allPools{
 | |
| 		poolOfSchemaValidators: schemaValidatorsPool{
 | |
| 			Pool: &sync.Pool{
 | |
| 				New: func() any {
 | |
| 					s := &SchemaValidator{}
 | |
| 
 | |
| 					return s
 | |
| 				},
 | |
| 			},
 | |
| 			debugMap:  make(map[*SchemaValidator]status),
 | |
| 			allocMap:  make(map[*SchemaValidator]string),
 | |
| 			redeemMap: make(map[*SchemaValidator]string),
 | |
| 		},
 | |
| 		poolOfObjectValidators: objectValidatorsPool{
 | |
| 			Pool: &sync.Pool{
 | |
| 				New: func() any {
 | |
| 					s := &objectValidator{}
 | |
| 
 | |
| 					return s
 | |
| 				},
 | |
| 			},
 | |
| 			debugMap:  make(map[*objectValidator]status),
 | |
| 			allocMap:  make(map[*objectValidator]string),
 | |
| 			redeemMap: make(map[*objectValidator]string),
 | |
| 		},
 | |
| 		poolOfSliceValidators: sliceValidatorsPool{
 | |
| 			Pool: &sync.Pool{
 | |
| 				New: func() any {
 | |
| 					s := &schemaSliceValidator{}
 | |
| 
 | |
| 					return s
 | |
| 				},
 | |
| 			},
 | |
| 			debugMap:  make(map[*schemaSliceValidator]status),
 | |
| 			allocMap:  make(map[*schemaSliceValidator]string),
 | |
| 			redeemMap: make(map[*schemaSliceValidator]string),
 | |
| 		},
 | |
| 		poolOfItemsValidators: itemsValidatorsPool{
 | |
| 			Pool: &sync.Pool{
 | |
| 				New: func() any {
 | |
| 					s := &itemsValidator{}
 | |
| 
 | |
| 					return s
 | |
| 				},
 | |
| 			},
 | |
| 			debugMap:  make(map[*itemsValidator]status),
 | |
| 			allocMap:  make(map[*itemsValidator]string),
 | |
| 			redeemMap: make(map[*itemsValidator]string),
 | |
| 		},
 | |
| 		poolOfBasicCommonValidators: basicCommonValidatorsPool{
 | |
| 			Pool: &sync.Pool{
 | |
| 				New: func() any {
 | |
| 					s := &basicCommonValidator{}
 | |
| 
 | |
| 					return s
 | |
| 				},
 | |
| 			},
 | |
| 			debugMap:  make(map[*basicCommonValidator]status),
 | |
| 			allocMap:  make(map[*basicCommonValidator]string),
 | |
| 			redeemMap: make(map[*basicCommonValidator]string),
 | |
| 		},
 | |
| 		poolOfHeaderValidators: headerValidatorsPool{
 | |
| 			Pool: &sync.Pool{
 | |
| 				New: func() any {
 | |
| 					s := &HeaderValidator{}
 | |
| 
 | |
| 					return s
 | |
| 				},
 | |
| 			},
 | |
| 			debugMap:  make(map[*HeaderValidator]status),
 | |
| 			allocMap:  make(map[*HeaderValidator]string),
 | |
| 			redeemMap: make(map[*HeaderValidator]string),
 | |
| 		},
 | |
| 		poolOfParamValidators: paramValidatorsPool{
 | |
| 			Pool: &sync.Pool{
 | |
| 				New: func() any {
 | |
| 					s := &ParamValidator{}
 | |
| 
 | |
| 					return s
 | |
| 				},
 | |
| 			},
 | |
| 			debugMap:  make(map[*ParamValidator]status),
 | |
| 			allocMap:  make(map[*ParamValidator]string),
 | |
| 			redeemMap: make(map[*ParamValidator]string),
 | |
| 		},
 | |
| 		poolOfBasicSliceValidators: basicSliceValidatorsPool{
 | |
| 			Pool: &sync.Pool{
 | |
| 				New: func() any {
 | |
| 					s := &basicSliceValidator{}
 | |
| 
 | |
| 					return s
 | |
| 				},
 | |
| 			},
 | |
| 			debugMap:  make(map[*basicSliceValidator]status),
 | |
| 			allocMap:  make(map[*basicSliceValidator]string),
 | |
| 			redeemMap: make(map[*basicSliceValidator]string),
 | |
| 		},
 | |
| 		poolOfNumberValidators: numberValidatorsPool{
 | |
| 			Pool: &sync.Pool{
 | |
| 				New: func() any {
 | |
| 					s := &numberValidator{}
 | |
| 
 | |
| 					return s
 | |
| 				},
 | |
| 			},
 | |
| 			debugMap:  make(map[*numberValidator]status),
 | |
| 			allocMap:  make(map[*numberValidator]string),
 | |
| 			redeemMap: make(map[*numberValidator]string),
 | |
| 		},
 | |
| 		poolOfStringValidators: stringValidatorsPool{
 | |
| 			Pool: &sync.Pool{
 | |
| 				New: func() any {
 | |
| 					s := &stringValidator{}
 | |
| 
 | |
| 					return s
 | |
| 				},
 | |
| 			},
 | |
| 			debugMap:  make(map[*stringValidator]status),
 | |
| 			allocMap:  make(map[*stringValidator]string),
 | |
| 			redeemMap: make(map[*stringValidator]string),
 | |
| 		},
 | |
| 		poolOfSchemaPropsValidators: schemaPropsValidatorsPool{
 | |
| 			Pool: &sync.Pool{
 | |
| 				New: func() any {
 | |
| 					s := &schemaPropsValidator{}
 | |
| 
 | |
| 					return s
 | |
| 				},
 | |
| 			},
 | |
| 			debugMap:  make(map[*schemaPropsValidator]status),
 | |
| 			allocMap:  make(map[*schemaPropsValidator]string),
 | |
| 			redeemMap: make(map[*schemaPropsValidator]string),
 | |
| 		},
 | |
| 		poolOfFormatValidators: formatValidatorsPool{
 | |
| 			Pool: &sync.Pool{
 | |
| 				New: func() any {
 | |
| 					s := &formatValidator{}
 | |
| 
 | |
| 					return s
 | |
| 				},
 | |
| 			},
 | |
| 			debugMap:  make(map[*formatValidator]status),
 | |
| 			allocMap:  make(map[*formatValidator]string),
 | |
| 			redeemMap: make(map[*formatValidator]string),
 | |
| 		},
 | |
| 		poolOfTypeValidators: typeValidatorsPool{
 | |
| 			Pool: &sync.Pool{
 | |
| 				New: func() any {
 | |
| 					s := &typeValidator{}
 | |
| 
 | |
| 					return s
 | |
| 				},
 | |
| 			},
 | |
| 			debugMap:  make(map[*typeValidator]status),
 | |
| 			allocMap:  make(map[*typeValidator]string),
 | |
| 			redeemMap: make(map[*typeValidator]string),
 | |
| 		},
 | |
| 		poolOfSchemas: schemasPool{
 | |
| 			Pool: &sync.Pool{
 | |
| 				New: func() any {
 | |
| 					s := &spec.Schema{}
 | |
| 
 | |
| 					return s
 | |
| 				},
 | |
| 			},
 | |
| 			debugMap:  make(map[*spec.Schema]status),
 | |
| 			allocMap:  make(map[*spec.Schema]string),
 | |
| 			redeemMap: make(map[*spec.Schema]string),
 | |
| 		},
 | |
| 		poolOfResults: resultsPool{
 | |
| 			Pool: &sync.Pool{
 | |
| 				New: func() any {
 | |
| 					s := &Result{}
 | |
| 
 | |
| 					return s
 | |
| 				},
 | |
| 			},
 | |
| 			debugMap:  make(map[*Result]status),
 | |
| 			allocMap:  make(map[*Result]string),
 | |
| 			redeemMap: make(map[*Result]string),
 | |
| 		},
 | |
| 	}
 | |
| }
 | |
| 
 | |
| const (
 | |
| 	statusFresh status = iota + 1
 | |
| 	statusRecycled
 | |
| 	statusRedeemed
 | |
| )
 | |
| 
 | |
| func (s status) String() string {
 | |
| 	switch s {
 | |
| 	case statusFresh:
 | |
| 		return "fresh"
 | |
| 	case statusRecycled:
 | |
| 		return "recycled"
 | |
| 	case statusRedeemed:
 | |
| 		return "redeemed"
 | |
| 	default:
 | |
| 		panic(fmt.Errorf("invalid status: %d", s))
 | |
| 	}
 | |
| }
 | |
| 
 | |
| type (
 | |
| 	// Debug
 | |
| 	status uint8
 | |
| 
 | |
| 	allPools struct {
 | |
| 		// memory pools for all validator objects.
 | |
| 		//
 | |
| 		// Each pool can be borrowed from and redeemed to.
 | |
| 		poolOfSchemaValidators      schemaValidatorsPool
 | |
| 		poolOfObjectValidators      objectValidatorsPool
 | |
| 		poolOfSliceValidators       sliceValidatorsPool
 | |
| 		poolOfItemsValidators       itemsValidatorsPool
 | |
| 		poolOfBasicCommonValidators basicCommonValidatorsPool
 | |
| 		poolOfHeaderValidators      headerValidatorsPool
 | |
| 		poolOfParamValidators       paramValidatorsPool
 | |
| 		poolOfBasicSliceValidators  basicSliceValidatorsPool
 | |
| 		poolOfNumberValidators      numberValidatorsPool
 | |
| 		poolOfStringValidators      stringValidatorsPool
 | |
| 		poolOfSchemaPropsValidators schemaPropsValidatorsPool
 | |
| 		poolOfFormatValidators      formatValidatorsPool
 | |
| 		poolOfTypeValidators        typeValidatorsPool
 | |
| 		poolOfSchemas               schemasPool
 | |
| 		poolOfResults               resultsPool
 | |
| 	}
 | |
| 
 | |
| 	schemaValidatorsPool struct {
 | |
| 		*sync.Pool
 | |
| 		debugMap  map[*SchemaValidator]status
 | |
| 		allocMap  map[*SchemaValidator]string
 | |
| 		redeemMap map[*SchemaValidator]string
 | |
| 		mx        sync.Mutex
 | |
| 	}
 | |
| 
 | |
| 	objectValidatorsPool struct {
 | |
| 		*sync.Pool
 | |
| 		debugMap  map[*objectValidator]status
 | |
| 		allocMap  map[*objectValidator]string
 | |
| 		redeemMap map[*objectValidator]string
 | |
| 		mx        sync.Mutex
 | |
| 	}
 | |
| 
 | |
| 	sliceValidatorsPool struct {
 | |
| 		*sync.Pool
 | |
| 		debugMap  map[*schemaSliceValidator]status
 | |
| 		allocMap  map[*schemaSliceValidator]string
 | |
| 		redeemMap map[*schemaSliceValidator]string
 | |
| 		mx        sync.Mutex
 | |
| 	}
 | |
| 
 | |
| 	itemsValidatorsPool struct {
 | |
| 		*sync.Pool
 | |
| 		debugMap  map[*itemsValidator]status
 | |
| 		allocMap  map[*itemsValidator]string
 | |
| 		redeemMap map[*itemsValidator]string
 | |
| 		mx        sync.Mutex
 | |
| 	}
 | |
| 
 | |
| 	basicCommonValidatorsPool struct {
 | |
| 		*sync.Pool
 | |
| 		debugMap  map[*basicCommonValidator]status
 | |
| 		allocMap  map[*basicCommonValidator]string
 | |
| 		redeemMap map[*basicCommonValidator]string
 | |
| 		mx        sync.Mutex
 | |
| 	}
 | |
| 
 | |
| 	headerValidatorsPool struct {
 | |
| 		*sync.Pool
 | |
| 		debugMap  map[*HeaderValidator]status
 | |
| 		allocMap  map[*HeaderValidator]string
 | |
| 		redeemMap map[*HeaderValidator]string
 | |
| 		mx        sync.Mutex
 | |
| 	}
 | |
| 
 | |
| 	paramValidatorsPool struct {
 | |
| 		*sync.Pool
 | |
| 		debugMap  map[*ParamValidator]status
 | |
| 		allocMap  map[*ParamValidator]string
 | |
| 		redeemMap map[*ParamValidator]string
 | |
| 		mx        sync.Mutex
 | |
| 	}
 | |
| 
 | |
| 	basicSliceValidatorsPool struct {
 | |
| 		*sync.Pool
 | |
| 		debugMap  map[*basicSliceValidator]status
 | |
| 		allocMap  map[*basicSliceValidator]string
 | |
| 		redeemMap map[*basicSliceValidator]string
 | |
| 		mx        sync.Mutex
 | |
| 	}
 | |
| 
 | |
| 	numberValidatorsPool struct {
 | |
| 		*sync.Pool
 | |
| 		debugMap  map[*numberValidator]status
 | |
| 		allocMap  map[*numberValidator]string
 | |
| 		redeemMap map[*numberValidator]string
 | |
| 		mx        sync.Mutex
 | |
| 	}
 | |
| 
 | |
| 	stringValidatorsPool struct {
 | |
| 		*sync.Pool
 | |
| 		debugMap  map[*stringValidator]status
 | |
| 		allocMap  map[*stringValidator]string
 | |
| 		redeemMap map[*stringValidator]string
 | |
| 		mx        sync.Mutex
 | |
| 	}
 | |
| 
 | |
| 	schemaPropsValidatorsPool struct {
 | |
| 		*sync.Pool
 | |
| 		debugMap  map[*schemaPropsValidator]status
 | |
| 		allocMap  map[*schemaPropsValidator]string
 | |
| 		redeemMap map[*schemaPropsValidator]string
 | |
| 		mx        sync.Mutex
 | |
| 	}
 | |
| 
 | |
| 	formatValidatorsPool struct {
 | |
| 		*sync.Pool
 | |
| 		debugMap  map[*formatValidator]status
 | |
| 		allocMap  map[*formatValidator]string
 | |
| 		redeemMap map[*formatValidator]string
 | |
| 		mx        sync.Mutex
 | |
| 	}
 | |
| 
 | |
| 	typeValidatorsPool struct {
 | |
| 		*sync.Pool
 | |
| 		debugMap  map[*typeValidator]status
 | |
| 		allocMap  map[*typeValidator]string
 | |
| 		redeemMap map[*typeValidator]string
 | |
| 		mx        sync.Mutex
 | |
| 	}
 | |
| 
 | |
| 	schemasPool struct {
 | |
| 		*sync.Pool
 | |
| 		debugMap  map[*spec.Schema]status
 | |
| 		allocMap  map[*spec.Schema]string
 | |
| 		redeemMap map[*spec.Schema]string
 | |
| 		mx        sync.Mutex
 | |
| 	}
 | |
| 
 | |
| 	resultsPool struct {
 | |
| 		*sync.Pool
 | |
| 		debugMap  map[*Result]status
 | |
| 		allocMap  map[*Result]string
 | |
| 		redeemMap map[*Result]string
 | |
| 		mx        sync.Mutex
 | |
| 	}
 | |
| )
 | |
| 
 | |
| func (p *schemaValidatorsPool) BorrowValidator() *SchemaValidator {
 | |
| 	s := p.Get().(*SchemaValidator)
 | |
| 
 | |
| 	p.mx.Lock()
 | |
| 	defer p.mx.Unlock()
 | |
| 	x, ok := p.debugMap[s]
 | |
| 	if !ok {
 | |
| 		p.debugMap[s] = statusFresh
 | |
| 	} else {
 | |
| 		if x != statusRedeemed {
 | |
| 			panic("recycled schema should have been redeemed")
 | |
| 		}
 | |
| 		p.debugMap[s] = statusRecycled
 | |
| 	}
 | |
| 	p.allocMap[s] = caller()
 | |
| 
 | |
| 	return s
 | |
| }
 | |
| 
 | |
| func (p *schemaValidatorsPool) RedeemValidator(s *SchemaValidator) {
 | |
| 	// NOTE: s might be nil. In that case, Put is a noop.
 | |
| 	p.mx.Lock()
 | |
| 	defer p.mx.Unlock()
 | |
| 	x, ok := p.debugMap[s]
 | |
| 	if !ok {
 | |
| 		panic("redeemed schema should have been allocated")
 | |
| 	}
 | |
| 	if x != statusRecycled && x != statusFresh {
 | |
| 		panic("redeemed schema should have been allocated from a fresh or recycled pointer")
 | |
| 	}
 | |
| 	p.debugMap[s] = statusRedeemed
 | |
| 	p.redeemMap[s] = caller()
 | |
| 	p.Put(s)
 | |
| }
 | |
| 
 | |
| func (p *objectValidatorsPool) BorrowValidator() *objectValidator {
 | |
| 	s := p.Get().(*objectValidator)
 | |
| 
 | |
| 	p.mx.Lock()
 | |
| 	defer p.mx.Unlock()
 | |
| 	x, ok := p.debugMap[s]
 | |
| 	if !ok {
 | |
| 		p.debugMap[s] = statusFresh
 | |
| 	} else {
 | |
| 		if x != statusRedeemed {
 | |
| 			panic("recycled object should have been redeemed")
 | |
| 		}
 | |
| 		p.debugMap[s] = statusRecycled
 | |
| 	}
 | |
| 	p.allocMap[s] = caller()
 | |
| 
 | |
| 	return s
 | |
| }
 | |
| 
 | |
| func (p *objectValidatorsPool) RedeemValidator(s *objectValidator) {
 | |
| 	p.mx.Lock()
 | |
| 	defer p.mx.Unlock()
 | |
| 	x, ok := p.debugMap[s]
 | |
| 	if !ok {
 | |
| 		panic("redeemed object should have been allocated")
 | |
| 	}
 | |
| 	if x != statusRecycled && x != statusFresh {
 | |
| 		panic("redeemed object should have been allocated from a fresh or recycled pointer")
 | |
| 	}
 | |
| 	p.debugMap[s] = statusRedeemed
 | |
| 	p.redeemMap[s] = caller()
 | |
| 	p.Put(s)
 | |
| }
 | |
| 
 | |
| func (p *sliceValidatorsPool) BorrowValidator() *schemaSliceValidator {
 | |
| 	s := p.Get().(*schemaSliceValidator)
 | |
| 
 | |
| 	p.mx.Lock()
 | |
| 	defer p.mx.Unlock()
 | |
| 	x, ok := p.debugMap[s]
 | |
| 	if !ok {
 | |
| 		p.debugMap[s] = statusFresh
 | |
| 	} else {
 | |
| 		if x != statusRedeemed {
 | |
| 			panic("recycled schemaSliceValidator should have been redeemed")
 | |
| 		}
 | |
| 		p.debugMap[s] = statusRecycled
 | |
| 	}
 | |
| 	p.allocMap[s] = caller()
 | |
| 
 | |
| 	return s
 | |
| }
 | |
| 
 | |
| func (p *sliceValidatorsPool) RedeemValidator(s *schemaSliceValidator) {
 | |
| 	p.mx.Lock()
 | |
| 	defer p.mx.Unlock()
 | |
| 	x, ok := p.debugMap[s]
 | |
| 	if !ok {
 | |
| 		panic("redeemed schemaSliceValidator should have been allocated")
 | |
| 	}
 | |
| 	if x != statusRecycled && x != statusFresh {
 | |
| 		panic("redeemed schemaSliceValidator should have been allocated from a fresh or recycled pointer")
 | |
| 	}
 | |
| 	p.debugMap[s] = statusRedeemed
 | |
| 	p.redeemMap[s] = caller()
 | |
| 	p.Put(s)
 | |
| }
 | |
| 
 | |
| func (p *itemsValidatorsPool) BorrowValidator() *itemsValidator {
 | |
| 	s := p.Get().(*itemsValidator)
 | |
| 
 | |
| 	p.mx.Lock()
 | |
| 	defer p.mx.Unlock()
 | |
| 	x, ok := p.debugMap[s]
 | |
| 	if !ok {
 | |
| 		p.debugMap[s] = statusFresh
 | |
| 	} else {
 | |
| 		if x != statusRedeemed {
 | |
| 			panic("recycled itemsValidator should have been redeemed")
 | |
| 		}
 | |
| 		p.debugMap[s] = statusRecycled
 | |
| 	}
 | |
| 	p.allocMap[s] = caller()
 | |
| 
 | |
| 	return s
 | |
| }
 | |
| 
 | |
| func (p *itemsValidatorsPool) RedeemValidator(s *itemsValidator) {
 | |
| 	p.mx.Lock()
 | |
| 	defer p.mx.Unlock()
 | |
| 	x, ok := p.debugMap[s]
 | |
| 	if !ok {
 | |
| 		panic("redeemed itemsValidator should have been allocated")
 | |
| 	}
 | |
| 	if x != statusRecycled && x != statusFresh {
 | |
| 		panic("redeemed itemsValidator should have been allocated from a fresh or recycled pointer")
 | |
| 	}
 | |
| 	p.debugMap[s] = statusRedeemed
 | |
| 	p.redeemMap[s] = caller()
 | |
| 	p.Put(s)
 | |
| }
 | |
| 
 | |
| func (p *basicCommonValidatorsPool) BorrowValidator() *basicCommonValidator {
 | |
| 	s := p.Get().(*basicCommonValidator)
 | |
| 
 | |
| 	p.mx.Lock()
 | |
| 	defer p.mx.Unlock()
 | |
| 	x, ok := p.debugMap[s]
 | |
| 	if !ok {
 | |
| 		p.debugMap[s] = statusFresh
 | |
| 	} else {
 | |
| 		if x != statusRedeemed {
 | |
| 			panic("recycled basicCommonValidator should have been redeemed")
 | |
| 		}
 | |
| 		p.debugMap[s] = statusRecycled
 | |
| 	}
 | |
| 	p.allocMap[s] = caller()
 | |
| 
 | |
| 	return s
 | |
| }
 | |
| 
 | |
| func (p *basicCommonValidatorsPool) RedeemValidator(s *basicCommonValidator) {
 | |
| 	p.mx.Lock()
 | |
| 	defer p.mx.Unlock()
 | |
| 	x, ok := p.debugMap[s]
 | |
| 	if !ok {
 | |
| 		panic("redeemed basicCommonValidator should have been allocated")
 | |
| 	}
 | |
| 	if x != statusRecycled && x != statusFresh {
 | |
| 		panic("redeemed basicCommonValidator should have been allocated from a fresh or recycled pointer")
 | |
| 	}
 | |
| 	p.debugMap[s] = statusRedeemed
 | |
| 	p.redeemMap[s] = caller()
 | |
| 	p.Put(s)
 | |
| }
 | |
| 
 | |
| func (p *headerValidatorsPool) BorrowValidator() *HeaderValidator {
 | |
| 	s := p.Get().(*HeaderValidator)
 | |
| 
 | |
| 	p.mx.Lock()
 | |
| 	defer p.mx.Unlock()
 | |
| 	x, ok := p.debugMap[s]
 | |
| 	if !ok {
 | |
| 		p.debugMap[s] = statusFresh
 | |
| 	} else {
 | |
| 		if x != statusRedeemed {
 | |
| 			panic("recycled HeaderValidator should have been redeemed")
 | |
| 		}
 | |
| 		p.debugMap[s] = statusRecycled
 | |
| 	}
 | |
| 	p.allocMap[s] = caller()
 | |
| 
 | |
| 	return s
 | |
| }
 | |
| 
 | |
| func (p *headerValidatorsPool) RedeemValidator(s *HeaderValidator) {
 | |
| 	p.mx.Lock()
 | |
| 	defer p.mx.Unlock()
 | |
| 	x, ok := p.debugMap[s]
 | |
| 	if !ok {
 | |
| 		panic("redeemed header should have been allocated")
 | |
| 	}
 | |
| 	if x != statusRecycled && x != statusFresh {
 | |
| 		panic("redeemed header should have been allocated from a fresh or recycled pointer")
 | |
| 	}
 | |
| 	p.debugMap[s] = statusRedeemed
 | |
| 	p.redeemMap[s] = caller()
 | |
| 	p.Put(s)
 | |
| }
 | |
| 
 | |
| func (p *paramValidatorsPool) BorrowValidator() *ParamValidator {
 | |
| 	s := p.Get().(*ParamValidator)
 | |
| 
 | |
| 	p.mx.Lock()
 | |
| 	defer p.mx.Unlock()
 | |
| 	x, ok := p.debugMap[s]
 | |
| 	if !ok {
 | |
| 		p.debugMap[s] = statusFresh
 | |
| 	} else {
 | |
| 		if x != statusRedeemed {
 | |
| 			panic("recycled param should have been redeemed")
 | |
| 		}
 | |
| 		p.debugMap[s] = statusRecycled
 | |
| 	}
 | |
| 	p.allocMap[s] = caller()
 | |
| 
 | |
| 	return s
 | |
| }
 | |
| 
 | |
| func (p *paramValidatorsPool) RedeemValidator(s *ParamValidator) {
 | |
| 	p.mx.Lock()
 | |
| 	defer p.mx.Unlock()
 | |
| 	x, ok := p.debugMap[s]
 | |
| 	if !ok {
 | |
| 		panic("redeemed param should have been allocated")
 | |
| 	}
 | |
| 	if x != statusRecycled && x != statusFresh {
 | |
| 		panic("redeemed param should have been allocated from a fresh or recycled pointer")
 | |
| 	}
 | |
| 	p.debugMap[s] = statusRedeemed
 | |
| 	p.redeemMap[s] = caller()
 | |
| 	p.Put(s)
 | |
| }
 | |
| 
 | |
| func (p *basicSliceValidatorsPool) BorrowValidator() *basicSliceValidator {
 | |
| 	s := p.Get().(*basicSliceValidator)
 | |
| 
 | |
| 	p.mx.Lock()
 | |
| 	defer p.mx.Unlock()
 | |
| 	x, ok := p.debugMap[s]
 | |
| 	if !ok {
 | |
| 		p.debugMap[s] = statusFresh
 | |
| 	} else {
 | |
| 		if x != statusRedeemed {
 | |
| 			panic("recycled basicSliceValidator should have been redeemed")
 | |
| 		}
 | |
| 		p.debugMap[s] = statusRecycled
 | |
| 	}
 | |
| 	p.allocMap[s] = caller()
 | |
| 
 | |
| 	return s
 | |
| }
 | |
| 
 | |
| func (p *basicSliceValidatorsPool) RedeemValidator(s *basicSliceValidator) {
 | |
| 	p.mx.Lock()
 | |
| 	defer p.mx.Unlock()
 | |
| 	x, ok := p.debugMap[s]
 | |
| 	if !ok {
 | |
| 		panic("redeemed basicSliceValidator should have been allocated")
 | |
| 	}
 | |
| 	if x != statusRecycled && x != statusFresh {
 | |
| 		panic("redeemed basicSliceValidator should have been allocated from a fresh or recycled pointer")
 | |
| 	}
 | |
| 	p.debugMap[s] = statusRedeemed
 | |
| 	p.redeemMap[s] = caller()
 | |
| 	p.Put(s)
 | |
| }
 | |
| 
 | |
| func (p *numberValidatorsPool) BorrowValidator() *numberValidator {
 | |
| 	s := p.Get().(*numberValidator)
 | |
| 
 | |
| 	p.mx.Lock()
 | |
| 	defer p.mx.Unlock()
 | |
| 	x, ok := p.debugMap[s]
 | |
| 	if !ok {
 | |
| 		p.debugMap[s] = statusFresh
 | |
| 	} else {
 | |
| 		if x != statusRedeemed {
 | |
| 			panic("recycled number should have been redeemed")
 | |
| 		}
 | |
| 		p.debugMap[s] = statusRecycled
 | |
| 	}
 | |
| 	p.allocMap[s] = caller()
 | |
| 
 | |
| 	return s
 | |
| }
 | |
| 
 | |
| func (p *numberValidatorsPool) RedeemValidator(s *numberValidator) {
 | |
| 	p.mx.Lock()
 | |
| 	defer p.mx.Unlock()
 | |
| 	x, ok := p.debugMap[s]
 | |
| 	if !ok {
 | |
| 		panic("redeemed number should have been allocated")
 | |
| 	}
 | |
| 	if x != statusRecycled && x != statusFresh {
 | |
| 		panic("redeemed number should have been allocated from a fresh or recycled pointer")
 | |
| 	}
 | |
| 	p.debugMap[s] = statusRedeemed
 | |
| 	p.redeemMap[s] = caller()
 | |
| 	p.Put(s)
 | |
| }
 | |
| 
 | |
| func (p *stringValidatorsPool) BorrowValidator() *stringValidator {
 | |
| 	s := p.Get().(*stringValidator)
 | |
| 
 | |
| 	p.mx.Lock()
 | |
| 	defer p.mx.Unlock()
 | |
| 	x, ok := p.debugMap[s]
 | |
| 	if !ok {
 | |
| 		p.debugMap[s] = statusFresh
 | |
| 	} else {
 | |
| 		if x != statusRedeemed {
 | |
| 			panic("recycled string should have been redeemed")
 | |
| 		}
 | |
| 		p.debugMap[s] = statusRecycled
 | |
| 	}
 | |
| 	p.allocMap[s] = caller()
 | |
| 
 | |
| 	return s
 | |
| }
 | |
| 
 | |
| func (p *stringValidatorsPool) RedeemValidator(s *stringValidator) {
 | |
| 	p.mx.Lock()
 | |
| 	defer p.mx.Unlock()
 | |
| 	x, ok := p.debugMap[s]
 | |
| 	if !ok {
 | |
| 		panic("redeemed string should have been allocated")
 | |
| 	}
 | |
| 	if x != statusRecycled && x != statusFresh {
 | |
| 		panic("redeemed string should have been allocated from a fresh or recycled pointer")
 | |
| 	}
 | |
| 	p.debugMap[s] = statusRedeemed
 | |
| 	p.redeemMap[s] = caller()
 | |
| 	p.Put(s)
 | |
| }
 | |
| 
 | |
| func (p *schemaPropsValidatorsPool) BorrowValidator() *schemaPropsValidator {
 | |
| 	s := p.Get().(*schemaPropsValidator)
 | |
| 
 | |
| 	p.mx.Lock()
 | |
| 	defer p.mx.Unlock()
 | |
| 	x, ok := p.debugMap[s]
 | |
| 	if !ok {
 | |
| 		p.debugMap[s] = statusFresh
 | |
| 	} else {
 | |
| 		if x != statusRedeemed {
 | |
| 			panic("recycled param should have been redeemed")
 | |
| 		}
 | |
| 		p.debugMap[s] = statusRecycled
 | |
| 	}
 | |
| 	p.allocMap[s] = caller()
 | |
| 
 | |
| 	return s
 | |
| }
 | |
| 
 | |
| func (p *schemaPropsValidatorsPool) RedeemValidator(s *schemaPropsValidator) {
 | |
| 	p.mx.Lock()
 | |
| 	defer p.mx.Unlock()
 | |
| 	x, ok := p.debugMap[s]
 | |
| 	if !ok {
 | |
| 		panic("redeemed schemaProps should have been allocated")
 | |
| 	}
 | |
| 	if x != statusRecycled && x != statusFresh {
 | |
| 		panic("redeemed schemaProps should have been allocated from a fresh or recycled pointer")
 | |
| 	}
 | |
| 	p.debugMap[s] = statusRedeemed
 | |
| 	p.redeemMap[s] = caller()
 | |
| 	p.Put(s)
 | |
| }
 | |
| 
 | |
| func (p *formatValidatorsPool) BorrowValidator() *formatValidator {
 | |
| 	s := p.Get().(*formatValidator)
 | |
| 
 | |
| 	p.mx.Lock()
 | |
| 	defer p.mx.Unlock()
 | |
| 	x, ok := p.debugMap[s]
 | |
| 	if !ok {
 | |
| 		p.debugMap[s] = statusFresh
 | |
| 	} else {
 | |
| 		if x != statusRedeemed {
 | |
| 			panic("recycled format should have been redeemed")
 | |
| 		}
 | |
| 		p.debugMap[s] = statusRecycled
 | |
| 	}
 | |
| 	p.allocMap[s] = caller()
 | |
| 
 | |
| 	return s
 | |
| }
 | |
| 
 | |
| func (p *formatValidatorsPool) RedeemValidator(s *formatValidator) {
 | |
| 	p.mx.Lock()
 | |
| 	defer p.mx.Unlock()
 | |
| 	x, ok := p.debugMap[s]
 | |
| 	if !ok {
 | |
| 		panic("redeemed format should have been allocated")
 | |
| 	}
 | |
| 	if x != statusRecycled && x != statusFresh {
 | |
| 		panic("redeemed format should have been allocated from a fresh or recycled pointer")
 | |
| 	}
 | |
| 	p.debugMap[s] = statusRedeemed
 | |
| 	p.redeemMap[s] = caller()
 | |
| 	p.Put(s)
 | |
| }
 | |
| 
 | |
| func (p *typeValidatorsPool) BorrowValidator() *typeValidator {
 | |
| 	s := p.Get().(*typeValidator)
 | |
| 
 | |
| 	p.mx.Lock()
 | |
| 	defer p.mx.Unlock()
 | |
| 	x, ok := p.debugMap[s]
 | |
| 	if !ok {
 | |
| 		p.debugMap[s] = statusFresh
 | |
| 	} else {
 | |
| 		if x != statusRedeemed {
 | |
| 			panic("recycled type should have been redeemed")
 | |
| 		}
 | |
| 		p.debugMap[s] = statusRecycled
 | |
| 	}
 | |
| 	p.allocMap[s] = caller()
 | |
| 
 | |
| 	return s
 | |
| }
 | |
| 
 | |
| func (p *typeValidatorsPool) RedeemValidator(s *typeValidator) {
 | |
| 	p.mx.Lock()
 | |
| 	defer p.mx.Unlock()
 | |
| 	x, ok := p.debugMap[s]
 | |
| 	if !ok {
 | |
| 		panic("redeemed type should have been allocated")
 | |
| 	}
 | |
| 	if x != statusRecycled && x != statusFresh {
 | |
| 		panic(fmt.Errorf("redeemed type should have been allocated from a fresh or recycled pointer. Got status %s, already redeamed at: %s", x, p.redeemMap[s]))
 | |
| 	}
 | |
| 	p.debugMap[s] = statusRedeemed
 | |
| 	p.redeemMap[s] = caller()
 | |
| 	p.Put(s)
 | |
| }
 | |
| 
 | |
| func (p *schemasPool) BorrowSchema() *spec.Schema {
 | |
| 	s := p.Get().(*spec.Schema)
 | |
| 
 | |
| 	p.mx.Lock()
 | |
| 	defer p.mx.Unlock()
 | |
| 	x, ok := p.debugMap[s]
 | |
| 	if !ok {
 | |
| 		p.debugMap[s] = statusFresh
 | |
| 	} else {
 | |
| 		if x != statusRedeemed {
 | |
| 			panic("recycled spec.Schema should have been redeemed")
 | |
| 		}
 | |
| 		p.debugMap[s] = statusRecycled
 | |
| 	}
 | |
| 	p.allocMap[s] = caller()
 | |
| 
 | |
| 	return s
 | |
| }
 | |
| 
 | |
| func (p *schemasPool) RedeemSchema(s *spec.Schema) {
 | |
| 	p.mx.Lock()
 | |
| 	defer p.mx.Unlock()
 | |
| 	x, ok := p.debugMap[s]
 | |
| 	if !ok {
 | |
| 		panic("redeemed spec.Schema should have been allocated")
 | |
| 	}
 | |
| 	if x != statusRecycled && x != statusFresh {
 | |
| 		panic("redeemed spec.Schema should have been allocated from a fresh or recycled pointer")
 | |
| 	}
 | |
| 	p.debugMap[s] = statusRedeemed
 | |
| 	p.redeemMap[s] = caller()
 | |
| 	p.Put(s)
 | |
| }
 | |
| 
 | |
| func (p *resultsPool) BorrowResult() *Result {
 | |
| 	s := p.Get().(*Result).cleared()
 | |
| 
 | |
| 	p.mx.Lock()
 | |
| 	defer p.mx.Unlock()
 | |
| 	x, ok := p.debugMap[s]
 | |
| 	if !ok {
 | |
| 		p.debugMap[s] = statusFresh
 | |
| 	} else {
 | |
| 		if x != statusRedeemed {
 | |
| 			panic("recycled result should have been redeemed")
 | |
| 		}
 | |
| 		p.debugMap[s] = statusRecycled
 | |
| 	}
 | |
| 	p.allocMap[s] = caller()
 | |
| 
 | |
| 	return s
 | |
| }
 | |
| 
 | |
| func (p *resultsPool) RedeemResult(s *Result) {
 | |
| 	if s == emptyResult {
 | |
| 		if len(s.Errors) > 0 || len(s.Warnings) > 0 {
 | |
| 			panic("empty result should not mutate")
 | |
| 		}
 | |
| 		return
 | |
| 	}
 | |
| 	p.mx.Lock()
 | |
| 	defer p.mx.Unlock()
 | |
| 	x, ok := p.debugMap[s]
 | |
| 	if !ok {
 | |
| 		panic("redeemed Result should have been allocated")
 | |
| 	}
 | |
| 	if x != statusRecycled && x != statusFresh {
 | |
| 		panic("redeemed Result should have been allocated from a fresh or recycled pointer")
 | |
| 	}
 | |
| 	p.debugMap[s] = statusRedeemed
 | |
| 	p.redeemMap[s] = caller()
 | |
| 	p.Put(s)
 | |
| }
 | |
| 
 | |
| func (p *allPools) allIsRedeemed(t testing.TB) bool {
 | |
| 	outcome := true
 | |
| 	for k, v := range p.poolOfSchemaValidators.debugMap {
 | |
| 		if v == statusRedeemed {
 | |
| 			continue
 | |
| 		}
 | |
| 		t.Logf("schemaValidator should be redeemed. Allocated by: %s", p.poolOfSchemaValidators.allocMap[k])
 | |
| 		outcome = false
 | |
| 	}
 | |
| 	for k, v := range p.poolOfObjectValidators.debugMap {
 | |
| 		if v == statusRedeemed {
 | |
| 			continue
 | |
| 		}
 | |
| 		t.Logf("objectValidator should be redeemed. Allocated by: %s", p.poolOfObjectValidators.allocMap[k])
 | |
| 		outcome = false
 | |
| 	}
 | |
| 	for k, v := range p.poolOfSliceValidators.debugMap {
 | |
| 		if v == statusRedeemed {
 | |
| 			continue
 | |
| 		}
 | |
| 		t.Logf("sliceValidator should be redeemed. Allocated by: %s", p.poolOfSliceValidators.allocMap[k])
 | |
| 		outcome = false
 | |
| 	}
 | |
| 	for k, v := range p.poolOfItemsValidators.debugMap {
 | |
| 		if v == statusRedeemed {
 | |
| 			continue
 | |
| 		}
 | |
| 		t.Logf("itemsValidator should be redeemed. Allocated by: %s", p.poolOfItemsValidators.allocMap[k])
 | |
| 		outcome = false
 | |
| 	}
 | |
| 	for k, v := range p.poolOfBasicCommonValidators.debugMap {
 | |
| 		if v == statusRedeemed {
 | |
| 			continue
 | |
| 		}
 | |
| 		t.Logf("basicCommonValidator should be redeemed. Allocated by: %s", p.poolOfBasicCommonValidators.allocMap[k])
 | |
| 		outcome = false
 | |
| 	}
 | |
| 	for k, v := range p.poolOfHeaderValidators.debugMap {
 | |
| 		if v == statusRedeemed {
 | |
| 			continue
 | |
| 		}
 | |
| 		t.Logf("headerValidator should be redeemed. Allocated by: %s", p.poolOfHeaderValidators.allocMap[k])
 | |
| 		outcome = false
 | |
| 	}
 | |
| 	for k, v := range p.poolOfParamValidators.debugMap {
 | |
| 		if v == statusRedeemed {
 | |
| 			continue
 | |
| 		}
 | |
| 		t.Logf("paramValidator should be redeemed. Allocated by: %s", p.poolOfParamValidators.allocMap[k])
 | |
| 		outcome = false
 | |
| 	}
 | |
| 	for k, v := range p.poolOfBasicSliceValidators.debugMap {
 | |
| 		if v == statusRedeemed {
 | |
| 			continue
 | |
| 		}
 | |
| 		t.Logf("basicSliceValidator should be redeemed. Allocated by: %s", p.poolOfBasicSliceValidators.allocMap[k])
 | |
| 		outcome = false
 | |
| 	}
 | |
| 	for k, v := range p.poolOfNumberValidators.debugMap {
 | |
| 		if v == statusRedeemed {
 | |
| 			continue
 | |
| 		}
 | |
| 		t.Logf("numberValidator should be redeemed. Allocated by: %s", p.poolOfNumberValidators.allocMap[k])
 | |
| 		outcome = false
 | |
| 	}
 | |
| 	for k, v := range p.poolOfStringValidators.debugMap {
 | |
| 		if v == statusRedeemed {
 | |
| 			continue
 | |
| 		}
 | |
| 		t.Logf("stringValidator should be redeemed. Allocated by: %s", p.poolOfStringValidators.allocMap[k])
 | |
| 		outcome = false
 | |
| 	}
 | |
| 	for k, v := range p.poolOfSchemaPropsValidators.debugMap {
 | |
| 		if v == statusRedeemed {
 | |
| 			continue
 | |
| 		}
 | |
| 		t.Logf("schemaPropsValidator should be redeemed. Allocated by: %s", p.poolOfSchemaPropsValidators.allocMap[k])
 | |
| 		outcome = false
 | |
| 	}
 | |
| 	for k, v := range p.poolOfFormatValidators.debugMap {
 | |
| 		if v == statusRedeemed {
 | |
| 			continue
 | |
| 		}
 | |
| 		t.Logf("formatValidator should be redeemed. Allocated by: %s", p.poolOfFormatValidators.allocMap[k])
 | |
| 		outcome = false
 | |
| 	}
 | |
| 	for k, v := range p.poolOfTypeValidators.debugMap {
 | |
| 		if v == statusRedeemed {
 | |
| 			continue
 | |
| 		}
 | |
| 		t.Logf("typeValidator should be redeemed. Allocated by: %s", p.poolOfTypeValidators.allocMap[k])
 | |
| 		outcome = false
 | |
| 	}
 | |
| 	for k, v := range p.poolOfSchemas.debugMap {
 | |
| 		if v == statusRedeemed {
 | |
| 			continue
 | |
| 		}
 | |
| 		t.Logf("schemas should be redeemed. Allocated by: %s", p.poolOfSchemas.allocMap[k])
 | |
| 		outcome = false
 | |
| 	}
 | |
| 	for k, v := range p.poolOfResults.debugMap {
 | |
| 		if v == statusRedeemed {
 | |
| 			continue
 | |
| 		}
 | |
| 		t.Logf("result should be redeemed. Allocated by: %s", p.poolOfResults.allocMap[k])
 | |
| 		outcome = false
 | |
| 	}
 | |
| 
 | |
| 	return outcome
 | |
| }
 | |
| 
 | |
| func caller() string {
 | |
| 	pc, _, _, _ := runtime.Caller(3) //nolint:dogsled
 | |
| 	from, line := runtime.FuncForPC(pc).FileLine(pc)
 | |
| 
 | |
| 	return fmt.Sprintf("%s:%d", from, line)
 | |
| }
 |