194 lines · 4.6 KB · Go
RawDownload
// Copyright 2022 Gregory Petrosyan <gregory.petrosyan@gmail.com>//// This Source Code Form is subject to the terms of the Mozilla Public// License, v. 2.0. If a copy of the MPL was not distributed with this// file, You can obtain one at https://mozilla.org/MPL/2.0/. package rapid import (	"fmt"	"reflect") // Make creates a generator of values of type V, using reflection to infer the required structure.func Make[V any]() *Generator[V] {	var zero V	gen := newMakeGen(reflect.TypeOf(zero))	return newGenerator[V](&makeGen[V]{		gen: gen,	})} type makeGen[V any] struct {	gen *Generator[any]} func (g *makeGen[V]) String() string {	var zero V	return fmt.Sprintf("Make[%T]()", zero)} func (g *makeGen[V]) value(t *T) V {	return g.gen.value(t).(V)} func newMakeGen(typ reflect.Type) *Generator[any] {	gen, mayNeedCast := newMakeKindGen(typ)	if !mayNeedCast || typ.String() == typ.Kind().String() {		return gen // fast path with less reflect	}	return newGenerator[any](&castGen{gen, typ})} type castGen struct {	gen *Generator[any]	typ reflect.Type} func (g *castGen) String() string {	return fmt.Sprintf("cast(%v, %v)", g.gen, g.typ.Name())} func (g *castGen) value(t *T) any {	v := g.gen.value(t)	return reflect.ValueOf(v).Convert(g.typ).Interface()} func newMakeKindGen(typ reflect.Type) (gen *Generator[any], mayNeedCast bool) {	switch typ.Kind() {	case reflect.Bool:		return Bool().AsAny(), true	case reflect.Int:		return Int().AsAny(), true	case reflect.Int8:		return Int8().AsAny(), true	case reflect.Int16:		return Int16().AsAny(), true	case reflect.Int32:		return Int32().AsAny(), true	case reflect.Int64:		return Int64().AsAny(), true	case reflect.Uint:		return Uint().AsAny(), true	case reflect.Uint8:		return Uint8().AsAny(), true	case reflect.Uint16:		return Uint16().AsAny(), true	case reflect.Uint32:		return Uint32().AsAny(), true	case reflect.Uint64:		return Uint64().AsAny(), true	case reflect.Uintptr:		return Uintptr().AsAny(), true	case reflect.Float32:		return Float32().AsAny(), true	case reflect.Float64:		return Float64().AsAny(), true	case reflect.Array:		return genAnyArray(typ), false	case reflect.Map:		return genAnyMap(typ), false	case reflect.Pointer:		return Deferred(func() *Generator[any] { return genAnyPointer(typ) }), false	case reflect.Slice:		return genAnySlice(typ), false	case reflect.String:		return String().AsAny(), true	case reflect.Struct:		return genAnyStruct(typ), false	default:		panic(fmt.Sprintf("unsupported type kind for Make: %v", typ.Kind()))	}} func genAnyPointer(typ reflect.Type) *Generator[any] {	elem := typ.Elem()	elemGen := newMakeGen(elem)	const pNonNil = 0.5 	return Custom[any](func(t *T) any {		if flipBiasedCoin(t.s, pNonNil) {			val := elemGen.value(t)			ptr := reflect.New(elem)			ptr.Elem().Set(reflect.ValueOf(val))			return ptr.Interface()		} else {			return reflect.Zero(typ).Interface()		}	})} func genAnyArray(typ reflect.Type) *Generator[any] {	count := typ.Len()	elemGen := newMakeGen(typ.Elem()) 	return Custom[any](func(t *T) any {		a := reflect.Indirect(reflect.New(typ))		if count == 0 {			t.s.drawBits(0)		} else {			for i := 0; i < count; i++ {				e := reflect.ValueOf(elemGen.value(t))				a.Index(i).Set(e)			}		}		return a.Interface()	})} func genAnySlice(typ reflect.Type) *Generator[any] {	elemGen := newMakeGen(typ.Elem()) 	return Custom[any](func(t *T) any {		repeat := newRepeat(-1, -1, -1, elemGen.String())		sl := reflect.MakeSlice(typ, 0, repeat.avg())		for repeat.more(t.s) {			e := reflect.ValueOf(elemGen.value(t))			sl = reflect.Append(sl, e)		}		return sl.Interface()	})} func genAnyMap(typ reflect.Type) *Generator[any] {	keyGen := newMakeGen(typ.Key())	valGen := newMakeGen(typ.Elem()) 	return Custom[any](func(t *T) any {		label := keyGen.String() + "," + valGen.String()		repeat := newRepeat(-1, -1, -1, label)		m := reflect.MakeMapWithSize(typ, repeat.avg())		for repeat.more(t.s) {			k := reflect.ValueOf(keyGen.value(t))			v := reflect.ValueOf(valGen.value(t))			if m.MapIndex(k).IsValid() {				repeat.reject()			} else {				m.SetMapIndex(k, v)			}		}		return m.Interface()	})} func genAnyStruct(typ reflect.Type) *Generator[any] {	numFields := typ.NumField()	fieldGens := make([]*Generator[any], numFields)	for i := 0; i < numFields; i++ {		fieldGens[i] = newMakeGen(typ.Field(i).Type)	} 	return Custom[any](func(t *T) any {		s := reflect.Indirect(reflect.New(typ))		if numFields == 0 {			t.s.drawBits(0)		} else {			for i := 0; i < numFields; i++ {				f := reflect.ValueOf(fieldGens[i].value(t))				s.Field(i).Set(f)			}		}		return s.Interface()	})}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t