Vendor main dependencies.
This commit is contained in:
parent
49a09ab7dd
commit
dd5e3fba01
2738 changed files with 1045689 additions and 0 deletions
13
vendor/github.com/BurntSushi/ty/COPYING
generated
vendored
Normal file
13
vendor/github.com/BurntSushi/ty/COPYING
generated
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
Version 2, December 2004
|
||||
|
||||
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim or modified
|
||||
copies of this license document, and changing it is allowed as long
|
||||
as the name is changed.
|
||||
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. You just DO WHAT THE FUCK YOU WANT TO.
|
22
vendor/github.com/BurntSushi/ty/doc.go
generated
vendored
Normal file
22
vendor/github.com/BurntSushi/ty/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
Package ty provides utilities for writing type parametric functions with run
|
||||
time type safety.
|
||||
|
||||
This package contains two sub-packages `fun` and `data` which define some
|
||||
potentially useful functions and abstractions using the type checker in
|
||||
this package.
|
||||
|
||||
Requirements
|
||||
|
||||
Go tip (or 1.1 when it's released) is required. This package will not work
|
||||
with Go 1.0.x or earlier.
|
||||
|
||||
The very foundation of this package only recently became possible with the
|
||||
addition of 3 new functions in the standard library `reflect` package:
|
||||
SliceOf, MapOf and ChanOf. In particular, it provides the ability to
|
||||
dynamically construct types at run time from component types.
|
||||
|
||||
Further extensions to this package can be made if similar functions are added
|
||||
for structs and functions(?).
|
||||
*/
|
||||
package ty
|
84
vendor/github.com/BurntSushi/ty/fun/chan.go
generated
vendored
Normal file
84
vendor/github.com/BurntSushi/ty/fun/chan.go
generated
vendored
Normal file
|
@ -0,0 +1,84 @@
|
|||
package fun
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/BurntSushi/ty"
|
||||
)
|
||||
|
||||
// AsyncChan has a parametric type:
|
||||
//
|
||||
// func AsyncChan(chan A) (send chan<- A, recv <-chan A)
|
||||
//
|
||||
// AsyncChan provides a channel abstraction without a fixed size buffer.
|
||||
// The input should be a pointer to a channel that has a type without a
|
||||
// direction, e.g., `new(chan int)`. Two new channels are returned: `send` and
|
||||
// `recv`. The caller must send data on the `send` channel and receive data on
|
||||
// the `recv` channel.
|
||||
//
|
||||
// Implementation is inspired by Kyle Lemons' work:
|
||||
// https://github.com/kylelemons/iq/blob/master/iq_slice.go
|
||||
func AsyncChan(baseChan interface{}) (send, recv interface{}) {
|
||||
chk := ty.Check(
|
||||
new(func(*chan ty.A) (chan ty.A, chan ty.A)),
|
||||
baseChan)
|
||||
|
||||
// We don't care about the baseChan---it is only used to construct
|
||||
// the return types.
|
||||
tsend, trecv := chk.Returns[0], chk.Returns[1]
|
||||
|
||||
buf := make([]reflect.Value, 0, 10)
|
||||
rsend := reflect.MakeChan(tsend, 0)
|
||||
rrecv := reflect.MakeChan(trecv, 0)
|
||||
|
||||
go func() {
|
||||
defer rrecv.Close()
|
||||
|
||||
BUFLOOP:
|
||||
for {
|
||||
if len(buf) == 0 {
|
||||
rv, ok := rsend.Recv()
|
||||
if !ok {
|
||||
break BUFLOOP
|
||||
}
|
||||
buf = append(buf, rv)
|
||||
}
|
||||
|
||||
cases := []reflect.SelectCase{
|
||||
// case v, ok := <-send
|
||||
{
|
||||
Dir: reflect.SelectRecv,
|
||||
Chan: rsend,
|
||||
},
|
||||
// case recv <- buf[0]
|
||||
{
|
||||
Dir: reflect.SelectSend,
|
||||
Chan: rrecv,
|
||||
Send: buf[0],
|
||||
},
|
||||
}
|
||||
choice, rval, rok := reflect.Select(cases)
|
||||
switch choice {
|
||||
case 0:
|
||||
// case v, ok := <-send
|
||||
if !rok {
|
||||
break BUFLOOP
|
||||
}
|
||||
buf = append(buf, rval)
|
||||
case 1:
|
||||
// case recv <- buf[0]
|
||||
buf = buf[1:]
|
||||
default:
|
||||
panic("bug")
|
||||
}
|
||||
}
|
||||
for _, rv := range buf {
|
||||
rrecv.Send(rv)
|
||||
}
|
||||
}()
|
||||
|
||||
// Create the directional channel types.
|
||||
tsDir := reflect.ChanOf(reflect.SendDir, tsend.Elem())
|
||||
trDir := reflect.ChanOf(reflect.RecvDir, trecv.Elem())
|
||||
return rsend.Convert(tsDir).Interface(), rrecv.Convert(trDir).Interface()
|
||||
}
|
118
vendor/github.com/BurntSushi/ty/fun/doc.go
generated
vendored
Normal file
118
vendor/github.com/BurntSushi/ty/fun/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
Package fun provides type parametric utility functions for lists, sets,
|
||||
channels and maps.
|
||||
|
||||
The central contribution of this package is a set of functions that operate
|
||||
on values without depending on their types while maintaining type safety at
|
||||
run time using the `reflect` package.
|
||||
|
||||
There are two primary concerns when deciding whether to use this package
|
||||
or not: the loss of compile time type safety and performance. In particular,
|
||||
with regard to performance, most functions here are much slower than their
|
||||
built-in counter parts. However, there are a couple where the overhead of
|
||||
reflection is relatively insignificant: AsyncChan and ParMap.
|
||||
|
||||
In terms of code structure and organization, the price is mostly paid inside
|
||||
of the package due to the annoyances of operating with `reflect`. The caller
|
||||
usually only has one obligation other than to provide values consistent with
|
||||
the type of the function: type assert the result to the desired type.
|
||||
|
||||
When the caller provides values that are inconsistent with the parametric type
|
||||
of the function, the function will panic with a `TypeError`. (Either because
|
||||
the types cannot be unified or because they cannot be constructed due to
|
||||
limitations of the `reflect` package. See the `github.com/BurntSushi/ty`
|
||||
package for more details.)
|
||||
|
||||
Requirements
|
||||
|
||||
Go tip (or 1.1 when it's released) is required. This package will not work
|
||||
with Go 1.0.x or earlier.
|
||||
|
||||
The very foundation of this package only recently became possible with the
|
||||
addition of 3 new functions in the standard library `reflect` package:
|
||||
SliceOf, MapOf and ChanOf. In particular, it provides the ability to
|
||||
dynamically construct types at run time from component types.
|
||||
|
||||
Further extensions to this package can be made if similar functions are added
|
||||
for structs and functions(?).
|
||||
|
||||
Examples
|
||||
|
||||
Squaring each integer in a slice:
|
||||
|
||||
square := func(x int) int { return x * x }
|
||||
nums := []int{1, 2, 3, 4, 5}
|
||||
squares := Map(square, nums).([]int)
|
||||
|
||||
Reversing any slice:
|
||||
|
||||
slice := []string{"a", "b", "c"}
|
||||
reversed := Reverse(slice).([]string)
|
||||
|
||||
Sorting any slice:
|
||||
|
||||
// Sort a slice of structs with first class functions.
|
||||
type Album struct {
|
||||
Title string
|
||||
Year int
|
||||
}
|
||||
albums := []Album{
|
||||
{"Born to Run", 1975},
|
||||
{"WIESS", 1973},
|
||||
{"Darkness", 1978},
|
||||
{"Greetings", 1973},
|
||||
}
|
||||
|
||||
less := func(a, b Album) bool { return a.Year < b.Year },
|
||||
sorted := QuickSort(less, albums).([]Album)
|
||||
|
||||
Parallel map:
|
||||
|
||||
// Compute the prime factorization concurrently
|
||||
// for every integer in [1000, 10000].
|
||||
primeFactors := func(n int) []int { // compute prime factors }
|
||||
factors := ParMap(primeFactors, Range(1000, 10001)).([]int)
|
||||
|
||||
Asynchronous channel without a fixed size buffer:
|
||||
|
||||
s, r := AsyncChan(new(chan int))
|
||||
send, recv := s.(chan<- int), r.(<-chan int)
|
||||
|
||||
// Send as much as you want.
|
||||
for i := 0; i < 100; i++ {
|
||||
s <- i
|
||||
}
|
||||
close(s)
|
||||
for i := range recv {
|
||||
// do something with `i`
|
||||
}
|
||||
|
||||
Shuffle any slice in place:
|
||||
|
||||
jumbleMe := []string{"The", "quick", "brown", "fox"}
|
||||
Shuffle(jumbleMe)
|
||||
|
||||
Function memoization:
|
||||
|
||||
// Memoizing a recursive function like `fibonacci`.
|
||||
// Write it like normal:
|
||||
var fib func(n int64) int64
|
||||
fib = func(n int64) int64 {
|
||||
switch n {
|
||||
case 0:
|
||||
return 0
|
||||
case 1:
|
||||
return 1
|
||||
}
|
||||
return fib(n - 1) + fib(n - 2)
|
||||
}
|
||||
|
||||
// And wrap it with `Memo`.
|
||||
fib = Memo(fib).(func(int64) int64)
|
||||
|
||||
// Will keep your CPU busy for a long time
|
||||
// without memoization.
|
||||
fmt.Println(fib(80))
|
||||
|
||||
*/
|
||||
package fun
|
35
vendor/github.com/BurntSushi/ty/fun/func.go
generated
vendored
Normal file
35
vendor/github.com/BurntSushi/ty/fun/func.go
generated
vendored
Normal file
|
@ -0,0 +1,35 @@
|
|||
package fun
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/BurntSushi/ty"
|
||||
)
|
||||
|
||||
// Memo has a parametric type:
|
||||
//
|
||||
// func Memo(f func(A) B) func(A) B
|
||||
//
|
||||
// Memo memoizes any function of a single argument that returns a single value.
|
||||
// The type `A` must be a Go type for which the comparison operators `==` and
|
||||
// `!=` are fully defined (this rules out functions, maps and slices).
|
||||
func Memo(f interface{}) interface{} {
|
||||
chk := ty.Check(
|
||||
new(func(func(ty.A) ty.B)),
|
||||
f)
|
||||
vf := chk.Args[0]
|
||||
|
||||
saved := make(map[interface{}]reflect.Value)
|
||||
memo := func(in []reflect.Value) []reflect.Value {
|
||||
val := in[0].Interface()
|
||||
ret, ok := saved[val]
|
||||
if ok {
|
||||
return []reflect.Value{ret}
|
||||
}
|
||||
|
||||
ret = call1(vf, in[0])
|
||||
saved[val] = ret
|
||||
return []reflect.Value{ret}
|
||||
}
|
||||
return reflect.MakeFunc(vf.Type(), memo).Interface()
|
||||
}
|
303
vendor/github.com/BurntSushi/ty/fun/list.go
generated
vendored
Normal file
303
vendor/github.com/BurntSushi/ty/fun/list.go
generated
vendored
Normal file
|
@ -0,0 +1,303 @@
|
|||
package fun
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"runtime"
|
||||
"sync"
|
||||
|
||||
"github.com/BurntSushi/ty"
|
||||
)
|
||||
|
||||
// All has a parametric type:
|
||||
//
|
||||
// func All(p func(A) bool, xs []A) bool
|
||||
//
|
||||
// All returns `true` if and only if every element in `xs` satisfies `p`.
|
||||
func All(f, xs interface{}) bool {
|
||||
chk := ty.Check(
|
||||
new(func(func(ty.A) bool, []ty.A) bool),
|
||||
f, xs)
|
||||
vf, vxs := chk.Args[0], chk.Args[1]
|
||||
|
||||
xsLen := vxs.Len()
|
||||
for i := 0; i < xsLen; i++ {
|
||||
if !call1(vf, vxs.Index(i)).Interface().(bool) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Exists has a parametric type:
|
||||
//
|
||||
// func Exists(p func(A) bool, xs []A) bool
|
||||
//
|
||||
// Exists returns `true` if and only if an element in `xs` satisfies `p`.
|
||||
func Exists(f, xs interface{}) bool {
|
||||
chk := ty.Check(
|
||||
new(func(func(ty.A) bool, []ty.A) bool),
|
||||
f, xs)
|
||||
vf, vxs := chk.Args[0], chk.Args[1]
|
||||
|
||||
xsLen := vxs.Len()
|
||||
for i := 0; i < xsLen; i++ {
|
||||
if call1(vf, vxs.Index(i)).Interface().(bool) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// In has a parametric type:
|
||||
//
|
||||
// func In(needle A, haystack []A) bool
|
||||
//
|
||||
// In returns `true` if and only if `v` can be found in `xs`. The equality test
|
||||
// used is Go's standard `==` equality and NOT deep equality.
|
||||
//
|
||||
// Note that this requires that `A` be a type that can be meaningfully compared.
|
||||
func In(needle, haystack interface{}) bool {
|
||||
chk := ty.Check(
|
||||
new(func(ty.A, []ty.A) bool),
|
||||
needle, haystack)
|
||||
vhaystack := chk.Args[1]
|
||||
|
||||
length := vhaystack.Len()
|
||||
for i := 0; i < length; i++ {
|
||||
if vhaystack.Index(i).Interface() == needle {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Map has a parametric type:
|
||||
//
|
||||
// func Map(f func(A) B, xs []A) []B
|
||||
//
|
||||
// Map returns the list corresponding to the return value of applying
|
||||
// `f` to each element in `xs`.
|
||||
func Map(f, xs interface{}) interface{} {
|
||||
chk := ty.Check(
|
||||
new(func(func(ty.A) ty.B, []ty.A) []ty.B),
|
||||
f, xs)
|
||||
vf, vxs, tys := chk.Args[0], chk.Args[1], chk.Returns[0]
|
||||
|
||||
xsLen := vxs.Len()
|
||||
vys := reflect.MakeSlice(tys, xsLen, xsLen)
|
||||
for i := 0; i < xsLen; i++ {
|
||||
vy := call1(vf, vxs.Index(i))
|
||||
vys.Index(i).Set(vy)
|
||||
}
|
||||
return vys.Interface()
|
||||
}
|
||||
|
||||
// Filter has a parametric type:
|
||||
//
|
||||
// func Filter(p func(A) bool, xs []A) []A
|
||||
//
|
||||
// Filter returns a new list only containing the elements of `xs` that satisfy
|
||||
// the predicate `p`.
|
||||
func Filter(p, xs interface{}) interface{} {
|
||||
chk := ty.Check(
|
||||
new(func(func(ty.A) bool, []ty.A) []ty.A),
|
||||
p, xs)
|
||||
vp, vxs, tys := chk.Args[0], chk.Args[1], chk.Returns[0]
|
||||
|
||||
xsLen := vxs.Len()
|
||||
vys := reflect.MakeSlice(tys, 0, xsLen)
|
||||
for i := 0; i < xsLen; i++ {
|
||||
vx := vxs.Index(i)
|
||||
if call1(vp, vx).Bool() {
|
||||
vys = reflect.Append(vys, vx)
|
||||
}
|
||||
}
|
||||
return vys.Interface()
|
||||
}
|
||||
|
||||
// Foldl has a parametric type:
|
||||
//
|
||||
// func Foldl(f func(A, B) B, init B, xs []A) B
|
||||
//
|
||||
// Foldl reduces a list of A to a single element B using a left fold with
|
||||
// an initial value `init`.
|
||||
func Foldl(f, init, xs interface{}) interface{} {
|
||||
chk := ty.Check(
|
||||
new(func(func(ty.A, ty.B) ty.B, ty.B, []ty.A) ty.B),
|
||||
f, init, xs)
|
||||
vf, vinit, vxs, tb := chk.Args[0], chk.Args[1], chk.Args[2], chk.Returns[0]
|
||||
|
||||
xsLen := vxs.Len()
|
||||
vb := zeroValue(tb)
|
||||
vb.Set(vinit)
|
||||
if xsLen == 0 {
|
||||
return vb.Interface()
|
||||
}
|
||||
|
||||
vb.Set(call1(vf, vxs.Index(0), vb))
|
||||
for i := 1; i < xsLen; i++ {
|
||||
vb.Set(call1(vf, vxs.Index(i), vb))
|
||||
}
|
||||
return vb.Interface()
|
||||
}
|
||||
|
||||
// Foldr has a parametric type:
|
||||
//
|
||||
// func Foldr(f func(A, B) B, init B, xs []A) B
|
||||
//
|
||||
// Foldr reduces a list of A to a single element B using a right fold with
|
||||
// an initial value `init`.
|
||||
func Foldr(f, init, xs interface{}) interface{} {
|
||||
chk := ty.Check(
|
||||
new(func(func(ty.A, ty.B) ty.B, ty.B, []ty.A) ty.B),
|
||||
f, init, xs)
|
||||
vf, vinit, vxs, tb := chk.Args[0], chk.Args[1], chk.Args[2], chk.Returns[0]
|
||||
|
||||
xsLen := vxs.Len()
|
||||
vb := zeroValue(tb)
|
||||
vb.Set(vinit)
|
||||
if xsLen == 0 {
|
||||
return vb.Interface()
|
||||
}
|
||||
|
||||
vb.Set(call1(vf, vxs.Index(xsLen-1), vb))
|
||||
for i := xsLen - 2; i >= 0; i-- {
|
||||
vb.Set(call1(vf, vxs.Index(i), vb))
|
||||
}
|
||||
return vb.Interface()
|
||||
}
|
||||
|
||||
// Concat has a parametric type:
|
||||
//
|
||||
// func Concat(xs [][]A) []A
|
||||
//
|
||||
// Concat returns a new flattened list by appending all elements of `xs`.
|
||||
func Concat(xs interface{}) interface{} {
|
||||
chk := ty.Check(
|
||||
new(func([][]ty.A) []ty.A),
|
||||
xs)
|
||||
vxs, tflat := chk.Args[0], chk.Returns[0]
|
||||
|
||||
xsLen := vxs.Len()
|
||||
vflat := reflect.MakeSlice(tflat, 0, xsLen*3)
|
||||
for i := 0; i < xsLen; i++ {
|
||||
vflat = reflect.AppendSlice(vflat, vxs.Index(i))
|
||||
}
|
||||
return vflat.Interface()
|
||||
}
|
||||
|
||||
// Reverse has a parametric type:
|
||||
//
|
||||
// func Reverse(xs []A) []A
|
||||
//
|
||||
// Reverse returns a new slice that is the reverse of `xs`.
|
||||
func Reverse(xs interface{}) interface{} {
|
||||
chk := ty.Check(
|
||||
new(func([]ty.A) []ty.A),
|
||||
xs)
|
||||
vxs, tys := chk.Args[0], chk.Returns[0]
|
||||
|
||||
xsLen := vxs.Len()
|
||||
vys := reflect.MakeSlice(tys, xsLen, xsLen)
|
||||
for i := 0; i < xsLen; i++ {
|
||||
vys.Index(i).Set(vxs.Index(xsLen - 1 - i))
|
||||
}
|
||||
return vys.Interface()
|
||||
}
|
||||
|
||||
// Copy has a parametric type:
|
||||
//
|
||||
// func Copy(xs []A) []A
|
||||
//
|
||||
// Copy returns a copy of `xs` using Go's `copy` operation.
|
||||
func Copy(xs interface{}) interface{} {
|
||||
chk := ty.Check(
|
||||
new(func([]ty.A) []ty.A),
|
||||
xs)
|
||||
vxs, tys := chk.Args[0], chk.Returns[0]
|
||||
|
||||
xsLen := vxs.Len()
|
||||
vys := reflect.MakeSlice(tys, xsLen, xsLen)
|
||||
reflect.Copy(vys, vxs)
|
||||
return vys.Interface()
|
||||
}
|
||||
|
||||
// ParMap has a parametric type:
|
||||
//
|
||||
// func ParMap(f func(A) B, xs []A) []B
|
||||
//
|
||||
// ParMap is just like Map, except it applies `f` to each element in `xs`
|
||||
// concurrently using N worker goroutines (where N is the number of CPUs
|
||||
// available reported by the Go runtime). If you want to control the number
|
||||
// of goroutines spawned, use `ParMapN`.
|
||||
//
|
||||
// It is important that `f` not be a trivial operation, otherwise the overhead
|
||||
// of executing it concurrently will result in worse performance than using
|
||||
// a `Map`.
|
||||
func ParMap(f, xs interface{}) interface{} {
|
||||
n := runtime.NumCPU()
|
||||
if n < 1 {
|
||||
n = 1
|
||||
}
|
||||
return ParMapN(f, xs, n)
|
||||
}
|
||||
|
||||
// ParMapN has a parametric type:
|
||||
//
|
||||
// func ParMapN(f func(A) B, xs []A, n int) []B
|
||||
//
|
||||
// ParMapN is just like Map, except it applies `f` to each element in `xs`
|
||||
// concurrently using `n` worker goroutines.
|
||||
//
|
||||
// It is important that `f` not be a trivial operation, otherwise the overhead
|
||||
// of executing it concurrently will result in worse performance than using
|
||||
// a `Map`.
|
||||
func ParMapN(f, xs interface{}, n int) interface{} {
|
||||
chk := ty.Check(
|
||||
new(func(func(ty.A) ty.B, []ty.A) []ty.B),
|
||||
f, xs)
|
||||
vf, vxs, tys := chk.Args[0], chk.Args[1], chk.Returns[0]
|
||||
|
||||
xsLen := vxs.Len()
|
||||
ys := reflect.MakeSlice(tys, xsLen, xsLen)
|
||||
|
||||
if n < 1 {
|
||||
n = 1
|
||||
}
|
||||
work := make(chan int, n)
|
||||
wg := new(sync.WaitGroup)
|
||||
for i := 0; i < n; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
for j := range work {
|
||||
// Good golly miss molly. Is `reflect.Value.Index`
|
||||
// safe to access/set from multiple goroutines?
|
||||
// XXX: If not, we'll need an extra wave of allocation to
|
||||
// use real slices of `reflect.Value`.
|
||||
ys.Index(j).Set(call1(vf, vxs.Index(j)))
|
||||
}
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
for i := 0; i < xsLen; i++ {
|
||||
work <- i
|
||||
}
|
||||
close(work)
|
||||
wg.Wait()
|
||||
return ys.Interface()
|
||||
}
|
||||
|
||||
// Range generates a list of integers corresponding to every integer in
|
||||
// the half-open interval [x, y).
|
||||
//
|
||||
// Range will panic if `end < start`.
|
||||
func Range(start, end int) []int {
|
||||
if end < start {
|
||||
panic("range must have end greater than or equal to start")
|
||||
}
|
||||
r := make([]int, end-start)
|
||||
for i := start; i < end; i++ {
|
||||
r[i-start] = i
|
||||
}
|
||||
return r
|
||||
}
|
46
vendor/github.com/BurntSushi/ty/fun/map.go
generated
vendored
Normal file
46
vendor/github.com/BurntSushi/ty/fun/map.go
generated
vendored
Normal file
|
@ -0,0 +1,46 @@
|
|||
package fun
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/BurntSushi/ty"
|
||||
)
|
||||
|
||||
// Keys has a parametric type:
|
||||
//
|
||||
// func Keys(m map[A]B) []A
|
||||
//
|
||||
// Keys returns a list of the keys of `m` in an unspecified order.
|
||||
func Keys(m interface{}) interface{} {
|
||||
chk := ty.Check(
|
||||
new(func(map[ty.A]ty.B) []ty.A),
|
||||
m)
|
||||
vm, tkeys := chk.Args[0], chk.Returns[0]
|
||||
|
||||
vkeys := reflect.MakeSlice(tkeys, vm.Len(), vm.Len())
|
||||
for i, vkey := range vm.MapKeys() {
|
||||
vkeys.Index(i).Set(vkey)
|
||||
}
|
||||
return vkeys.Interface()
|
||||
}
|
||||
|
||||
// Values has a parametric type:
|
||||
//
|
||||
// func Values(m map[A]B) []B
|
||||
//
|
||||
// Values returns a list of the values of `m` in an unspecified order.
|
||||
func Values(m interface{}) interface{} {
|
||||
chk := ty.Check(
|
||||
new(func(map[ty.A]ty.B) []ty.B),
|
||||
m)
|
||||
vm, tvals := chk.Args[0], chk.Returns[0]
|
||||
|
||||
vvals := reflect.MakeSlice(tvals, vm.Len(), vm.Len())
|
||||
for i, vkey := range vm.MapKeys() {
|
||||
vvals.Index(i).Set(vm.MapIndex(vkey))
|
||||
}
|
||||
return vvals.Interface()
|
||||
}
|
||||
|
||||
// func MapMerge(m1, m2 interface{}) interface{} {
|
||||
// }
|
94
vendor/github.com/BurntSushi/ty/fun/rand.go
generated
vendored
Normal file
94
vendor/github.com/BurntSushi/ty/fun/rand.go
generated
vendored
Normal file
|
@ -0,0 +1,94 @@
|
|||
package fun
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/BurntSushi/ty"
|
||||
)
|
||||
|
||||
var randNumGen *rand.Rand
|
||||
|
||||
func init() {
|
||||
randNumGen = rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
}
|
||||
|
||||
// ShuffleGen has a parametric type:
|
||||
//
|
||||
// func ShuffleGen(xs []A, rng *rand.Rand)
|
||||
//
|
||||
// ShuffleGen shuffles `xs` in place using the given random number
|
||||
// generator `rng`.
|
||||
func ShuffleGen(xs interface{}, rng *rand.Rand) {
|
||||
chk := ty.Check(
|
||||
new(func([]ty.A, *rand.Rand)),
|
||||
xs, rng)
|
||||
vxs := chk.Args[0]
|
||||
|
||||
// Implements the Fisher-Yates shuffle: http://goo.gl/Hb9vg
|
||||
xsLen := vxs.Len()
|
||||
swapper := swapperOf(vxs.Type().Elem())
|
||||
for i := xsLen - 1; i >= 1; i-- {
|
||||
j := rng.Intn(i + 1)
|
||||
swapper.swap(vxs.Index(i), vxs.Index(j))
|
||||
}
|
||||
}
|
||||
|
||||
// Shuffle has a parametric type:
|
||||
//
|
||||
// func Shuffle(xs []A)
|
||||
//
|
||||
// Shuffle shuffles `xs` in place using a default random number
|
||||
// generator seeded once at program initialization.
|
||||
func Shuffle(xs interface{}) {
|
||||
ShuffleGen(xs, randNumGen)
|
||||
}
|
||||
|
||||
// Sample has a parametric type:
|
||||
//
|
||||
// func Sample(population []A, n int) []A
|
||||
//
|
||||
// Sample returns a random sample of size `n` from a list
|
||||
// `population` using a default random number generator seeded once at
|
||||
// program initialization.
|
||||
// All elements in `population` have an equal chance of being selected.
|
||||
// If `n` is greater than the size of `population`, then `n` is set to
|
||||
// the size of the population.
|
||||
func Sample(population interface{}, n int) interface{} {
|
||||
return SampleGen(population, n, randNumGen)
|
||||
}
|
||||
|
||||
// SampleGen has a parametric type:
|
||||
//
|
||||
// func SampleGen(population []A, n int, rng *rand.Rand) []A
|
||||
//
|
||||
// SampleGen returns a random sample of size `n` from a list
|
||||
// `population` using a given random number generator `rng`.
|
||||
// All elements in `population` have an equal chance of being selected.
|
||||
// If `n` is greater than the size of `population`, then `n` is set to
|
||||
// the size of the population.
|
||||
func SampleGen(population interface{}, n int, rng *rand.Rand) interface{} {
|
||||
chk := ty.Check(
|
||||
new(func([]ty.A, int, *rand.Rand) []ty.A),
|
||||
population, n, rng)
|
||||
rpop, tsamp := chk.Args[0], chk.Returns[0]
|
||||
|
||||
popLen := rpop.Len()
|
||||
if n == 0 {
|
||||
return reflect.MakeSlice(tsamp, 0, 0).Interface()
|
||||
}
|
||||
if n > popLen {
|
||||
n = popLen
|
||||
}
|
||||
|
||||
// TODO(burntsushi): Implement an algorithm that doesn't depend on
|
||||
// the size of the population.
|
||||
|
||||
rsamp := reflect.MakeSlice(tsamp, n, n)
|
||||
choices := rng.Perm(popLen)
|
||||
for i := 0; i < n; i++ {
|
||||
rsamp.Index(i).Set(rpop.Index(choices[i]))
|
||||
}
|
||||
return rsamp.Interface()
|
||||
}
|
99
vendor/github.com/BurntSushi/ty/fun/set.go
generated
vendored
Normal file
99
vendor/github.com/BurntSushi/ty/fun/set.go
generated
vendored
Normal file
|
@ -0,0 +1,99 @@
|
|||
package fun
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/BurntSushi/ty"
|
||||
)
|
||||
|
||||
// Set has a parametric type:
|
||||
//
|
||||
// func Set(xs []A) map[A]bool
|
||||
//
|
||||
// Set creates a set from a list.
|
||||
func Set(xs interface{}) interface{} {
|
||||
chk := ty.Check(
|
||||
new(func([]ty.A) map[ty.A]bool),
|
||||
xs)
|
||||
vxs, tset := chk.Args[0], chk.Returns[0]
|
||||
|
||||
vtrue := reflect.ValueOf(true)
|
||||
vset := reflect.MakeMap(tset)
|
||||
xsLen := vxs.Len()
|
||||
for i := 0; i < xsLen; i++ {
|
||||
vset.SetMapIndex(vxs.Index(i), vtrue)
|
||||
}
|
||||
return vset.Interface()
|
||||
}
|
||||
|
||||
// Union has a parametric type:
|
||||
//
|
||||
// func Union(a map[A]bool, b map[A]bool) map[A]bool
|
||||
//
|
||||
// Union returns the union of two sets, where a set is represented as a
|
||||
// `map[A]bool`. The sets `a` and `b` are not modified.
|
||||
func Union(a, b interface{}) interface{} {
|
||||
chk := ty.Check(
|
||||
new(func(map[ty.A]bool, map[ty.A]bool) map[ty.A]bool),
|
||||
a, b)
|
||||
va, vb, tc := chk.Args[0], chk.Args[1], chk.Returns[0]
|
||||
|
||||
vtrue := reflect.ValueOf(true)
|
||||
vc := reflect.MakeMap(tc)
|
||||
for _, vkey := range va.MapKeys() {
|
||||
vc.SetMapIndex(vkey, vtrue)
|
||||
}
|
||||
for _, vkey := range vb.MapKeys() {
|
||||
vc.SetMapIndex(vkey, vtrue)
|
||||
}
|
||||
return vc.Interface()
|
||||
}
|
||||
|
||||
// Intersection has a parametric type:
|
||||
//
|
||||
// func Intersection(a map[A]bool, b map[A]bool) map[A]bool
|
||||
//
|
||||
// Intersection returns the intersection of two sets, where a set is
|
||||
// represented as a `map[A]bool`. The sets `a` and `b` are not modified.
|
||||
func Intersection(a, b interface{}) interface{} {
|
||||
chk := ty.Check(
|
||||
new(func(map[ty.A]bool, map[ty.A]bool) map[ty.A]bool),
|
||||
a, b)
|
||||
va, vb, tc := chk.Args[0], chk.Args[1], chk.Returns[0]
|
||||
|
||||
vtrue := reflect.ValueOf(true)
|
||||
vc := reflect.MakeMap(tc)
|
||||
for _, vkey := range va.MapKeys() {
|
||||
if vb.MapIndex(vkey).IsValid() {
|
||||
vc.SetMapIndex(vkey, vtrue)
|
||||
}
|
||||
}
|
||||
for _, vkey := range vb.MapKeys() {
|
||||
if va.MapIndex(vkey).IsValid() {
|
||||
vc.SetMapIndex(vkey, vtrue)
|
||||
}
|
||||
}
|
||||
return vc.Interface()
|
||||
}
|
||||
|
||||
// Difference has a parametric type:
|
||||
//
|
||||
// func Difference(a map[A]bool, b map[A]bool) map[A]bool
|
||||
//
|
||||
// Difference returns a set with all elements in `a` that are not in `b`.
|
||||
// The sets `a` and `b` are not modified.
|
||||
func Difference(a, b interface{}) interface{} {
|
||||
chk := ty.Check(
|
||||
new(func(map[ty.A]bool, map[ty.A]bool) map[ty.A]bool),
|
||||
a, b)
|
||||
va, vb, tc := chk.Args[0], chk.Args[1], chk.Returns[0]
|
||||
|
||||
vtrue := reflect.ValueOf(true)
|
||||
vc := reflect.MakeMap(tc)
|
||||
for _, vkey := range va.MapKeys() {
|
||||
if !vb.MapIndex(vkey).IsValid() {
|
||||
vc.SetMapIndex(vkey, vtrue)
|
||||
}
|
||||
}
|
||||
return vc.Interface()
|
||||
}
|
98
vendor/github.com/BurntSushi/ty/fun/sort.go
generated
vendored
Normal file
98
vendor/github.com/BurntSushi/ty/fun/sort.go
generated
vendored
Normal file
|
@ -0,0 +1,98 @@
|
|||
package fun
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"sort"
|
||||
|
||||
"github.com/BurntSushi/ty"
|
||||
)
|
||||
|
||||
// QuickSort has a parametric type:
|
||||
//
|
||||
// func QuickSort(less func(x1 A, x2 A) bool, []A) []A
|
||||
//
|
||||
// QuickSort applies the "quicksort" algorithm to return a new sorted list
|
||||
// of `xs`, where `xs` is not modified.
|
||||
//
|
||||
// `less` should be a function that returns true if and only if `x1` is less
|
||||
// than `x2`.
|
||||
func QuickSort(less, xs interface{}) interface{} {
|
||||
chk := ty.Check(
|
||||
new(func(func(ty.A, ty.A) bool, []ty.A) []ty.A),
|
||||
less, xs)
|
||||
vless, vxs, tys := chk.Args[0], chk.Args[1], chk.Returns[0]
|
||||
|
||||
var qsort func(left, right int)
|
||||
var partition func(left, right, pivot int) int
|
||||
xsind := Range(0, vxs.Len())
|
||||
|
||||
qsort = func(left, right int) {
|
||||
if left >= right {
|
||||
return
|
||||
}
|
||||
pivot := (left + right) / 2
|
||||
pivot = partition(left, right, pivot)
|
||||
|
||||
qsort(left, pivot-1)
|
||||
qsort(pivot+1, right)
|
||||
}
|
||||
partition = func(left, right, pivot int) int {
|
||||
vpivot := xsind[pivot]
|
||||
xsind[pivot], xsind[right] = xsind[right], xsind[pivot]
|
||||
|
||||
ind := left
|
||||
for i := left; i < right; i++ {
|
||||
if call1(vless, vxs.Index(xsind[i]), vxs.Index(vpivot)).Bool() {
|
||||
xsind[i], xsind[ind] = xsind[ind], xsind[i]
|
||||
ind++
|
||||
}
|
||||
}
|
||||
xsind[ind], xsind[right] = xsind[right], xsind[ind]
|
||||
return ind
|
||||
}
|
||||
|
||||
// Sort `xsind` in place.
|
||||
qsort(0, len(xsind)-1)
|
||||
|
||||
vys := reflect.MakeSlice(tys, len(xsind), len(xsind))
|
||||
for i, xsIndex := range xsind {
|
||||
vys.Index(i).Set(vxs.Index(xsIndex))
|
||||
}
|
||||
return vys.Interface()
|
||||
}
|
||||
|
||||
// Sort has a parametric type:
|
||||
//
|
||||
// func Sort(less func(x1 A, x2 A) bool, []A)
|
||||
//
|
||||
// Sort uses the standard library `sort` package to sort `xs` in place.
|
||||
//
|
||||
// `less` should be a function that returns true if and only if `x1` is less
|
||||
// than `x2`.
|
||||
func Sort(less, xs interface{}) {
|
||||
chk := ty.Check(
|
||||
new(func(func(ty.A, ty.A) bool, []ty.A)),
|
||||
less, xs)
|
||||
|
||||
vless, vxs := chk.Args[0], chk.Args[1]
|
||||
sort.Sort(&sortable{vless, vxs, swapperOf(vxs.Type().Elem())})
|
||||
}
|
||||
|
||||
type sortable struct {
|
||||
less reflect.Value
|
||||
xs reflect.Value
|
||||
swapper swapper
|
||||
}
|
||||
|
||||
func (s *sortable) Less(i, j int) bool {
|
||||
ith, jth := s.xs.Index(i), s.xs.Index(j)
|
||||
return call1(s.less, ith, jth).Bool()
|
||||
}
|
||||
|
||||
func (s *sortable) Swap(i, j int) {
|
||||
s.swapper.swap(s.xs.Index(i), s.xs.Index(j))
|
||||
}
|
||||
|
||||
func (s *sortable) Len() int {
|
||||
return s.xs.Len()
|
||||
}
|
37
vendor/github.com/BurntSushi/ty/fun/util.go
generated
vendored
Normal file
37
vendor/github.com/BurntSushi/ty/fun/util.go
generated
vendored
Normal file
|
@ -0,0 +1,37 @@
|
|||
package fun
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func zeroValue(typ reflect.Type) reflect.Value {
|
||||
return reflect.New(typ).Elem()
|
||||
}
|
||||
|
||||
type swapper reflect.Value
|
||||
|
||||
func swapperOf(typ reflect.Type) swapper {
|
||||
return swapper(zeroValue(typ))
|
||||
}
|
||||
|
||||
func (s swapper) swap(a, b reflect.Value) {
|
||||
vs := reflect.Value(s)
|
||||
vs.Set(a)
|
||||
a.Set(b)
|
||||
b.Set(vs)
|
||||
}
|
||||
|
||||
func call(f reflect.Value, args ...reflect.Value) {
|
||||
f.Call(args)
|
||||
}
|
||||
|
||||
func call1(f reflect.Value, args ...reflect.Value) reflect.Value {
|
||||
return f.Call(args)[0]
|
||||
}
|
||||
|
||||
func call2(f reflect.Value, args ...reflect.Value) (
|
||||
reflect.Value, reflect.Value) {
|
||||
|
||||
ret := f.Call(args)
|
||||
return ret[0], ret[1]
|
||||
}
|
338
vendor/github.com/BurntSushi/ty/type-check.go
generated
vendored
Normal file
338
vendor/github.com/BurntSushi/ty/type-check.go
generated
vendored
Normal file
|
@ -0,0 +1,338 @@
|
|||
package ty
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// TypeError corresponds to any error reported by the `Check` function.
|
||||
// Since `Check` panics, if you want to run `Check` safely, it is
|
||||
// appropriate to recover and use a type switch to discover a `TypeError`
|
||||
// value.
|
||||
type TypeError string
|
||||
|
||||
func (te TypeError) Error() string {
|
||||
return string(te)
|
||||
}
|
||||
|
||||
func pe(format string, v ...interface{}) TypeError {
|
||||
return TypeError(fmt.Sprintf(format, v...))
|
||||
}
|
||||
|
||||
func ppe(format string, v ...interface{}) {
|
||||
panic(pe(format, v...))
|
||||
}
|
||||
|
||||
// Typed corresponds to the information returned by `Check`.
|
||||
type Typed struct {
|
||||
// In correspondence with the `as` parameter to `Check`.
|
||||
Args []reflect.Value
|
||||
|
||||
// In correspondence with the return types of `f` in `Check`.
|
||||
Returns []reflect.Type
|
||||
|
||||
// The type environment generated via unification in `Check`.
|
||||
// (Its usefulness in the public API is questionable.)
|
||||
TypeEnv map[string]reflect.Type
|
||||
}
|
||||
|
||||
// Check accepts a function `f`, which may have a parametric type, along with a
|
||||
// number of arguments in correspondence with the arguments to `f`,
|
||||
// and returns inferred Go type information. This type information includes
|
||||
// a list of `reflect.Value` in correspondence with `as`, a list of
|
||||
// `reflect.Type` in correspondence with the return types of `f` and a type
|
||||
// environment mapping type variables to `reflect.Type`.
|
||||
//
|
||||
// The power of `Check` comes from the following invariant: if `Check` returns,
|
||||
// then the types of the arguments corresponding to `as` are consistent
|
||||
// with the parametric type of `f`, *and* the parametric return types of `f`
|
||||
// were made into valid Go types that are not parametric. Otherwise, there is
|
||||
// a bug in `Check`.
|
||||
//
|
||||
// More concretely, consider a simple parametric function `Map`, which
|
||||
// transforms a list of elements by applying a function to each element in
|
||||
// order to generate a new list. Such a function constructed only for integers
|
||||
// might have a type like
|
||||
//
|
||||
// func Map(func(int) int, []int) []int
|
||||
//
|
||||
// But the parametric type of `Map` could be given with
|
||||
//
|
||||
// func Map(func(A) B, []A) []B
|
||||
//
|
||||
// which in English reads, "Given a function from any type `A` to any type `B`
|
||||
// and a slice of `A`, `Map` returns a slice of `B`."
|
||||
//
|
||||
// To write a parametric function like `Map`, one can pass a pointer
|
||||
// to a nil function of the desired parametric type to get the reflection
|
||||
// information:
|
||||
//
|
||||
// func Map(f, xs interface{}) interface{} {
|
||||
// // Given the parametric type and the arguments, Check will
|
||||
// // return all the reflection information you need to write `Map`.
|
||||
// uni := ty.Check(
|
||||
// new(func(func(ty.A) ty.B, []ty.A) []ty.B),
|
||||
// f, xs)
|
||||
//
|
||||
// // `vf` and `vxs` are `reflect.Value`s of `f` and `xs`.
|
||||
// vf, vxs := uni.Args[0], uni.Args[1]
|
||||
//
|
||||
// // `tys` is a `reflect.Type` of `[]ty.B` where `ty.B` is replaced
|
||||
// // with the return type of the given function `f`.
|
||||
// tys := uni.Returns[0]
|
||||
//
|
||||
// // Given the promise of `Check`, we now know that `vf` has
|
||||
// // type `func(ty.A) ty.B` and `vxs` has type `[]ty.A`.
|
||||
// xsLen := vxs.Len()
|
||||
//
|
||||
// // Constructs a new slice which will have type `[]ty.B`.
|
||||
// vys := reflect.MakeSlice(tys, xsLen, xsLen)
|
||||
//
|
||||
// // Actually perform the `Map` operation, but in the world of
|
||||
// // reflection.
|
||||
// for i := 0; i < xsLen; i++ {
|
||||
// vy := vf.Call([]reflect.Value{vxs.Index(i)})[0]
|
||||
// vys.Index(i).Set(vy)
|
||||
// }
|
||||
//
|
||||
// // The `reflect.Value.Interface` method is how we exit the world of
|
||||
// // reflection. The onus is now on the caller to type assert it to
|
||||
// // the appropriate type.
|
||||
// return vys.Interface()
|
||||
// }
|
||||
//
|
||||
// Working in the reflection world is certainly more inconvenient than writing
|
||||
// regular Go code, but the information and invariants held by `Check` provide
|
||||
// a more convenient experience than how one normally works with reflection.
|
||||
// (Notice that there is no error-prone type switching or boiler plate to
|
||||
// construct new types, since `Check` guarantees the types are consistent
|
||||
// with the inputs for us.)
|
||||
//
|
||||
// And while writing such functions is still not so convenient,
|
||||
// invoking them is simple:
|
||||
//
|
||||
// square := func(x int) int { return x * x }
|
||||
// squared := Map(square, []int{1, 2, 3, 4, 5}).([]int)
|
||||
//
|
||||
// Restrictions
|
||||
//
|
||||
// There are a few restrictions imposed on the parametric return types of
|
||||
// `f`: type variables may only be found in types that can be composed by the
|
||||
// `reflect` package. This *only* includes channels, maps, pointers and slices.
|
||||
// If a type variable is found in an array, function or struct, `Check` will
|
||||
// panic.
|
||||
//
|
||||
// Also, type variables inside of structs are ignored in the types of the
|
||||
// arguments `as`. This restriction may be lifted in the future.
|
||||
//
|
||||
// To be clear: type variables *may* appear in arrays or functions in the types
|
||||
// of the arguments `as`.
|
||||
func Check(f interface{}, as ...interface{}) *Typed {
|
||||
rf := reflect.ValueOf(f)
|
||||
tf := rf.Type()
|
||||
|
||||
if tf.Kind() == reflect.Ptr {
|
||||
rf = reflect.Indirect(rf)
|
||||
tf = rf.Type()
|
||||
}
|
||||
if tf.Kind() != reflect.Func {
|
||||
ppe("The type of `f` must be a function, but it is a '%s'.", tf.Kind())
|
||||
}
|
||||
if tf.NumIn() != len(as) {
|
||||
ppe("`f` expects %d arguments, but only %d were given.",
|
||||
tf.NumIn(), len(as))
|
||||
}
|
||||
|
||||
// Populate the argument value list.
|
||||
args := make([]reflect.Value, len(as))
|
||||
for i := 0; i < len(as); i++ {
|
||||
args[i] = reflect.ValueOf(as[i])
|
||||
}
|
||||
|
||||
// Populate our type variable environment through unification.
|
||||
tyenv := make(tyenv)
|
||||
for i := 0; i < len(args); i++ {
|
||||
tp := typePair{tyenv, tf.In(i), args[i].Type()}
|
||||
|
||||
// Mutates the type variable environment.
|
||||
if err := tp.unify(tp.param, tp.input); err != nil {
|
||||
argTypes := make([]string, len(args))
|
||||
for i := range args {
|
||||
argTypes[i] = args[i].Type().String()
|
||||
}
|
||||
ppe("\nError type checking\n\t%s\nwith argument types\n\t(%s)\n%s",
|
||||
tf, strings.Join(argTypes, ", "), err)
|
||||
}
|
||||
}
|
||||
|
||||
// Now substitute those types into the return types of `f`.
|
||||
retTypes := make([]reflect.Type, tf.NumOut())
|
||||
for i := 0; i < tf.NumOut(); i++ {
|
||||
retTypes[i] = (&returnType{tyenv, tf.Out(i)}).tysubst(tf.Out(i))
|
||||
}
|
||||
return &Typed{args, retTypes, map[string]reflect.Type(tyenv)}
|
||||
}
|
||||
|
||||
// tyenv maps type variable names to their inferred Go type.
|
||||
type tyenv map[string]reflect.Type
|
||||
|
||||
// typePair represents a pair of types to be unified. They act as a way to
|
||||
// report sensible error messages from within the unification algorithm.
|
||||
//
|
||||
// It also includes a type environment, which is mutated during unification.
|
||||
type typePair struct {
|
||||
tyenv tyenv
|
||||
param reflect.Type
|
||||
input reflect.Type
|
||||
}
|
||||
|
||||
func (tp typePair) error(format string, v ...interface{}) error {
|
||||
return pe("Type error when unifying type '%s' and '%s': %s",
|
||||
tp.param, tp.input, fmt.Sprintf(format, v...))
|
||||
}
|
||||
|
||||
// unify attempts to satisfy a pair of types, where the `param` type is the
|
||||
// expected type of a function argument and the `input` type is the known
|
||||
// type of a function argument. The `param` type may be parametric (that is,
|
||||
// it may contain a type that is convertible to TypeVariable) but the
|
||||
// `input` type may *not* be parametric.
|
||||
//
|
||||
// Any failure to unify the two types results in a panic.
|
||||
//
|
||||
// The end result of unification is a type environment: a set of substitutions
|
||||
// from type variable to a Go type.
|
||||
func (tp typePair) unify(param, input reflect.Type) error {
|
||||
if tyname := tyvarName(input); len(tyname) > 0 {
|
||||
return tp.error("Type variables are not allowed in the types of " +
|
||||
"arguments.")
|
||||
}
|
||||
if tyname := tyvarName(param); len(tyname) > 0 {
|
||||
if cur, ok := tp.tyenv[tyname]; ok && cur != input {
|
||||
return tp.error("Type variable %s expected type '%s' but got '%s'.",
|
||||
tyname, cur, input)
|
||||
} else if !ok {
|
||||
tp.tyenv[tyname] = input
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if param.Kind() != input.Kind() {
|
||||
return tp.error("Cannot unify different kinds of types '%s' and '%s'.",
|
||||
param, input)
|
||||
}
|
||||
|
||||
switch param.Kind() {
|
||||
case reflect.Array:
|
||||
return tp.unify(param.Elem(), input.Elem())
|
||||
case reflect.Chan:
|
||||
if param.ChanDir() != input.ChanDir() {
|
||||
return tp.error("Cannot unify '%s' with '%s' "+
|
||||
"(channel directions are different: '%s' != '%s').",
|
||||
param, input, param.ChanDir(), input.ChanDir())
|
||||
}
|
||||
return tp.unify(param.Elem(), input.Elem())
|
||||
case reflect.Func:
|
||||
if param.NumIn() != input.NumIn() || param.NumOut() != input.NumOut() {
|
||||
return tp.error("Cannot unify '%s' with '%s'.", param, input)
|
||||
}
|
||||
for i := 0; i < param.NumIn(); i++ {
|
||||
if err := tp.unify(param.In(i), input.In(i)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
for i := 0; i < param.NumOut(); i++ {
|
||||
if err := tp.unify(param.Out(i), input.Out(i)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
case reflect.Map:
|
||||
if err := tp.unify(param.Key(), input.Key()); err != nil {
|
||||
return err
|
||||
}
|
||||
return tp.unify(param.Elem(), input.Elem())
|
||||
case reflect.Ptr:
|
||||
return tp.unify(param.Elem(), input.Elem())
|
||||
case reflect.Slice:
|
||||
return tp.unify(param.Elem(), input.Elem())
|
||||
}
|
||||
|
||||
// The only other container types are Interface and Struct.
|
||||
// I am unsure about what to do with interfaces. Mind is fuzzy.
|
||||
// Structs? I don't think it really makes much sense to use type
|
||||
// variables inside of them.
|
||||
return nil
|
||||
}
|
||||
|
||||
// returnType corresponds to the type of a single return value of a function,
|
||||
// in which the type may be parametric. It also contains a type environment
|
||||
// constructed from unification.
|
||||
type returnType struct {
|
||||
tyenv tyenv
|
||||
typ reflect.Type
|
||||
}
|
||||
|
||||
func (rt returnType) panic(format string, v ...interface{}) {
|
||||
ppe("Error substituting in return type '%s': %s",
|
||||
rt.typ, fmt.Sprintf(format, v...))
|
||||
}
|
||||
|
||||
// tysubst attempts to substitute all type variables within a single return
|
||||
// type with their corresponding Go type from the type environment.
|
||||
//
|
||||
// tysubst will panic if a type variable is unbound, or if it encounters a
|
||||
// type that cannot be dynamically created. Such types include arrays,
|
||||
// functions and structs. (A limitation of the `reflect` package.)
|
||||
func (rt returnType) tysubst(typ reflect.Type) reflect.Type {
|
||||
if tyname := tyvarName(typ); len(tyname) > 0 {
|
||||
if thetype, ok := rt.tyenv[tyname]; !ok {
|
||||
rt.panic("Unbound type variable %s.", tyname)
|
||||
} else {
|
||||
return thetype
|
||||
}
|
||||
}
|
||||
|
||||
switch typ.Kind() {
|
||||
case reflect.Array:
|
||||
rt.panic("Cannot dynamically create Array types.")
|
||||
case reflect.Chan:
|
||||
return reflect.ChanOf(typ.ChanDir(), rt.tysubst(typ.Elem()))
|
||||
case reflect.Func:
|
||||
rt.panic("Cannot dynamically create Function types.")
|
||||
case reflect.Interface:
|
||||
// rt.panic("TODO")
|
||||
// Not sure if this is right.
|
||||
return typ
|
||||
case reflect.Map:
|
||||
return reflect.MapOf(rt.tysubst(typ.Key()), rt.tysubst(typ.Elem()))
|
||||
case reflect.Ptr:
|
||||
return reflect.PtrTo(rt.tysubst(typ.Elem()))
|
||||
case reflect.Slice:
|
||||
return reflect.SliceOf(rt.tysubst(typ.Elem()))
|
||||
case reflect.Struct:
|
||||
rt.panic("Cannot dynamically create Struct types.")
|
||||
case reflect.UnsafePointer:
|
||||
rt.panic("Cannot dynamically create unsafe.Pointer types.")
|
||||
}
|
||||
|
||||
// We've covered all the composite types, so we're only left with
|
||||
// base types.
|
||||
return typ
|
||||
}
|
||||
|
||||
func tyvarName(t reflect.Type) string {
|
||||
if !t.ConvertibleTo(tyvarUnderlyingType) {
|
||||
return ""
|
||||
}
|
||||
return t.Name()
|
||||
}
|
||||
|
||||
// AssertType panics with a `TypeError` if `v` does not have type `t`.
|
||||
// Otherwise, it returns the `reflect.Value` of `v`.
|
||||
func AssertType(v interface{}, t reflect.Type) reflect.Value {
|
||||
rv := reflect.ValueOf(v)
|
||||
tv := rv.Type()
|
||||
if tv != t {
|
||||
ppe("Value '%v' has type '%s' but expected '%s'.", v, tv, t)
|
||||
}
|
||||
return rv
|
||||
}
|
28
vendor/github.com/BurntSushi/ty/tyvars.go
generated
vendored
Normal file
28
vendor/github.com/BurntSushi/ty/tyvars.go
generated
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
package ty
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// TypeVariable is the underlying type of every type variable used in
|
||||
// parametric types. It should not be used directly. Instead, use
|
||||
//
|
||||
// type myOwnTypeVariable TypeVariable
|
||||
//
|
||||
// to create your own type variable. For your convenience, this package
|
||||
// defines some type variables for you. (e.g., `A`, `B`, `C`, ...)
|
||||
type TypeVariable struct {
|
||||
noImitation struct{}
|
||||
}
|
||||
|
||||
// tyvarUnderlyingType is used to discover types that are type variables.
|
||||
// Namely, any type variable must be convertible to `TypeVariable`.
|
||||
var tyvarUnderlyingType = reflect.TypeOf(TypeVariable{})
|
||||
|
||||
type A TypeVariable
|
||||
type B TypeVariable
|
||||
type C TypeVariable
|
||||
type D TypeVariable
|
||||
type E TypeVariable
|
||||
type F TypeVariable
|
||||
type G TypeVariable
|
Loading…
Add table
Add a link
Reference in a new issue