mirror of https://github.com/gogits/gogs.git
Unknwon
7 years ago
45 changed files with 2473 additions and 0 deletions
@ -0,0 +1,201 @@ |
|||||||
|
Apache License |
||||||
|
Version 2.0, January 2004 |
||||||
|
http://www.apache.org/licenses/ |
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION |
||||||
|
|
||||||
|
1. Definitions. |
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction, |
||||||
|
and distribution as defined by Sections 1 through 9 of this document. |
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by |
||||||
|
the copyright owner that is granting the License. |
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all |
||||||
|
other entities that control, are controlled by, or are under common |
||||||
|
control with that entity. For the purposes of this definition, |
||||||
|
"control" means (i) the power, direct or indirect, to cause the |
||||||
|
direction or management of such entity, whether by contract or |
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the |
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity. |
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity |
||||||
|
exercising permissions granted by this License. |
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications, |
||||||
|
including but not limited to software source code, documentation |
||||||
|
source, and configuration files. |
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical |
||||||
|
transformation or translation of a Source form, including but |
||||||
|
not limited to compiled object code, generated documentation, |
||||||
|
and conversions to other media types. |
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or |
||||||
|
Object form, made available under the License, as indicated by a |
||||||
|
copyright notice that is included in or attached to the work |
||||||
|
(an example is provided in the Appendix below). |
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object |
||||||
|
form, that is based on (or derived from) the Work and for which the |
||||||
|
editorial revisions, annotations, elaborations, or other modifications |
||||||
|
represent, as a whole, an original work of authorship. For the purposes |
||||||
|
of this License, Derivative Works shall not include works that remain |
||||||
|
separable from, or merely link (or bind by name) to the interfaces of, |
||||||
|
the Work and Derivative Works thereof. |
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including |
||||||
|
the original version of the Work and any modifications or additions |
||||||
|
to that Work or Derivative Works thereof, that is intentionally |
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner |
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of |
||||||
|
the copyright owner. For the purposes of this definition, "submitted" |
||||||
|
means any form of electronic, verbal, or written communication sent |
||||||
|
to the Licensor or its representatives, including but not limited to |
||||||
|
communication on electronic mailing lists, source code control systems, |
||||||
|
and issue tracking systems that are managed by, or on behalf of, the |
||||||
|
Licensor for the purpose of discussing and improving the Work, but |
||||||
|
excluding communication that is conspicuously marked or otherwise |
||||||
|
designated in writing by the copyright owner as "Not a Contribution." |
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity |
||||||
|
on behalf of whom a Contribution has been received by Licensor and |
||||||
|
subsequently incorporated within the Work. |
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of |
||||||
|
this License, each Contributor hereby grants to You a perpetual, |
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable |
||||||
|
copyright license to reproduce, prepare Derivative Works of, |
||||||
|
publicly display, publicly perform, sublicense, and distribute the |
||||||
|
Work and such Derivative Works in Source or Object form. |
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of |
||||||
|
this License, each Contributor hereby grants to You a perpetual, |
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable |
||||||
|
(except as stated in this section) patent license to make, have made, |
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work, |
||||||
|
where such license applies only to those patent claims licensable |
||||||
|
by such Contributor that are necessarily infringed by their |
||||||
|
Contribution(s) alone or by combination of their Contribution(s) |
||||||
|
with the Work to which such Contribution(s) was submitted. If You |
||||||
|
institute patent litigation against any entity (including a |
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work |
||||||
|
or a Contribution incorporated within the Work constitutes direct |
||||||
|
or contributory patent infringement, then any patent licenses |
||||||
|
granted to You under this License for that Work shall terminate |
||||||
|
as of the date such litigation is filed. |
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the |
||||||
|
Work or Derivative Works thereof in any medium, with or without |
||||||
|
modifications, and in Source or Object form, provided that You |
||||||
|
meet the following conditions: |
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or |
||||||
|
Derivative Works a copy of this License; and |
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices |
||||||
|
stating that You changed the files; and |
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works |
||||||
|
that You distribute, all copyright, patent, trademark, and |
||||||
|
attribution notices from the Source form of the Work, |
||||||
|
excluding those notices that do not pertain to any part of |
||||||
|
the Derivative Works; and |
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its |
||||||
|
distribution, then any Derivative Works that You distribute must |
||||||
|
include a readable copy of the attribution notices contained |
||||||
|
within such NOTICE file, excluding those notices that do not |
||||||
|
pertain to any part of the Derivative Works, in at least one |
||||||
|
of the following places: within a NOTICE text file distributed |
||||||
|
as part of the Derivative Works; within the Source form or |
||||||
|
documentation, if provided along with the Derivative Works; or, |
||||||
|
within a display generated by the Derivative Works, if and |
||||||
|
wherever such third-party notices normally appear. The contents |
||||||
|
of the NOTICE file are for informational purposes only and |
||||||
|
do not modify the License. You may add Your own attribution |
||||||
|
notices within Derivative Works that You distribute, alongside |
||||||
|
or as an addendum to the NOTICE text from the Work, provided |
||||||
|
that such additional attribution notices cannot be construed |
||||||
|
as modifying the License. |
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and |
||||||
|
may provide additional or different license terms and conditions |
||||||
|
for use, reproduction, or distribution of Your modifications, or |
||||||
|
for any such Derivative Works as a whole, provided Your use, |
||||||
|
reproduction, and distribution of the Work otherwise complies with |
||||||
|
the conditions stated in this License. |
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise, |
||||||
|
any Contribution intentionally submitted for inclusion in the Work |
||||||
|
by You to the Licensor shall be under the terms and conditions of |
||||||
|
this License, without any additional terms or conditions. |
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify |
||||||
|
the terms of any separate license agreement you may have executed |
||||||
|
with Licensor regarding such Contributions. |
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade |
||||||
|
names, trademarks, service marks, or product names of the Licensor, |
||||||
|
except as required for reasonable and customary use in describing the |
||||||
|
origin of the Work and reproducing the content of the NOTICE file. |
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or |
||||||
|
agreed to in writing, Licensor provides the Work (and each |
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS, |
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
||||||
|
implied, including, without limitation, any warranties or conditions |
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A |
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the |
||||||
|
appropriateness of using or redistributing the Work and assume any |
||||||
|
risks associated with Your exercise of permissions under this License. |
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory, |
||||||
|
whether in tort (including negligence), contract, or otherwise, |
||||||
|
unless required by applicable law (such as deliberate and grossly |
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be |
||||||
|
liable to You for damages, including any direct, indirect, special, |
||||||
|
incidental, or consequential damages of any character arising as a |
||||||
|
result of this License or out of the use or inability to use the |
||||||
|
Work (including but not limited to damages for loss of goodwill, |
||||||
|
work stoppage, computer failure or malfunction, or any and all |
||||||
|
other commercial damages or losses), even if such Contributor |
||||||
|
has been advised of the possibility of such damages. |
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing |
||||||
|
the Work or Derivative Works thereof, You may choose to offer, |
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity, |
||||||
|
or other liability obligations and/or rights consistent with this |
||||||
|
License. However, in accepting such obligations, You may act only |
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf |
||||||
|
of any other Contributor, and only if You agree to indemnify, |
||||||
|
defend, and hold each Contributor harmless for any liability |
||||||
|
incurred by, or claims asserted against, such Contributor by reason |
||||||
|
of your accepting any such warranty or additional liability. |
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS |
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work. |
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following |
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]" |
||||||
|
replaced with your own identifying information. (Don't include |
||||||
|
the brackets!) The text should be enclosed in the appropriate |
||||||
|
comment syntax for the file format. We also recommend that a |
||||||
|
file or class name and description of purpose be included on the |
||||||
|
same "printed page" as the copyright notice for easier |
||||||
|
identification within third-party archives. |
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner] |
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
you may not use this file except in compliance with the License. |
||||||
|
You may obtain a copy of the License at |
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software |
||||||
|
distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
See the License for the specific language governing permissions and |
||||||
|
limitations under the License. |
@ -0,0 +1,49 @@ |
|||||||
|
# concurrent |
||||||
|
|
||||||
|
[![Sourcegraph](https://sourcegraph.com/github.com/modern-go/concurrent/-/badge.svg)](https://sourcegraph.com/github.com/modern-go/concurrent?badge) |
||||||
|
[![GoDoc](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)](http://godoc.org/github.com/modern-go/concurrent) |
||||||
|
[![Build Status](https://travis-ci.org/modern-go/concurrent.svg?branch=master)](https://travis-ci.org/modern-go/concurrent) |
||||||
|
[![codecov](https://codecov.io/gh/modern-go/concurrent/branch/master/graph/badge.svg)](https://codecov.io/gh/modern-go/concurrent) |
||||||
|
[![rcard](https://goreportcard.com/badge/github.com/modern-go/concurrent)](https://goreportcard.com/report/github.com/modern-go/concurrent) |
||||||
|
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://raw.githubusercontent.com/modern-go/concurrent/master/LICENSE) |
||||||
|
|
||||||
|
* concurrent.Map: backport sync.Map for go below 1.9 |
||||||
|
* concurrent.Executor: goroutine with explicit ownership and cancellable |
||||||
|
|
||||||
|
# concurrent.Map |
||||||
|
|
||||||
|
because sync.Map is only available in go 1.9, we can use concurrent.Map to make code portable |
||||||
|
|
||||||
|
```go |
||||||
|
m := concurrent.NewMap() |
||||||
|
m.Store("hello", "world") |
||||||
|
elem, found := m.Load("hello") |
||||||
|
// elem will be "world" |
||||||
|
// found will be true |
||||||
|
``` |
||||||
|
|
||||||
|
# concurrent.Executor |
||||||
|
|
||||||
|
```go |
||||||
|
executor := concurrent.NewUnboundedExecutor() |
||||||
|
executor.Go(func(ctx context.Context) { |
||||||
|
everyMillisecond := time.NewTicker(time.Millisecond) |
||||||
|
for { |
||||||
|
select { |
||||||
|
case <-ctx.Done(): |
||||||
|
fmt.Println("goroutine exited") |
||||||
|
return |
||||||
|
case <-everyMillisecond.C: |
||||||
|
// do something |
||||||
|
} |
||||||
|
} |
||||||
|
}) |
||||||
|
time.Sleep(time.Second) |
||||||
|
executor.StopAndWaitForever() |
||||||
|
fmt.Println("executor stopped") |
||||||
|
``` |
||||||
|
|
||||||
|
attach goroutine to executor instance, so that we can |
||||||
|
|
||||||
|
* cancel it by stop the executor with Stop/StopAndWait/StopAndWaitForever |
||||||
|
* handle panic by callback: the default behavior will no longer crash your application |
@ -0,0 +1,14 @@ |
|||||||
|
package concurrent |
||||||
|
|
||||||
|
import "context" |
||||||
|
|
||||||
|
// Executor replace go keyword to start a new goroutine
|
||||||
|
// the goroutine should cancel itself if the context passed in has been cancelled
|
||||||
|
// the goroutine started by the executor, is owned by the executor
|
||||||
|
// we can cancel all executors owned by the executor just by stop the executor itself
|
||||||
|
// however Executor interface does not Stop method, the one starting and owning executor
|
||||||
|
// should use the concrete type of executor, instead of this interface.
|
||||||
|
type Executor interface { |
||||||
|
// Go starts a new goroutine controlled by the context
|
||||||
|
Go(handler func(ctx context.Context)) |
||||||
|
} |
@ -0,0 +1,15 @@ |
|||||||
|
//+build go1.9
|
||||||
|
|
||||||
|
package concurrent |
||||||
|
|
||||||
|
import "sync" |
||||||
|
|
||||||
|
// Map is a wrapper for sync.Map introduced in go1.9
|
||||||
|
type Map struct { |
||||||
|
sync.Map |
||||||
|
} |
||||||
|
|
||||||
|
// NewMap creates a thread safe Map
|
||||||
|
func NewMap() *Map { |
||||||
|
return &Map{} |
||||||
|
} |
@ -0,0 +1,33 @@ |
|||||||
|
//+build !go1.9
|
||||||
|
|
||||||
|
package concurrent |
||||||
|
|
||||||
|
import "sync" |
||||||
|
|
||||||
|
// Map implements a thread safe map for go version below 1.9 using mutex
|
||||||
|
type Map struct { |
||||||
|
lock sync.RWMutex |
||||||
|
data map[interface{}]interface{} |
||||||
|
} |
||||||
|
|
||||||
|
// NewMap creates a thread safe map
|
||||||
|
func NewMap() *Map { |
||||||
|
return &Map{ |
||||||
|
data: make(map[interface{}]interface{}, 32), |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Load is same as sync.Map Load
|
||||||
|
func (m *Map) Load(key interface{}) (elem interface{}, found bool) { |
||||||
|
m.lock.RLock() |
||||||
|
elem, found = m.data[key] |
||||||
|
m.lock.RUnlock() |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// Load is same as sync.Map Store
|
||||||
|
func (m *Map) Store(key interface{}, elem interface{}) { |
||||||
|
m.lock.Lock() |
||||||
|
m.data[key] = elem |
||||||
|
m.lock.Unlock() |
||||||
|
} |
@ -0,0 +1,13 @@ |
|||||||
|
package concurrent |
||||||
|
|
||||||
|
import ( |
||||||
|
"os" |
||||||
|
"log" |
||||||
|
"io/ioutil" |
||||||
|
) |
||||||
|
|
||||||
|
// ErrorLogger is used to print out error, can be set to writer other than stderr
|
||||||
|
var ErrorLogger = log.New(os.Stderr, "", 0) |
||||||
|
|
||||||
|
// InfoLogger is used to print informational message, default to off
|
||||||
|
var InfoLogger = log.New(ioutil.Discard, "", 0) |
@ -0,0 +1,12 @@ |
|||||||
|
#!/usr/bin/env bash |
||||||
|
|
||||||
|
set -e |
||||||
|
echo "" > coverage.txt |
||||||
|
|
||||||
|
for d in $(go list ./... | grep -v vendor); do |
||||||
|
go test -coverprofile=profile.out -coverpkg=github.com/modern-go/concurrent $d |
||||||
|
if [ -f profile.out ]; then |
||||||
|
cat profile.out >> coverage.txt |
||||||
|
rm profile.out |
||||||
|
fi |
||||||
|
done |
@ -0,0 +1,119 @@ |
|||||||
|
package concurrent |
||||||
|
|
||||||
|
import ( |
||||||
|
"context" |
||||||
|
"fmt" |
||||||
|
"runtime" |
||||||
|
"runtime/debug" |
||||||
|
"sync" |
||||||
|
"time" |
||||||
|
"reflect" |
||||||
|
) |
||||||
|
|
||||||
|
// HandlePanic logs goroutine panic by default
|
||||||
|
var HandlePanic = func(recovered interface{}, funcName string) { |
||||||
|
ErrorLogger.Println(fmt.Sprintf("%s panic: %v", funcName, recovered)) |
||||||
|
ErrorLogger.Println(string(debug.Stack())) |
||||||
|
} |
||||||
|
|
||||||
|
// UnboundedExecutor is a executor without limits on counts of alive goroutines
|
||||||
|
// it tracks the goroutine started by it, and can cancel them when shutdown
|
||||||
|
type UnboundedExecutor struct { |
||||||
|
ctx context.Context |
||||||
|
cancel context.CancelFunc |
||||||
|
activeGoroutinesMutex *sync.Mutex |
||||||
|
activeGoroutines map[string]int |
||||||
|
HandlePanic func(recovered interface{}, funcName string) |
||||||
|
} |
||||||
|
|
||||||
|
// GlobalUnboundedExecutor has the life cycle of the program itself
|
||||||
|
// any goroutine want to be shutdown before main exit can be started from this executor
|
||||||
|
// GlobalUnboundedExecutor expects the main function to call stop
|
||||||
|
// it does not magically knows the main function exits
|
||||||
|
var GlobalUnboundedExecutor = NewUnboundedExecutor() |
||||||
|
|
||||||
|
// NewUnboundedExecutor creates a new UnboundedExecutor,
|
||||||
|
// UnboundedExecutor can not be created by &UnboundedExecutor{}
|
||||||
|
// HandlePanic can be set with a callback to override global HandlePanic
|
||||||
|
func NewUnboundedExecutor() *UnboundedExecutor { |
||||||
|
ctx, cancel := context.WithCancel(context.TODO()) |
||||||
|
return &UnboundedExecutor{ |
||||||
|
ctx: ctx, |
||||||
|
cancel: cancel, |
||||||
|
activeGoroutinesMutex: &sync.Mutex{}, |
||||||
|
activeGoroutines: map[string]int{}, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Go starts a new goroutine and tracks its lifecycle.
|
||||||
|
// Panic will be recovered and logged automatically, except for StopSignal
|
||||||
|
func (executor *UnboundedExecutor) Go(handler func(ctx context.Context)) { |
||||||
|
pc := reflect.ValueOf(handler).Pointer() |
||||||
|
f := runtime.FuncForPC(pc) |
||||||
|
funcName := f.Name() |
||||||
|
file, line := f.FileLine(pc) |
||||||
|
executor.activeGoroutinesMutex.Lock() |
||||||
|
defer executor.activeGoroutinesMutex.Unlock() |
||||||
|
startFrom := fmt.Sprintf("%s:%d", file, line) |
||||||
|
executor.activeGoroutines[startFrom] += 1 |
||||||
|
go func() { |
||||||
|
defer func() { |
||||||
|
recovered := recover() |
||||||
|
// if you want to quit a goroutine without trigger HandlePanic
|
||||||
|
// use runtime.Goexit() to quit
|
||||||
|
if recovered != nil { |
||||||
|
if executor.HandlePanic == nil { |
||||||
|
HandlePanic(recovered, funcName) |
||||||
|
} else { |
||||||
|
executor.HandlePanic(recovered, funcName) |
||||||
|
} |
||||||
|
} |
||||||
|
executor.activeGoroutinesMutex.Lock() |
||||||
|
executor.activeGoroutines[startFrom] -= 1 |
||||||
|
executor.activeGoroutinesMutex.Unlock() |
||||||
|
}() |
||||||
|
handler(executor.ctx) |
||||||
|
}() |
||||||
|
} |
||||||
|
|
||||||
|
// Stop cancel all goroutines started by this executor without wait
|
||||||
|
func (executor *UnboundedExecutor) Stop() { |
||||||
|
executor.cancel() |
||||||
|
} |
||||||
|
|
||||||
|
// StopAndWaitForever cancel all goroutines started by this executor and
|
||||||
|
// wait until all goroutines exited
|
||||||
|
func (executor *UnboundedExecutor) StopAndWaitForever() { |
||||||
|
executor.StopAndWait(context.Background()) |
||||||
|
} |
||||||
|
|
||||||
|
// StopAndWait cancel all goroutines started by this executor and wait.
|
||||||
|
// Wait can be cancelled by the context passed in.
|
||||||
|
func (executor *UnboundedExecutor) StopAndWait(ctx context.Context) { |
||||||
|
executor.cancel() |
||||||
|
for { |
||||||
|
oneHundredMilliseconds := time.NewTimer(time.Millisecond * 100) |
||||||
|
select { |
||||||
|
case <-oneHundredMilliseconds.C: |
||||||
|
if executor.checkNoActiveGoroutines() { |
||||||
|
return |
||||||
|
} |
||||||
|
case <-ctx.Done(): |
||||||
|
return |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func (executor *UnboundedExecutor) checkNoActiveGoroutines() bool { |
||||||
|
executor.activeGoroutinesMutex.Lock() |
||||||
|
defer executor.activeGoroutinesMutex.Unlock() |
||||||
|
for startFrom, count := range executor.activeGoroutines { |
||||||
|
if count > 0 { |
||||||
|
InfoLogger.Println("UnboundedExecutor is still waiting goroutines to quit", |
||||||
|
"startFrom", startFrom, |
||||||
|
"count", count) |
||||||
|
return false |
||||||
|
} |
||||||
|
} |
||||||
|
return true |
||||||
|
} |
@ -0,0 +1,15 @@ |
|||||||
|
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. |
||||||
|
|
||||||
|
|
||||||
|
[[projects]] |
||||||
|
name = "github.com/modern-go/concurrent" |
||||||
|
packages = ["."] |
||||||
|
revision = "e0a39a4cb4216ea8db28e22a69f4ec25610d513a" |
||||||
|
version = "1.0.0" |
||||||
|
|
||||||
|
[solve-meta] |
||||||
|
analyzer-name = "dep" |
||||||
|
analyzer-version = 1 |
||||||
|
inputs-digest = "daee8a88b3498b61c5640056665b8b9eea062006f5e596bbb6a3ed9119a11ec7" |
||||||
|
solver-name = "gps-cdcl" |
||||||
|
solver-version = 1 |
@ -0,0 +1,35 @@ |
|||||||
|
# Gopkg.toml example |
||||||
|
# |
||||||
|
# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html |
||||||
|
# for detailed Gopkg.toml documentation. |
||||||
|
# |
||||||
|
# required = ["github.com/user/thing/cmd/thing"] |
||||||
|
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] |
||||||
|
# |
||||||
|
# [[constraint]] |
||||||
|
# name = "github.com/user/project" |
||||||
|
# version = "1.0.0" |
||||||
|
# |
||||||
|
# [[constraint]] |
||||||
|
# name = "github.com/user/project2" |
||||||
|
# branch = "dev" |
||||||
|
# source = "github.com/myfork/project2" |
||||||
|
# |
||||||
|
# [[override]] |
||||||
|
# name = "github.com/x/y" |
||||||
|
# version = "2.4.0" |
||||||
|
# |
||||||
|
# [prune] |
||||||
|
# non-go = false |
||||||
|
# go-tests = true |
||||||
|
# unused-packages = true |
||||||
|
|
||||||
|
ignored = ["github.com/modern-go/test","github.com/modern-go/test/must","github.com/modern-go/test/should"] |
||||||
|
|
||||||
|
[[constraint]] |
||||||
|
name = "github.com/modern-go/concurrent" |
||||||
|
version = "1.0.0" |
||||||
|
|
||||||
|
[prune] |
||||||
|
go-tests = true |
||||||
|
unused-packages = true |
@ -0,0 +1,201 @@ |
|||||||
|
Apache License |
||||||
|
Version 2.0, January 2004 |
||||||
|
http://www.apache.org/licenses/ |
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION |
||||||
|
|
||||||
|
1. Definitions. |
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction, |
||||||
|
and distribution as defined by Sections 1 through 9 of this document. |
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by |
||||||
|
the copyright owner that is granting the License. |
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all |
||||||
|
other entities that control, are controlled by, or are under common |
||||||
|
control with that entity. For the purposes of this definition, |
||||||
|
"control" means (i) the power, direct or indirect, to cause the |
||||||
|
direction or management of such entity, whether by contract or |
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the |
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity. |
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity |
||||||
|
exercising permissions granted by this License. |
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications, |
||||||
|
including but not limited to software source code, documentation |
||||||
|
source, and configuration files. |
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical |
||||||
|
transformation or translation of a Source form, including but |
||||||
|
not limited to compiled object code, generated documentation, |
||||||
|
and conversions to other media types. |
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or |
||||||
|
Object form, made available under the License, as indicated by a |
||||||
|
copyright notice that is included in or attached to the work |
||||||
|
(an example is provided in the Appendix below). |
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object |
||||||
|
form, that is based on (or derived from) the Work and for which the |
||||||
|
editorial revisions, annotations, elaborations, or other modifications |
||||||
|
represent, as a whole, an original work of authorship. For the purposes |
||||||
|
of this License, Derivative Works shall not include works that remain |
||||||
|
separable from, or merely link (or bind by name) to the interfaces of, |
||||||
|
the Work and Derivative Works thereof. |
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including |
||||||
|
the original version of the Work and any modifications or additions |
||||||
|
to that Work or Derivative Works thereof, that is intentionally |
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner |
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of |
||||||
|
the copyright owner. For the purposes of this definition, "submitted" |
||||||
|
means any form of electronic, verbal, or written communication sent |
||||||
|
to the Licensor or its representatives, including but not limited to |
||||||
|
communication on electronic mailing lists, source code control systems, |
||||||
|
and issue tracking systems that are managed by, or on behalf of, the |
||||||
|
Licensor for the purpose of discussing and improving the Work, but |
||||||
|
excluding communication that is conspicuously marked or otherwise |
||||||
|
designated in writing by the copyright owner as "Not a Contribution." |
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity |
||||||
|
on behalf of whom a Contribution has been received by Licensor and |
||||||
|
subsequently incorporated within the Work. |
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of |
||||||
|
this License, each Contributor hereby grants to You a perpetual, |
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable |
||||||
|
copyright license to reproduce, prepare Derivative Works of, |
||||||
|
publicly display, publicly perform, sublicense, and distribute the |
||||||
|
Work and such Derivative Works in Source or Object form. |
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of |
||||||
|
this License, each Contributor hereby grants to You a perpetual, |
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable |
||||||
|
(except as stated in this section) patent license to make, have made, |
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work, |
||||||
|
where such license applies only to those patent claims licensable |
||||||
|
by such Contributor that are necessarily infringed by their |
||||||
|
Contribution(s) alone or by combination of their Contribution(s) |
||||||
|
with the Work to which such Contribution(s) was submitted. If You |
||||||
|
institute patent litigation against any entity (including a |
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work |
||||||
|
or a Contribution incorporated within the Work constitutes direct |
||||||
|
or contributory patent infringement, then any patent licenses |
||||||
|
granted to You under this License for that Work shall terminate |
||||||
|
as of the date such litigation is filed. |
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the |
||||||
|
Work or Derivative Works thereof in any medium, with or without |
||||||
|
modifications, and in Source or Object form, provided that You |
||||||
|
meet the following conditions: |
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or |
||||||
|
Derivative Works a copy of this License; and |
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices |
||||||
|
stating that You changed the files; and |
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works |
||||||
|
that You distribute, all copyright, patent, trademark, and |
||||||
|
attribution notices from the Source form of the Work, |
||||||
|
excluding those notices that do not pertain to any part of |
||||||
|
the Derivative Works; and |
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its |
||||||
|
distribution, then any Derivative Works that You distribute must |
||||||
|
include a readable copy of the attribution notices contained |
||||||
|
within such NOTICE file, excluding those notices that do not |
||||||
|
pertain to any part of the Derivative Works, in at least one |
||||||
|
of the following places: within a NOTICE text file distributed |
||||||
|
as part of the Derivative Works; within the Source form or |
||||||
|
documentation, if provided along with the Derivative Works; or, |
||||||
|
within a display generated by the Derivative Works, if and |
||||||
|
wherever such third-party notices normally appear. The contents |
||||||
|
of the NOTICE file are for informational purposes only and |
||||||
|
do not modify the License. You may add Your own attribution |
||||||
|
notices within Derivative Works that You distribute, alongside |
||||||
|
or as an addendum to the NOTICE text from the Work, provided |
||||||
|
that such additional attribution notices cannot be construed |
||||||
|
as modifying the License. |
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and |
||||||
|
may provide additional or different license terms and conditions |
||||||
|
for use, reproduction, or distribution of Your modifications, or |
||||||
|
for any such Derivative Works as a whole, provided Your use, |
||||||
|
reproduction, and distribution of the Work otherwise complies with |
||||||
|
the conditions stated in this License. |
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise, |
||||||
|
any Contribution intentionally submitted for inclusion in the Work |
||||||
|
by You to the Licensor shall be under the terms and conditions of |
||||||
|
this License, without any additional terms or conditions. |
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify |
||||||
|
the terms of any separate license agreement you may have executed |
||||||
|
with Licensor regarding such Contributions. |
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade |
||||||
|
names, trademarks, service marks, or product names of the Licensor, |
||||||
|
except as required for reasonable and customary use in describing the |
||||||
|
origin of the Work and reproducing the content of the NOTICE file. |
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or |
||||||
|
agreed to in writing, Licensor provides the Work (and each |
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS, |
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
||||||
|
implied, including, without limitation, any warranties or conditions |
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A |
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the |
||||||
|
appropriateness of using or redistributing the Work and assume any |
||||||
|
risks associated with Your exercise of permissions under this License. |
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory, |
||||||
|
whether in tort (including negligence), contract, or otherwise, |
||||||
|
unless required by applicable law (such as deliberate and grossly |
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be |
||||||
|
liable to You for damages, including any direct, indirect, special, |
||||||
|
incidental, or consequential damages of any character arising as a |
||||||
|
result of this License or out of the use or inability to use the |
||||||
|
Work (including but not limited to damages for loss of goodwill, |
||||||
|
work stoppage, computer failure or malfunction, or any and all |
||||||
|
other commercial damages or losses), even if such Contributor |
||||||
|
has been advised of the possibility of such damages. |
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing |
||||||
|
the Work or Derivative Works thereof, You may choose to offer, |
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity, |
||||||
|
or other liability obligations and/or rights consistent with this |
||||||
|
License. However, in accepting such obligations, You may act only |
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf |
||||||
|
of any other Contributor, and only if You agree to indemnify, |
||||||
|
defend, and hold each Contributor harmless for any liability |
||||||
|
incurred by, or claims asserted against, such Contributor by reason |
||||||
|
of your accepting any such warranty or additional liability. |
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS |
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work. |
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following |
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]" |
||||||
|
replaced with your own identifying information. (Don't include |
||||||
|
the brackets!) The text should be enclosed in the appropriate |
||||||
|
comment syntax for the file format. We also recommend that a |
||||||
|
file or class name and description of purpose be included on the |
||||||
|
same "printed page" as the copyright notice for easier |
||||||
|
identification within third-party archives. |
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner] |
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
you may not use this file except in compliance with the License. |
||||||
|
You may obtain a copy of the License at |
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software |
||||||
|
distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
See the License for the specific language governing permissions and |
||||||
|
limitations under the License. |
@ -0,0 +1,71 @@ |
|||||||
|
# reflect2 |
||||||
|
|
||||||
|
[![Sourcegraph](https://sourcegraph.com/github.com/modern-go/reflect2/-/badge.svg)](https://sourcegraph.com/github.com/modern-go/reflect2?badge) |
||||||
|
[![GoDoc](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)](http://godoc.org/github.com/modern-go/reflect2) |
||||||
|
[![Build Status](https://travis-ci.org/modern-go/reflect2.svg?branch=master)](https://travis-ci.org/modern-go/reflect2) |
||||||
|
[![codecov](https://codecov.io/gh/modern-go/reflect2/branch/master/graph/badge.svg)](https://codecov.io/gh/modern-go/reflect2) |
||||||
|
[![rcard](https://goreportcard.com/badge/github.com/modern-go/reflect2)](https://goreportcard.com/report/github.com/modern-go/reflect2) |
||||||
|
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://raw.githubusercontent.com/modern-go/reflect2/master/LICENSE) |
||||||
|
|
||||||
|
reflect api that avoids runtime reflect.Value cost |
||||||
|
|
||||||
|
* reflect get/set interface{}, with type checking |
||||||
|
* reflect get/set unsafe.Pointer, without type checking |
||||||
|
* `reflect2.TypeByName` works like `Class.forName` found in java |
||||||
|
|
||||||
|
[json-iterator](https://github.com/json-iterator/go) use this package to save runtime dispatching cost. |
||||||
|
This package is designed for low level libraries to optimize reflection performance. |
||||||
|
General application should still use reflect standard library. |
||||||
|
|
||||||
|
# reflect2.TypeByName |
||||||
|
|
||||||
|
```go |
||||||
|
// given package is github.com/your/awesome-package |
||||||
|
type MyStruct struct { |
||||||
|
// ... |
||||||
|
} |
||||||
|
|
||||||
|
// will return the type |
||||||
|
reflect2.TypeByName("awesome-package.MyStruct") |
||||||
|
// however, if the type has not been used |
||||||
|
// it will be eliminated by compiler, so we can not get it in runtime |
||||||
|
``` |
||||||
|
|
||||||
|
# reflect2 get/set interface{} |
||||||
|
|
||||||
|
```go |
||||||
|
valType := reflect2.TypeOf(1) |
||||||
|
i := 1 |
||||||
|
j := 10 |
||||||
|
valType.Set(&i, &j) |
||||||
|
// i will be 10 |
||||||
|
``` |
||||||
|
|
||||||
|
to get set `type`, always use its pointer `*type` |
||||||
|
|
||||||
|
# reflect2 get/set unsafe.Pointer |
||||||
|
|
||||||
|
```go |
||||||
|
valType := reflect2.TypeOf(1) |
||||||
|
i := 1 |
||||||
|
j := 10 |
||||||
|
valType.UnsafeSet(unsafe.Pointer(&i), unsafe.Pointer(&j)) |
||||||
|
// i will be 10 |
||||||
|
``` |
||||||
|
|
||||||
|
to get set `type`, always use its pointer `*type` |
||||||
|
|
||||||
|
# benchmark |
||||||
|
|
||||||
|
Benchmark is not necessary for this package. It does nothing actually. |
||||||
|
As it is just a thin wrapper to make go runtime public. |
||||||
|
Both `reflect2` and `reflect` call same function |
||||||
|
provided by `runtime` package exposed by go language. |
||||||
|
|
||||||
|
# unsafe safety |
||||||
|
|
||||||
|
Instead of casting `[]byte` to `sliceHeader` in your application using unsafe. |
||||||
|
We can use reflect2 instead. This way, if `sliceHeader` changes in the future, |
||||||
|
only reflect2 need to be upgraded. |
||||||
|
|
||||||
|
reflect2 tries its best to keep the implementation same as reflect (by testing). |
@ -0,0 +1,8 @@ |
|||||||
|
//+build go1.7
|
||||||
|
|
||||||
|
package reflect2 |
||||||
|
|
||||||
|
import "unsafe" |
||||||
|
|
||||||
|
//go:linkname resolveTypeOff reflect.resolveTypeOff
|
||||||
|
func resolveTypeOff(rtype unsafe.Pointer, off int32) unsafe.Pointer |
@ -0,0 +1,14 @@ |
|||||||
|
//+build go1.9
|
||||||
|
|
||||||
|
package reflect2 |
||||||
|
|
||||||
|
import ( |
||||||
|
"unsafe" |
||||||
|
) |
||||||
|
|
||||||
|
//go:linkname makemap reflect.makemap
|
||||||
|
func makemap(rtype unsafe.Pointer, cap int) (m unsafe.Pointer) |
||||||
|
|
||||||
|
func makeMapWithSize(rtype unsafe.Pointer, cap int) unsafe.Pointer { |
||||||
|
return makemap(rtype, cap) |
||||||
|
} |
@ -0,0 +1,9 @@ |
|||||||
|
//+build !go1.7
|
||||||
|
|
||||||
|
package reflect2 |
||||||
|
|
||||||
|
import "unsafe" |
||||||
|
|
||||||
|
func resolveTypeOff(rtype unsafe.Pointer, off int32) unsafe.Pointer { |
||||||
|
return nil |
||||||
|
} |
@ -0,0 +1,14 @@ |
|||||||
|
//+build !go1.9
|
||||||
|
|
||||||
|
package reflect2 |
||||||
|
|
||||||
|
import ( |
||||||
|
"unsafe" |
||||||
|
) |
||||||
|
|
||||||
|
//go:linkname makemap reflect.makemap
|
||||||
|
func makemap(rtype unsafe.Pointer) (m unsafe.Pointer) |
||||||
|
|
||||||
|
func makeMapWithSize(rtype unsafe.Pointer, cap int) unsafe.Pointer { |
||||||
|
return makemap(rtype) |
||||||
|
} |
@ -0,0 +1,298 @@ |
|||||||
|
package reflect2 |
||||||
|
|
||||||
|
import ( |
||||||
|
"github.com/modern-go/concurrent" |
||||||
|
"reflect" |
||||||
|
"unsafe" |
||||||
|
) |
||||||
|
|
||||||
|
type Type interface { |
||||||
|
Kind() reflect.Kind |
||||||
|
// New return pointer to data of this type
|
||||||
|
New() interface{} |
||||||
|
// UnsafeNew return the allocated space pointed by unsafe.Pointer
|
||||||
|
UnsafeNew() unsafe.Pointer |
||||||
|
// PackEFace cast a unsafe pointer to object represented pointer
|
||||||
|
PackEFace(ptr unsafe.Pointer) interface{} |
||||||
|
// Indirect dereference object represented pointer to this type
|
||||||
|
Indirect(obj interface{}) interface{} |
||||||
|
// UnsafeIndirect dereference pointer to this type
|
||||||
|
UnsafeIndirect(ptr unsafe.Pointer) interface{} |
||||||
|
// Type1 returns reflect.Type
|
||||||
|
Type1() reflect.Type |
||||||
|
Implements(thatType Type) bool |
||||||
|
String() string |
||||||
|
RType() uintptr |
||||||
|
// interface{} of this type has pointer like behavior
|
||||||
|
LikePtr() bool |
||||||
|
IsNullable() bool |
||||||
|
IsNil(obj interface{}) bool |
||||||
|
UnsafeIsNil(ptr unsafe.Pointer) bool |
||||||
|
Set(obj interface{}, val interface{}) |
||||||
|
UnsafeSet(ptr unsafe.Pointer, val unsafe.Pointer) |
||||||
|
AssignableTo(anotherType Type) bool |
||||||
|
} |
||||||
|
|
||||||
|
type ListType interface { |
||||||
|
Type |
||||||
|
Elem() Type |
||||||
|
SetIndex(obj interface{}, index int, elem interface{}) |
||||||
|
UnsafeSetIndex(obj unsafe.Pointer, index int, elem unsafe.Pointer) |
||||||
|
GetIndex(obj interface{}, index int) interface{} |
||||||
|
UnsafeGetIndex(obj unsafe.Pointer, index int) unsafe.Pointer |
||||||
|
} |
||||||
|
|
||||||
|
type ArrayType interface { |
||||||
|
ListType |
||||||
|
Len() int |
||||||
|
} |
||||||
|
|
||||||
|
type SliceType interface { |
||||||
|
ListType |
||||||
|
MakeSlice(length int, cap int) interface{} |
||||||
|
UnsafeMakeSlice(length int, cap int) unsafe.Pointer |
||||||
|
Grow(obj interface{}, newLength int) |
||||||
|
UnsafeGrow(ptr unsafe.Pointer, newLength int) |
||||||
|
Append(obj interface{}, elem interface{}) |
||||||
|
UnsafeAppend(obj unsafe.Pointer, elem unsafe.Pointer) |
||||||
|
LengthOf(obj interface{}) int |
||||||
|
UnsafeLengthOf(ptr unsafe.Pointer) int |
||||||
|
SetNil(obj interface{}) |
||||||
|
UnsafeSetNil(ptr unsafe.Pointer) |
||||||
|
Cap(obj interface{}) int |
||||||
|
UnsafeCap(ptr unsafe.Pointer) int |
||||||
|
} |
||||||
|
|
||||||
|
type StructType interface { |
||||||
|
Type |
||||||
|
NumField() int |
||||||
|
Field(i int) StructField |
||||||
|
FieldByName(name string) StructField |
||||||
|
FieldByIndex(index []int) StructField |
||||||
|
FieldByNameFunc(match func(string) bool) StructField |
||||||
|
} |
||||||
|
|
||||||
|
type StructField interface { |
||||||
|
Offset() uintptr |
||||||
|
Name() string |
||||||
|
PkgPath() string |
||||||
|
Type() Type |
||||||
|
Tag() reflect.StructTag |
||||||
|
Index() []int |
||||||
|
Anonymous() bool |
||||||
|
Set(obj interface{}, value interface{}) |
||||||
|
UnsafeSet(obj unsafe.Pointer, value unsafe.Pointer) |
||||||
|
Get(obj interface{}) interface{} |
||||||
|
UnsafeGet(obj unsafe.Pointer) unsafe.Pointer |
||||||
|
} |
||||||
|
|
||||||
|
type MapType interface { |
||||||
|
Type |
||||||
|
Key() Type |
||||||
|
Elem() Type |
||||||
|
MakeMap(cap int) interface{} |
||||||
|
UnsafeMakeMap(cap int) unsafe.Pointer |
||||||
|
SetIndex(obj interface{}, key interface{}, elem interface{}) |
||||||
|
UnsafeSetIndex(obj unsafe.Pointer, key unsafe.Pointer, elem unsafe.Pointer) |
||||||
|
TryGetIndex(obj interface{}, key interface{}) (interface{}, bool) |
||||||
|
GetIndex(obj interface{}, key interface{}) interface{} |
||||||
|
UnsafeGetIndex(obj unsafe.Pointer, key unsafe.Pointer) unsafe.Pointer |
||||||
|
Iterate(obj interface{}) MapIterator |
||||||
|
UnsafeIterate(obj unsafe.Pointer) MapIterator |
||||||
|
} |
||||||
|
|
||||||
|
type MapIterator interface { |
||||||
|
HasNext() bool |
||||||
|
Next() (key interface{}, elem interface{}) |
||||||
|
UnsafeNext() (key unsafe.Pointer, elem unsafe.Pointer) |
||||||
|
} |
||||||
|
|
||||||
|
type PtrType interface { |
||||||
|
Type |
||||||
|
Elem() Type |
||||||
|
} |
||||||
|
|
||||||
|
type InterfaceType interface { |
||||||
|
NumMethod() int |
||||||
|
} |
||||||
|
|
||||||
|
type Config struct { |
||||||
|
UseSafeImplementation bool |
||||||
|
} |
||||||
|
|
||||||
|
type API interface { |
||||||
|
TypeOf(obj interface{}) Type |
||||||
|
Type2(type1 reflect.Type) Type |
||||||
|
} |
||||||
|
|
||||||
|
var ConfigUnsafe = Config{UseSafeImplementation: false}.Froze() |
||||||
|
var ConfigSafe = Config{UseSafeImplementation: true}.Froze() |
||||||
|
|
||||||
|
type frozenConfig struct { |
||||||
|
useSafeImplementation bool |
||||||
|
cache *concurrent.Map |
||||||
|
} |
||||||
|
|
||||||
|
func (cfg Config) Froze() *frozenConfig { |
||||||
|
return &frozenConfig{ |
||||||
|
useSafeImplementation: cfg.UseSafeImplementation, |
||||||
|
cache: concurrent.NewMap(), |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func (cfg *frozenConfig) TypeOf(obj interface{}) Type { |
||||||
|
cacheKey := uintptr(unpackEFace(obj).rtype) |
||||||
|
typeObj, found := cfg.cache.Load(cacheKey) |
||||||
|
if found { |
||||||
|
return typeObj.(Type) |
||||||
|
} |
||||||
|
return cfg.Type2(reflect.TypeOf(obj)) |
||||||
|
} |
||||||
|
|
||||||
|
func (cfg *frozenConfig) Type2(type1 reflect.Type) Type { |
||||||
|
if type1 == nil { |
||||||
|
return nil |
||||||
|
} |
||||||
|
cacheKey := uintptr(unpackEFace(type1).data) |
||||||
|
typeObj, found := cfg.cache.Load(cacheKey) |
||||||
|
if found { |
||||||
|
return typeObj.(Type) |
||||||
|
} |
||||||
|
type2 := cfg.wrapType(type1) |
||||||
|
cfg.cache.Store(cacheKey, type2) |
||||||
|
return type2 |
||||||
|
} |
||||||
|
|
||||||
|
func (cfg *frozenConfig) wrapType(type1 reflect.Type) Type { |
||||||
|
safeType := safeType{Type: type1, cfg: cfg} |
||||||
|
switch type1.Kind() { |
||||||
|
case reflect.Struct: |
||||||
|
if cfg.useSafeImplementation { |
||||||
|
return &safeStructType{safeType} |
||||||
|
} |
||||||
|
return newUnsafeStructType(cfg, type1) |
||||||
|
case reflect.Array: |
||||||
|
if cfg.useSafeImplementation { |
||||||
|
return &safeSliceType{safeType} |
||||||
|
} |
||||||
|
return newUnsafeArrayType(cfg, type1) |
||||||
|
case reflect.Slice: |
||||||
|
if cfg.useSafeImplementation { |
||||||
|
return &safeSliceType{safeType} |
||||||
|
} |
||||||
|
return newUnsafeSliceType(cfg, type1) |
||||||
|
case reflect.Map: |
||||||
|
if cfg.useSafeImplementation { |
||||||
|
return &safeMapType{safeType} |
||||||
|
} |
||||||
|
return newUnsafeMapType(cfg, type1) |
||||||
|
case reflect.Ptr, reflect.Chan, reflect.Func: |
||||||
|
if cfg.useSafeImplementation { |
||||||
|
return &safeMapType{safeType} |
||||||
|
} |
||||||
|
return newUnsafePtrType(cfg, type1) |
||||||
|
case reflect.Interface: |
||||||
|
if cfg.useSafeImplementation { |
||||||
|
return &safeMapType{safeType} |
||||||
|
} |
||||||
|
if type1.NumMethod() == 0 { |
||||||
|
return newUnsafeEFaceType(cfg, type1) |
||||||
|
} |
||||||
|
return newUnsafeIFaceType(cfg, type1) |
||||||
|
default: |
||||||
|
if cfg.useSafeImplementation { |
||||||
|
return &safeType |
||||||
|
} |
||||||
|
return newUnsafeType(cfg, type1) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func TypeOf(obj interface{}) Type { |
||||||
|
return ConfigUnsafe.TypeOf(obj) |
||||||
|
} |
||||||
|
|
||||||
|
func TypeOfPtr(obj interface{}) PtrType { |
||||||
|
return TypeOf(obj).(PtrType) |
||||||
|
} |
||||||
|
|
||||||
|
func Type2(type1 reflect.Type) Type { |
||||||
|
if type1 == nil { |
||||||
|
return nil |
||||||
|
} |
||||||
|
return ConfigUnsafe.Type2(type1) |
||||||
|
} |
||||||
|
|
||||||
|
func PtrTo(typ Type) Type { |
||||||
|
return Type2(reflect.PtrTo(typ.Type1())) |
||||||
|
} |
||||||
|
|
||||||
|
func PtrOf(obj interface{}) unsafe.Pointer { |
||||||
|
return unpackEFace(obj).data |
||||||
|
} |
||||||
|
|
||||||
|
func RTypeOf(obj interface{}) uintptr { |
||||||
|
return uintptr(unpackEFace(obj).rtype) |
||||||
|
} |
||||||
|
|
||||||
|
func IsNil(obj interface{}) bool { |
||||||
|
if obj == nil { |
||||||
|
return true |
||||||
|
} |
||||||
|
return unpackEFace(obj).data == nil |
||||||
|
} |
||||||
|
|
||||||
|
func IsNullable(kind reflect.Kind) bool { |
||||||
|
switch kind { |
||||||
|
case reflect.Ptr, reflect.Map, reflect.Chan, reflect.Func, reflect.Slice, reflect.Interface: |
||||||
|
return true |
||||||
|
} |
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
func likePtrKind(kind reflect.Kind) bool { |
||||||
|
switch kind { |
||||||
|
case reflect.Ptr, reflect.Map, reflect.Chan, reflect.Func: |
||||||
|
return true |
||||||
|
} |
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
func likePtrType(typ reflect.Type) bool { |
||||||
|
if likePtrKind(typ.Kind()) { |
||||||
|
return true |
||||||
|
} |
||||||
|
if typ.Kind() == reflect.Struct { |
||||||
|
if typ.NumField() != 1 { |
||||||
|
return false |
||||||
|
} |
||||||
|
return likePtrType(typ.Field(0).Type) |
||||||
|
} |
||||||
|
if typ.Kind() == reflect.Array { |
||||||
|
if typ.Len() != 1 { |
||||||
|
return false |
||||||
|
} |
||||||
|
return likePtrType(typ.Elem()) |
||||||
|
} |
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
// NoEscape hides a pointer from escape analysis. noescape is
|
||||||
|
// the identity function but escape analysis doesn't think the
|
||||||
|
// output depends on the input. noescape is inlined and currently
|
||||||
|
// compiles down to zero instructions.
|
||||||
|
// USE CAREFULLY!
|
||||||
|
//go:nosplit
|
||||||
|
func NoEscape(p unsafe.Pointer) unsafe.Pointer { |
||||||
|
x := uintptr(p) |
||||||
|
return unsafe.Pointer(x ^ 0) |
||||||
|
} |
||||||
|
|
||||||
|
func UnsafeCastString(str string) []byte { |
||||||
|
stringHeader := (*reflect.StringHeader)(unsafe.Pointer(&str)) |
||||||
|
sliceHeader := &reflect.SliceHeader{ |
||||||
|
Data: stringHeader.Data, |
||||||
|
Cap: stringHeader.Len, |
||||||
|
Len: stringHeader.Len, |
||||||
|
} |
||||||
|
return *(*[]byte)(unsafe.Pointer(sliceHeader)) |
||||||
|
} |
@ -0,0 +1,30 @@ |
|||||||
|
package reflect2 |
||||||
|
|
||||||
|
import ( |
||||||
|
"reflect" |
||||||
|
"unsafe" |
||||||
|
) |
||||||
|
|
||||||
|
// DefaultTypeOfKind return the non aliased default type for the kind
|
||||||
|
func DefaultTypeOfKind(kind reflect.Kind) Type { |
||||||
|
return kindTypes[kind] |
||||||
|
} |
||||||
|
|
||||||
|
var kindTypes = map[reflect.Kind]Type{ |
||||||
|
reflect.Bool: TypeOf(true), |
||||||
|
reflect.Uint8: TypeOf(uint8(0)), |
||||||
|
reflect.Int8: TypeOf(int8(0)), |
||||||
|
reflect.Uint16: TypeOf(uint16(0)), |
||||||
|
reflect.Int16: TypeOf(int16(0)), |
||||||
|
reflect.Uint32: TypeOf(uint32(0)), |
||||||
|
reflect.Int32: TypeOf(int32(0)), |
||||||
|
reflect.Uint64: TypeOf(uint64(0)), |
||||||
|
reflect.Int64: TypeOf(int64(0)), |
||||||
|
reflect.Uint: TypeOf(uint(0)), |
||||||
|
reflect.Int: TypeOf(int(0)), |
||||||
|
reflect.Float32: TypeOf(float32(0)), |
||||||
|
reflect.Float64: TypeOf(float64(0)), |
||||||
|
reflect.Uintptr: TypeOf(uintptr(0)), |
||||||
|
reflect.String: TypeOf(""), |
||||||
|
reflect.UnsafePointer: TypeOf(unsafe.Pointer(nil)), |
||||||
|
} |
@ -0,0 +1,58 @@ |
|||||||
|
package reflect2 |
||||||
|
|
||||||
|
import ( |
||||||
|
"reflect" |
||||||
|
"unsafe" |
||||||
|
) |
||||||
|
|
||||||
|
type safeField struct { |
||||||
|
reflect.StructField |
||||||
|
} |
||||||
|
|
||||||
|
func (field *safeField) Offset() uintptr { |
||||||
|
return field.StructField.Offset |
||||||
|
} |
||||||
|
|
||||||
|
func (field *safeField) Name() string { |
||||||
|
return field.StructField.Name |
||||||
|
} |
||||||
|
|
||||||
|
func (field *safeField) PkgPath() string { |
||||||
|
return field.StructField.PkgPath |
||||||
|
} |
||||||
|
|
||||||
|
func (field *safeField) Type() Type { |
||||||
|
panic("not implemented") |
||||||
|
} |
||||||
|
|
||||||
|
func (field *safeField) Tag() reflect.StructTag { |
||||||
|
return field.StructField.Tag |
||||||
|
} |
||||||
|
|
||||||
|
func (field *safeField) Index() []int { |
||||||
|
return field.StructField.Index |
||||||
|
} |
||||||
|
|
||||||
|
func (field *safeField) Anonymous() bool { |
||||||
|
return field.StructField.Anonymous |
||||||
|
} |
||||||
|
|
||||||
|
func (field *safeField) Set(obj interface{}, value interface{}) { |
||||||
|
val := reflect.ValueOf(obj).Elem() |
||||||
|
val.FieldByIndex(field.Index()).Set(reflect.ValueOf(value).Elem()) |
||||||
|
} |
||||||
|
|
||||||
|
func (field *safeField) UnsafeSet(obj unsafe.Pointer, value unsafe.Pointer) { |
||||||
|
panic("unsafe operation is not supported") |
||||||
|
} |
||||||
|
|
||||||
|
func (field *safeField) Get(obj interface{}) interface{} { |
||||||
|
val := reflect.ValueOf(obj).Elem().FieldByIndex(field.Index()) |
||||||
|
ptr := reflect.New(val.Type()) |
||||||
|
ptr.Elem().Set(val) |
||||||
|
return ptr.Interface() |
||||||
|
} |
||||||
|
|
||||||
|
func (field *safeField) UnsafeGet(obj unsafe.Pointer) unsafe.Pointer { |
||||||
|
panic("does not support unsafe operation") |
||||||
|
} |
@ -0,0 +1,101 @@ |
|||||||
|
package reflect2 |
||||||
|
|
||||||
|
import ( |
||||||
|
"reflect" |
||||||
|
"unsafe" |
||||||
|
) |
||||||
|
|
||||||
|
type safeMapType struct { |
||||||
|
safeType |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *safeMapType) Key() Type { |
||||||
|
return type2.safeType.cfg.Type2(type2.Type.Key()) |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *safeMapType) MakeMap(cap int) interface{} { |
||||||
|
ptr := reflect.New(type2.Type) |
||||||
|
ptr.Elem().Set(reflect.MakeMap(type2.Type)) |
||||||
|
return ptr.Interface() |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *safeMapType) UnsafeMakeMap(cap int) unsafe.Pointer { |
||||||
|
panic("does not support unsafe operation") |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *safeMapType) SetIndex(obj interface{}, key interface{}, elem interface{}) { |
||||||
|
keyVal := reflect.ValueOf(key) |
||||||
|
elemVal := reflect.ValueOf(elem) |
||||||
|
val := reflect.ValueOf(obj) |
||||||
|
val.Elem().SetMapIndex(keyVal.Elem(), elemVal.Elem()) |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *safeMapType) UnsafeSetIndex(obj unsafe.Pointer, key unsafe.Pointer, elem unsafe.Pointer) { |
||||||
|
panic("does not support unsafe operation") |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *safeMapType) TryGetIndex(obj interface{}, key interface{}) (interface{}, bool) { |
||||||
|
keyVal := reflect.ValueOf(key) |
||||||
|
if key == nil { |
||||||
|
keyVal = reflect.New(type2.Type.Key()).Elem() |
||||||
|
} |
||||||
|
val := reflect.ValueOf(obj).MapIndex(keyVal) |
||||||
|
if !val.IsValid() { |
||||||
|
return nil, false |
||||||
|
} |
||||||
|
return val.Interface(), true |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *safeMapType) GetIndex(obj interface{}, key interface{}) interface{} { |
||||||
|
val := reflect.ValueOf(obj).Elem() |
||||||
|
keyVal := reflect.ValueOf(key).Elem() |
||||||
|
elemVal := val.MapIndex(keyVal) |
||||||
|
if !elemVal.IsValid() { |
||||||
|
ptr := reflect.New(reflect.PtrTo(val.Type().Elem())) |
||||||
|
return ptr.Elem().Interface() |
||||||
|
} |
||||||
|
ptr := reflect.New(elemVal.Type()) |
||||||
|
ptr.Elem().Set(elemVal) |
||||||
|
return ptr.Interface() |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *safeMapType) UnsafeGetIndex(obj unsafe.Pointer, key unsafe.Pointer) unsafe.Pointer { |
||||||
|
panic("does not support unsafe operation") |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *safeMapType) Iterate(obj interface{}) MapIterator { |
||||||
|
m := reflect.ValueOf(obj).Elem() |
||||||
|
return &safeMapIterator{ |
||||||
|
m: m, |
||||||
|
keys: m.MapKeys(), |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *safeMapType) UnsafeIterate(obj unsafe.Pointer) MapIterator { |
||||||
|
panic("does not support unsafe operation") |
||||||
|
} |
||||||
|
|
||||||
|
type safeMapIterator struct { |
||||||
|
i int |
||||||
|
m reflect.Value |
||||||
|
keys []reflect.Value |
||||||
|
} |
||||||
|
|
||||||
|
func (iter *safeMapIterator) HasNext() bool { |
||||||
|
return iter.i != len(iter.keys) |
||||||
|
} |
||||||
|
|
||||||
|
func (iter *safeMapIterator) Next() (interface{}, interface{}) { |
||||||
|
key := iter.keys[iter.i] |
||||||
|
elem := iter.m.MapIndex(key) |
||||||
|
iter.i += 1 |
||||||
|
keyPtr := reflect.New(key.Type()) |
||||||
|
keyPtr.Elem().Set(key) |
||||||
|
elemPtr := reflect.New(elem.Type()) |
||||||
|
elemPtr.Elem().Set(elem) |
||||||
|
return keyPtr.Interface(), elemPtr.Interface() |
||||||
|
} |
||||||
|
|
||||||
|
func (iter *safeMapIterator) UnsafeNext() (unsafe.Pointer, unsafe.Pointer) { |
||||||
|
panic("does not support unsafe operation") |
||||||
|
} |
@ -0,0 +1,92 @@ |
|||||||
|
package reflect2 |
||||||
|
|
||||||
|
import ( |
||||||
|
"reflect" |
||||||
|
"unsafe" |
||||||
|
) |
||||||
|
|
||||||
|
type safeSliceType struct { |
||||||
|
safeType |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *safeSliceType) SetIndex(obj interface{}, index int, value interface{}) { |
||||||
|
val := reflect.ValueOf(obj).Elem() |
||||||
|
elem := reflect.ValueOf(value).Elem() |
||||||
|
val.Index(index).Set(elem) |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *safeSliceType) UnsafeSetIndex(obj unsafe.Pointer, index int, value unsafe.Pointer) { |
||||||
|
panic("does not support unsafe operation") |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *safeSliceType) GetIndex(obj interface{}, index int) interface{} { |
||||||
|
val := reflect.ValueOf(obj).Elem() |
||||||
|
elem := val.Index(index) |
||||||
|
ptr := reflect.New(elem.Type()) |
||||||
|
ptr.Elem().Set(elem) |
||||||
|
return ptr.Interface() |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *safeSliceType) UnsafeGetIndex(obj unsafe.Pointer, index int) unsafe.Pointer { |
||||||
|
panic("does not support unsafe operation") |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *safeSliceType) MakeSlice(length int, cap int) interface{} { |
||||||
|
val := reflect.MakeSlice(type2.Type, length, cap) |
||||||
|
ptr := reflect.New(val.Type()) |
||||||
|
ptr.Elem().Set(val) |
||||||
|
return ptr.Interface() |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *safeSliceType) UnsafeMakeSlice(length int, cap int) unsafe.Pointer { |
||||||
|
panic("does not support unsafe operation") |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *safeSliceType) Grow(obj interface{}, newLength int) { |
||||||
|
oldCap := type2.Cap(obj) |
||||||
|
oldSlice := reflect.ValueOf(obj).Elem() |
||||||
|
delta := newLength - oldCap |
||||||
|
deltaVals := make([]reflect.Value, delta) |
||||||
|
newSlice := reflect.Append(oldSlice, deltaVals...) |
||||||
|
oldSlice.Set(newSlice) |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *safeSliceType) UnsafeGrow(ptr unsafe.Pointer, newLength int) { |
||||||
|
panic("does not support unsafe operation") |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *safeSliceType) Append(obj interface{}, elem interface{}) { |
||||||
|
val := reflect.ValueOf(obj).Elem() |
||||||
|
elemVal := reflect.ValueOf(elem).Elem() |
||||||
|
newVal := reflect.Append(val, elemVal) |
||||||
|
val.Set(newVal) |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *safeSliceType) UnsafeAppend(obj unsafe.Pointer, elem unsafe.Pointer) { |
||||||
|
panic("does not support unsafe operation") |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *safeSliceType) SetNil(obj interface{}) { |
||||||
|
val := reflect.ValueOf(obj).Elem() |
||||||
|
val.Set(reflect.Zero(val.Type())) |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *safeSliceType) UnsafeSetNil(ptr unsafe.Pointer) { |
||||||
|
panic("does not support unsafe operation") |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *safeSliceType) LengthOf(obj interface{}) int { |
||||||
|
return reflect.ValueOf(obj).Elem().Len() |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *safeSliceType) UnsafeLengthOf(ptr unsafe.Pointer) int { |
||||||
|
panic("does not support unsafe operation") |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *safeSliceType) Cap(obj interface{}) int { |
||||||
|
return reflect.ValueOf(obj).Elem().Cap() |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *safeSliceType) UnsafeCap(ptr unsafe.Pointer) int { |
||||||
|
panic("does not support unsafe operation") |
||||||
|
} |
@ -0,0 +1,29 @@ |
|||||||
|
package reflect2 |
||||||
|
|
||||||
|
type safeStructType struct { |
||||||
|
safeType |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *safeStructType) FieldByName(name string) StructField { |
||||||
|
field, found := type2.Type.FieldByName(name) |
||||||
|
if !found { |
||||||
|
panic("field " + name + " not found") |
||||||
|
} |
||||||
|
return &safeField{StructField: field} |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *safeStructType) Field(i int) StructField { |
||||||
|
return &safeField{StructField: type2.Type.Field(i)} |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *safeStructType) FieldByIndex(index []int) StructField { |
||||||
|
return &safeField{StructField: type2.Type.FieldByIndex(index)} |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *safeStructType) FieldByNameFunc(match func(string) bool) StructField { |
||||||
|
field, found := type2.Type.FieldByNameFunc(match) |
||||||
|
if !found { |
||||||
|
panic("field match condition not found in " + type2.Type.String()) |
||||||
|
} |
||||||
|
return &safeField{StructField: field} |
||||||
|
} |
@ -0,0 +1,78 @@ |
|||||||
|
package reflect2 |
||||||
|
|
||||||
|
import ( |
||||||
|
"reflect" |
||||||
|
"unsafe" |
||||||
|
) |
||||||
|
|
||||||
|
type safeType struct { |
||||||
|
reflect.Type |
||||||
|
cfg *frozenConfig |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *safeType) New() interface{} { |
||||||
|
return reflect.New(type2.Type).Interface() |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *safeType) UnsafeNew() unsafe.Pointer { |
||||||
|
panic("does not support unsafe operation") |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *safeType) Elem() Type { |
||||||
|
return type2.cfg.Type2(type2.Type.Elem()) |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *safeType) Type1() reflect.Type { |
||||||
|
return type2.Type |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *safeType) PackEFace(ptr unsafe.Pointer) interface{} { |
||||||
|
panic("does not support unsafe operation") |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *safeType) Implements(thatType Type) bool { |
||||||
|
return type2.Type.Implements(thatType.Type1()) |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *safeType) RType() uintptr { |
||||||
|
panic("does not support unsafe operation") |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *safeType) Indirect(obj interface{}) interface{} { |
||||||
|
return reflect.Indirect(reflect.ValueOf(obj)).Interface() |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *safeType) UnsafeIndirect(ptr unsafe.Pointer) interface{} { |
||||||
|
panic("does not support unsafe operation") |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *safeType) LikePtr() bool { |
||||||
|
panic("does not support unsafe operation") |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *safeType) IsNullable() bool { |
||||||
|
return IsNullable(type2.Kind()) |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *safeType) IsNil(obj interface{}) bool { |
||||||
|
if obj == nil { |
||||||
|
return true |
||||||
|
} |
||||||
|
return reflect.ValueOf(obj).Elem().IsNil() |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *safeType) UnsafeIsNil(ptr unsafe.Pointer) bool { |
||||||
|
panic("does not support unsafe operation") |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *safeType) Set(obj interface{}, val interface{}) { |
||||||
|
reflect.ValueOf(obj).Elem().Set(reflect.ValueOf(val).Elem()) |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *safeType) UnsafeSet(ptr unsafe.Pointer, val unsafe.Pointer) { |
||||||
|
panic("does not support unsafe operation") |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *safeType) AssignableTo(anotherType Type) bool { |
||||||
|
return type2.Type1().AssignableTo(anotherType.Type1()) |
||||||
|
} |
@ -0,0 +1,12 @@ |
|||||||
|
#!/usr/bin/env bash |
||||||
|
|
||||||
|
set -e |
||||||
|
echo "" > coverage.txt |
||||||
|
|
||||||
|
for d in $(go list ./... | grep -v vendor); do |
||||||
|
go test -coverprofile=profile.out -coverpkg=github.com/modern-go/reflect2 $d |
||||||
|
if [ -f profile.out ]; then |
||||||
|
cat profile.out >> coverage.txt |
||||||
|
rm profile.out |
||||||
|
fi |
||||||
|
done |
@ -0,0 +1,103 @@ |
|||||||
|
package reflect2 |
||||||
|
|
||||||
|
import ( |
||||||
|
"reflect" |
||||||
|
"runtime" |
||||||
|
"strings" |
||||||
|
"unsafe" |
||||||
|
) |
||||||
|
|
||||||
|
// typelinks1 for 1.5 ~ 1.6
|
||||||
|
//go:linkname typelinks1 reflect.typelinks
|
||||||
|
func typelinks1() [][]unsafe.Pointer |
||||||
|
|
||||||
|
// typelinks2 for 1.7 ~
|
||||||
|
//go:linkname typelinks2 reflect.typelinks
|
||||||
|
func typelinks2() (sections []unsafe.Pointer, offset [][]int32) |
||||||
|
|
||||||
|
var types = map[string]reflect.Type{} |
||||||
|
var packages = map[string]map[string]reflect.Type{} |
||||||
|
|
||||||
|
func init() { |
||||||
|
ver := runtime.Version() |
||||||
|
if ver == "go1.5" || strings.HasPrefix(ver, "go1.5.") { |
||||||
|
loadGo15Types() |
||||||
|
} else if ver == "go1.6" || strings.HasPrefix(ver, "go1.6.") { |
||||||
|
loadGo15Types() |
||||||
|
} else { |
||||||
|
loadGo17Types() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func loadGo15Types() { |
||||||
|
var obj interface{} = reflect.TypeOf(0) |
||||||
|
typePtrss := typelinks1() |
||||||
|
for _, typePtrs := range typePtrss { |
||||||
|
for _, typePtr := range typePtrs { |
||||||
|
(*emptyInterface)(unsafe.Pointer(&obj)).word = typePtr |
||||||
|
typ := obj.(reflect.Type) |
||||||
|
if typ.Kind() == reflect.Ptr && typ.Elem().Kind() == reflect.Struct { |
||||||
|
loadedType := typ.Elem() |
||||||
|
pkgTypes := packages[loadedType.PkgPath()] |
||||||
|
if pkgTypes == nil { |
||||||
|
pkgTypes = map[string]reflect.Type{} |
||||||
|
packages[loadedType.PkgPath()] = pkgTypes |
||||||
|
} |
||||||
|
types[loadedType.String()] = loadedType |
||||||
|
pkgTypes[loadedType.Name()] = loadedType |
||||||
|
} |
||||||
|
if typ.Kind() == reflect.Slice && typ.Elem().Kind() == reflect.Ptr && |
||||||
|
typ.Elem().Elem().Kind() == reflect.Struct { |
||||||
|
loadedType := typ.Elem().Elem() |
||||||
|
pkgTypes := packages[loadedType.PkgPath()] |
||||||
|
if pkgTypes == nil { |
||||||
|
pkgTypes = map[string]reflect.Type{} |
||||||
|
packages[loadedType.PkgPath()] = pkgTypes |
||||||
|
} |
||||||
|
types[loadedType.String()] = loadedType |
||||||
|
pkgTypes[loadedType.Name()] = loadedType |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func loadGo17Types() { |
||||||
|
var obj interface{} = reflect.TypeOf(0) |
||||||
|
sections, offset := typelinks2() |
||||||
|
for i, offs := range offset { |
||||||
|
rodata := sections[i] |
||||||
|
for _, off := range offs { |
||||||
|
(*emptyInterface)(unsafe.Pointer(&obj)).word = resolveTypeOff(unsafe.Pointer(rodata), off) |
||||||
|
typ := obj.(reflect.Type) |
||||||
|
if typ.Kind() == reflect.Ptr && typ.Elem().Kind() == reflect.Struct { |
||||||
|
loadedType := typ.Elem() |
||||||
|
pkgTypes := packages[loadedType.PkgPath()] |
||||||
|
if pkgTypes == nil { |
||||||
|
pkgTypes = map[string]reflect.Type{} |
||||||
|
packages[loadedType.PkgPath()] = pkgTypes |
||||||
|
} |
||||||
|
types[loadedType.String()] = loadedType |
||||||
|
pkgTypes[loadedType.Name()] = loadedType |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
type emptyInterface struct { |
||||||
|
typ unsafe.Pointer |
||||||
|
word unsafe.Pointer |
||||||
|
} |
||||||
|
|
||||||
|
// TypeByName return the type by its name, just like Class.forName in java
|
||||||
|
func TypeByName(typeName string) Type { |
||||||
|
return Type2(types[typeName]) |
||||||
|
} |
||||||
|
|
||||||
|
// TypeByPackageName return the type by its package and name
|
||||||
|
func TypeByPackageName(pkgPath string, name string) Type { |
||||||
|
pkgTypes := packages[pkgPath] |
||||||
|
if pkgTypes == nil { |
||||||
|
return nil |
||||||
|
} |
||||||
|
return Type2(pkgTypes[name]) |
||||||
|
} |
@ -0,0 +1,65 @@ |
|||||||
|
package reflect2 |
||||||
|
|
||||||
|
import ( |
||||||
|
"reflect" |
||||||
|
"unsafe" |
||||||
|
) |
||||||
|
|
||||||
|
type UnsafeArrayType struct { |
||||||
|
unsafeType |
||||||
|
elemRType unsafe.Pointer |
||||||
|
pElemRType unsafe.Pointer |
||||||
|
elemSize uintptr |
||||||
|
likePtr bool |
||||||
|
} |
||||||
|
|
||||||
|
func newUnsafeArrayType(cfg *frozenConfig, type1 reflect.Type) *UnsafeArrayType { |
||||||
|
return &UnsafeArrayType{ |
||||||
|
unsafeType: *newUnsafeType(cfg, type1), |
||||||
|
elemRType: unpackEFace(type1.Elem()).data, |
||||||
|
pElemRType: unpackEFace(reflect.PtrTo(type1.Elem())).data, |
||||||
|
elemSize: type1.Elem().Size(), |
||||||
|
likePtr: likePtrType(type1), |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafeArrayType) LikePtr() bool { |
||||||
|
return type2.likePtr |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafeArrayType) Indirect(obj interface{}) interface{} { |
||||||
|
objEFace := unpackEFace(obj) |
||||||
|
assertType("Type.Indirect argument 1", type2.ptrRType, objEFace.rtype) |
||||||
|
return type2.UnsafeIndirect(objEFace.data) |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafeArrayType) UnsafeIndirect(ptr unsafe.Pointer) interface{} { |
||||||
|
if type2.likePtr { |
||||||
|
return packEFace(type2.rtype, *(*unsafe.Pointer)(ptr)) |
||||||
|
} |
||||||
|
return packEFace(type2.rtype, ptr) |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafeArrayType) SetIndex(obj interface{}, index int, elem interface{}) { |
||||||
|
objEFace := unpackEFace(obj) |
||||||
|
assertType("ArrayType.SetIndex argument 1", type2.ptrRType, objEFace.rtype) |
||||||
|
elemEFace := unpackEFace(elem) |
||||||
|
assertType("ArrayType.SetIndex argument 3", type2.pElemRType, elemEFace.rtype) |
||||||
|
type2.UnsafeSetIndex(objEFace.data, index, elemEFace.data) |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafeArrayType) UnsafeSetIndex(obj unsafe.Pointer, index int, elem unsafe.Pointer) { |
||||||
|
elemPtr := arrayAt(obj, index, type2.elemSize, "i < s.Len") |
||||||
|
typedmemmove(type2.elemRType, elemPtr, elem) |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafeArrayType) GetIndex(obj interface{}, index int) interface{} { |
||||||
|
objEFace := unpackEFace(obj) |
||||||
|
assertType("ArrayType.GetIndex argument 1", type2.ptrRType, objEFace.rtype) |
||||||
|
elemPtr := type2.UnsafeGetIndex(objEFace.data, index) |
||||||
|
return packEFace(type2.pElemRType, elemPtr) |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafeArrayType) UnsafeGetIndex(obj unsafe.Pointer, index int) unsafe.Pointer { |
||||||
|
return arrayAt(obj, index, type2.elemSize, "i < s.Len") |
||||||
|
} |
@ -0,0 +1,59 @@ |
|||||||
|
package reflect2 |
||||||
|
|
||||||
|
import ( |
||||||
|
"reflect" |
||||||
|
"unsafe" |
||||||
|
) |
||||||
|
|
||||||
|
type eface struct { |
||||||
|
rtype unsafe.Pointer |
||||||
|
data unsafe.Pointer |
||||||
|
} |
||||||
|
|
||||||
|
func unpackEFace(obj interface{}) *eface { |
||||||
|
return (*eface)(unsafe.Pointer(&obj)) |
||||||
|
} |
||||||
|
|
||||||
|
func packEFace(rtype unsafe.Pointer, data unsafe.Pointer) interface{} { |
||||||
|
var i interface{} |
||||||
|
e := (*eface)(unsafe.Pointer(&i)) |
||||||
|
e.rtype = rtype |
||||||
|
e.data = data |
||||||
|
return i |
||||||
|
} |
||||||
|
|
||||||
|
type UnsafeEFaceType struct { |
||||||
|
unsafeType |
||||||
|
} |
||||||
|
|
||||||
|
func newUnsafeEFaceType(cfg *frozenConfig, type1 reflect.Type) *UnsafeEFaceType { |
||||||
|
return &UnsafeEFaceType{ |
||||||
|
unsafeType: *newUnsafeType(cfg, type1), |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafeEFaceType) IsNil(obj interface{}) bool { |
||||||
|
if obj == nil { |
||||||
|
return true |
||||||
|
} |
||||||
|
objEFace := unpackEFace(obj) |
||||||
|
assertType("Type.IsNil argument 1", type2.ptrRType, objEFace.rtype) |
||||||
|
return type2.UnsafeIsNil(objEFace.data) |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafeEFaceType) UnsafeIsNil(ptr unsafe.Pointer) bool { |
||||||
|
if ptr == nil { |
||||||
|
return true |
||||||
|
} |
||||||
|
return unpackEFace(*(*interface{})(ptr)).data == nil |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafeEFaceType) Indirect(obj interface{}) interface{} { |
||||||
|
objEFace := unpackEFace(obj) |
||||||
|
assertType("Type.Indirect argument 1", type2.ptrRType, objEFace.rtype) |
||||||
|
return type2.UnsafeIndirect(objEFace.data) |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafeEFaceType) UnsafeIndirect(ptr unsafe.Pointer) interface{} { |
||||||
|
return *(*interface{})(ptr) |
||||||
|
} |
@ -0,0 +1,74 @@ |
|||||||
|
package reflect2 |
||||||
|
|
||||||
|
import ( |
||||||
|
"reflect" |
||||||
|
"unsafe" |
||||||
|
) |
||||||
|
|
||||||
|
type UnsafeStructField struct { |
||||||
|
reflect.StructField |
||||||
|
structType *UnsafeStructType |
||||||
|
rtype unsafe.Pointer |
||||||
|
ptrRType unsafe.Pointer |
||||||
|
} |
||||||
|
|
||||||
|
func newUnsafeStructField(structType *UnsafeStructType, structField reflect.StructField) *UnsafeStructField { |
||||||
|
return &UnsafeStructField{ |
||||||
|
StructField: structField, |
||||||
|
rtype: unpackEFace(structField.Type).data, |
||||||
|
ptrRType: unpackEFace(reflect.PtrTo(structField.Type)).data, |
||||||
|
structType: structType, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func (field *UnsafeStructField) Offset() uintptr { |
||||||
|
return field.StructField.Offset |
||||||
|
} |
||||||
|
|
||||||
|
func (field *UnsafeStructField) Name() string { |
||||||
|
return field.StructField.Name |
||||||
|
} |
||||||
|
|
||||||
|
func (field *UnsafeStructField) PkgPath() string { |
||||||
|
return field.StructField.PkgPath |
||||||
|
} |
||||||
|
|
||||||
|
func (field *UnsafeStructField) Type() Type { |
||||||
|
return field.structType.cfg.Type2(field.StructField.Type) |
||||||
|
} |
||||||
|
|
||||||
|
func (field *UnsafeStructField) Tag() reflect.StructTag { |
||||||
|
return field.StructField.Tag |
||||||
|
} |
||||||
|
|
||||||
|
func (field *UnsafeStructField) Index() []int { |
||||||
|
return field.StructField.Index |
||||||
|
} |
||||||
|
|
||||||
|
func (field *UnsafeStructField) Anonymous() bool { |
||||||
|
return field.StructField.Anonymous |
||||||
|
} |
||||||
|
|
||||||
|
func (field *UnsafeStructField) Set(obj interface{}, value interface{}) { |
||||||
|
objEFace := unpackEFace(obj) |
||||||
|
assertType("StructField.SetIndex argument 1", field.structType.ptrRType, objEFace.rtype) |
||||||
|
valueEFace := unpackEFace(value) |
||||||
|
assertType("StructField.SetIndex argument 2", field.ptrRType, valueEFace.rtype) |
||||||
|
field.UnsafeSet(objEFace.data, valueEFace.data) |
||||||
|
} |
||||||
|
|
||||||
|
func (field *UnsafeStructField) UnsafeSet(obj unsafe.Pointer, value unsafe.Pointer) { |
||||||
|
fieldPtr := add(obj, field.StructField.Offset, "same as non-reflect &v.field") |
||||||
|
typedmemmove(field.rtype, fieldPtr, value) |
||||||
|
} |
||||||
|
|
||||||
|
func (field *UnsafeStructField) Get(obj interface{}) interface{} { |
||||||
|
objEFace := unpackEFace(obj) |
||||||
|
assertType("StructField.GetIndex argument 1", field.structType.ptrRType, objEFace.rtype) |
||||||
|
value := field.UnsafeGet(objEFace.data) |
||||||
|
return packEFace(field.ptrRType, value) |
||||||
|
} |
||||||
|
|
||||||
|
func (field *UnsafeStructField) UnsafeGet(obj unsafe.Pointer) unsafe.Pointer { |
||||||
|
return add(obj, field.StructField.Offset, "same as non-reflect &v.field") |
||||||
|
} |
@ -0,0 +1,64 @@ |
|||||||
|
package reflect2 |
||||||
|
|
||||||
|
import ( |
||||||
|
"reflect" |
||||||
|
"unsafe" |
||||||
|
) |
||||||
|
|
||||||
|
type iface struct { |
||||||
|
itab *itab |
||||||
|
data unsafe.Pointer |
||||||
|
} |
||||||
|
|
||||||
|
type itab struct { |
||||||
|
ignore unsafe.Pointer |
||||||
|
rtype unsafe.Pointer |
||||||
|
} |
||||||
|
|
||||||
|
func IFaceToEFace(ptr unsafe.Pointer) interface{} { |
||||||
|
iface := (*iface)(ptr) |
||||||
|
if iface.itab == nil { |
||||||
|
return nil |
||||||
|
} |
||||||
|
return packEFace(iface.itab.rtype, iface.data) |
||||||
|
} |
||||||
|
|
||||||
|
type UnsafeIFaceType struct { |
||||||
|
unsafeType |
||||||
|
} |
||||||
|
|
||||||
|
func newUnsafeIFaceType(cfg *frozenConfig, type1 reflect.Type) *UnsafeIFaceType { |
||||||
|
return &UnsafeIFaceType{ |
||||||
|
unsafeType: *newUnsafeType(cfg, type1), |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafeIFaceType) Indirect(obj interface{}) interface{} { |
||||||
|
objEFace := unpackEFace(obj) |
||||||
|
assertType("Type.Indirect argument 1", type2.ptrRType, objEFace.rtype) |
||||||
|
return type2.UnsafeIndirect(objEFace.data) |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafeIFaceType) UnsafeIndirect(ptr unsafe.Pointer) interface{} { |
||||||
|
return IFaceToEFace(ptr) |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafeIFaceType) IsNil(obj interface{}) bool { |
||||||
|
if obj == nil { |
||||||
|
return true |
||||||
|
} |
||||||
|
objEFace := unpackEFace(obj) |
||||||
|
assertType("Type.IsNil argument 1", type2.ptrRType, objEFace.rtype) |
||||||
|
return type2.UnsafeIsNil(objEFace.data) |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafeIFaceType) UnsafeIsNil(ptr unsafe.Pointer) bool { |
||||||
|
if ptr == nil { |
||||||
|
return true |
||||||
|
} |
||||||
|
iface := (*iface)(ptr) |
||||||
|
if iface.itab == nil { |
||||||
|
return true |
||||||
|
} |
||||||
|
return false |
||||||
|
} |
@ -0,0 +1,70 @@ |
|||||||
|
package reflect2 |
||||||
|
|
||||||
|
import "unsafe" |
||||||
|
|
||||||
|
//go:linkname unsafe_New reflect.unsafe_New
|
||||||
|
func unsafe_New(rtype unsafe.Pointer) unsafe.Pointer |
||||||
|
|
||||||
|
//go:linkname typedmemmove reflect.typedmemmove
|
||||||
|
func typedmemmove(rtype unsafe.Pointer, dst, src unsafe.Pointer) |
||||||
|
|
||||||
|
//go:linkname unsafe_NewArray reflect.unsafe_NewArray
|
||||||
|
func unsafe_NewArray(rtype unsafe.Pointer, length int) unsafe.Pointer |
||||||
|
|
||||||
|
// typedslicecopy copies a slice of elemType values from src to dst,
|
||||||
|
// returning the number of elements copied.
|
||||||
|
//go:linkname typedslicecopy reflect.typedslicecopy
|
||||||
|
//go:noescape
|
||||||
|
func typedslicecopy(elemType unsafe.Pointer, dst, src sliceHeader) int |
||||||
|
|
||||||
|
//go:linkname mapassign reflect.mapassign
|
||||||
|
//go:noescape
|
||||||
|
func mapassign(rtype unsafe.Pointer, m unsafe.Pointer, key, val unsafe.Pointer) |
||||||
|
|
||||||
|
//go:linkname mapaccess reflect.mapaccess
|
||||||
|
//go:noescape
|
||||||
|
func mapaccess(rtype unsafe.Pointer, m unsafe.Pointer, key unsafe.Pointer) (val unsafe.Pointer) |
||||||
|
|
||||||
|
// m escapes into the return value, but the caller of mapiterinit
|
||||||
|
// doesn't let the return value escape.
|
||||||
|
//go:noescape
|
||||||
|
//go:linkname mapiterinit reflect.mapiterinit
|
||||||
|
func mapiterinit(rtype unsafe.Pointer, m unsafe.Pointer) *hiter |
||||||
|
|
||||||
|
//go:noescape
|
||||||
|
//go:linkname mapiternext reflect.mapiternext
|
||||||
|
func mapiternext(it *hiter) |
||||||
|
|
||||||
|
//go:linkname ifaceE2I reflect.ifaceE2I
|
||||||
|
func ifaceE2I(rtype unsafe.Pointer, src interface{}, dst unsafe.Pointer) |
||||||
|
|
||||||
|
// A hash iteration structure.
|
||||||
|
// If you modify hiter, also change cmd/internal/gc/reflect.go to indicate
|
||||||
|
// the layout of this structure.
|
||||||
|
type hiter struct { |
||||||
|
key unsafe.Pointer // Must be in first position. Write nil to indicate iteration end (see cmd/internal/gc/range.go).
|
||||||
|
value unsafe.Pointer // Must be in second position (see cmd/internal/gc/range.go).
|
||||||
|
// rest fields are ignored
|
||||||
|
} |
||||||
|
|
||||||
|
// add returns p+x.
|
||||||
|
//
|
||||||
|
// The whySafe string is ignored, so that the function still inlines
|
||||||
|
// as efficiently as p+x, but all call sites should use the string to
|
||||||
|
// record why the addition is safe, which is to say why the addition
|
||||||
|
// does not cause x to advance to the very end of p's allocation
|
||||||
|
// and therefore point incorrectly at the next block in memory.
|
||||||
|
func add(p unsafe.Pointer, x uintptr, whySafe string) unsafe.Pointer { |
||||||
|
return unsafe.Pointer(uintptr(p) + x) |
||||||
|
} |
||||||
|
|
||||||
|
// arrayAt returns the i-th element of p,
|
||||||
|
// an array whose elements are eltSize bytes wide.
|
||||||
|
// The array pointed at by p must have at least i+1 elements:
|
||||||
|
// it is invalid (but impossible to check here) to pass i >= len,
|
||||||
|
// because then the result will point outside the array.
|
||||||
|
// whySafe must explain why i < len. (Passing "i < len" is fine;
|
||||||
|
// the benefit is to surface this assumption at the call site.)
|
||||||
|
func arrayAt(p unsafe.Pointer, i int, eltSize uintptr, whySafe string) unsafe.Pointer { |
||||||
|
return add(p, uintptr(i)*eltSize, "i < len") |
||||||
|
} |
@ -0,0 +1,138 @@ |
|||||||
|
package reflect2 |
||||||
|
|
||||||
|
import ( |
||||||
|
"reflect" |
||||||
|
"unsafe" |
||||||
|
) |
||||||
|
|
||||||
|
type UnsafeMapType struct { |
||||||
|
unsafeType |
||||||
|
pKeyRType unsafe.Pointer |
||||||
|
pElemRType unsafe.Pointer |
||||||
|
} |
||||||
|
|
||||||
|
func newUnsafeMapType(cfg *frozenConfig, type1 reflect.Type) MapType { |
||||||
|
return &UnsafeMapType{ |
||||||
|
unsafeType: *newUnsafeType(cfg, type1), |
||||||
|
pKeyRType: unpackEFace(reflect.PtrTo(type1.Key())).data, |
||||||
|
pElemRType: unpackEFace(reflect.PtrTo(type1.Elem())).data, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafeMapType) IsNil(obj interface{}) bool { |
||||||
|
if obj == nil { |
||||||
|
return true |
||||||
|
} |
||||||
|
objEFace := unpackEFace(obj) |
||||||
|
assertType("Type.IsNil argument 1", type2.ptrRType, objEFace.rtype) |
||||||
|
return type2.UnsafeIsNil(objEFace.data) |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafeMapType) UnsafeIsNil(ptr unsafe.Pointer) bool { |
||||||
|
if ptr == nil { |
||||||
|
return true |
||||||
|
} |
||||||
|
return *(*unsafe.Pointer)(ptr) == nil |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafeMapType) LikePtr() bool { |
||||||
|
return true |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafeMapType) Indirect(obj interface{}) interface{} { |
||||||
|
objEFace := unpackEFace(obj) |
||||||
|
assertType("MapType.Indirect argument 1", type2.ptrRType, objEFace.rtype) |
||||||
|
return type2.UnsafeIndirect(objEFace.data) |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafeMapType) UnsafeIndirect(ptr unsafe.Pointer) interface{} { |
||||||
|
return packEFace(type2.rtype, *(*unsafe.Pointer)(ptr)) |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafeMapType) Key() Type { |
||||||
|
return type2.cfg.Type2(type2.Type.Key()) |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafeMapType) MakeMap(cap int) interface{} { |
||||||
|
return packEFace(type2.ptrRType, type2.UnsafeMakeMap(cap)) |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafeMapType) UnsafeMakeMap(cap int) unsafe.Pointer { |
||||||
|
m := makeMapWithSize(type2.rtype, cap) |
||||||
|
return unsafe.Pointer(&m) |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafeMapType) SetIndex(obj interface{}, key interface{}, elem interface{}) { |
||||||
|
objEFace := unpackEFace(obj) |
||||||
|
assertType("MapType.SetIndex argument 1", type2.ptrRType, objEFace.rtype) |
||||||
|
keyEFace := unpackEFace(key) |
||||||
|
assertType("MapType.SetIndex argument 2", type2.pKeyRType, keyEFace.rtype) |
||||||
|
elemEFace := unpackEFace(elem) |
||||||
|
assertType("MapType.SetIndex argument 3", type2.pElemRType, elemEFace.rtype) |
||||||
|
type2.UnsafeSetIndex(objEFace.data, keyEFace.data, elemEFace.data) |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafeMapType) UnsafeSetIndex(obj unsafe.Pointer, key unsafe.Pointer, elem unsafe.Pointer) { |
||||||
|
mapassign(type2.rtype, *(*unsafe.Pointer)(obj), key, elem) |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafeMapType) TryGetIndex(obj interface{}, key interface{}) (interface{}, bool) { |
||||||
|
objEFace := unpackEFace(obj) |
||||||
|
assertType("MapType.TryGetIndex argument 1", type2.ptrRType, objEFace.rtype) |
||||||
|
keyEFace := unpackEFace(key) |
||||||
|
assertType("MapType.TryGetIndex argument 2", type2.pKeyRType, keyEFace.rtype) |
||||||
|
elemPtr := type2.UnsafeGetIndex(objEFace.data, keyEFace.data) |
||||||
|
if elemPtr == nil { |
||||||
|
return nil, false |
||||||
|
} |
||||||
|
return packEFace(type2.pElemRType, elemPtr), true |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafeMapType) GetIndex(obj interface{}, key interface{}) interface{} { |
||||||
|
objEFace := unpackEFace(obj) |
||||||
|
assertType("MapType.GetIndex argument 1", type2.ptrRType, objEFace.rtype) |
||||||
|
keyEFace := unpackEFace(key) |
||||||
|
assertType("MapType.GetIndex argument 2", type2.pKeyRType, keyEFace.rtype) |
||||||
|
elemPtr := type2.UnsafeGetIndex(objEFace.data, keyEFace.data) |
||||||
|
return packEFace(type2.pElemRType, elemPtr) |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafeMapType) UnsafeGetIndex(obj unsafe.Pointer, key unsafe.Pointer) unsafe.Pointer { |
||||||
|
return mapaccess(type2.rtype, *(*unsafe.Pointer)(obj), key) |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafeMapType) Iterate(obj interface{}) MapIterator { |
||||||
|
objEFace := unpackEFace(obj) |
||||||
|
assertType("MapType.Iterate argument 1", type2.ptrRType, objEFace.rtype) |
||||||
|
return type2.UnsafeIterate(objEFace.data) |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafeMapType) UnsafeIterate(obj unsafe.Pointer) MapIterator { |
||||||
|
return &UnsafeMapIterator{ |
||||||
|
hiter: mapiterinit(type2.rtype, *(*unsafe.Pointer)(obj)), |
||||||
|
pKeyRType: type2.pKeyRType, |
||||||
|
pElemRType: type2.pElemRType, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
type UnsafeMapIterator struct { |
||||||
|
*hiter |
||||||
|
pKeyRType unsafe.Pointer |
||||||
|
pElemRType unsafe.Pointer |
||||||
|
} |
||||||
|
|
||||||
|
func (iter *UnsafeMapIterator) HasNext() bool { |
||||||
|
return iter.key != nil |
||||||
|
} |
||||||
|
|
||||||
|
func (iter *UnsafeMapIterator) Next() (interface{}, interface{}) { |
||||||
|
key, elem := iter.UnsafeNext() |
||||||
|
return packEFace(iter.pKeyRType, key), packEFace(iter.pElemRType, elem) |
||||||
|
} |
||||||
|
|
||||||
|
func (iter *UnsafeMapIterator) UnsafeNext() (unsafe.Pointer, unsafe.Pointer) { |
||||||
|
key := iter.key |
||||||
|
elem := iter.value |
||||||
|
mapiternext(iter.hiter) |
||||||
|
return key, elem |
||||||
|
} |
@ -0,0 +1,46 @@ |
|||||||
|
package reflect2 |
||||||
|
|
||||||
|
import ( |
||||||
|
"reflect" |
||||||
|
"unsafe" |
||||||
|
) |
||||||
|
|
||||||
|
type UnsafePtrType struct { |
||||||
|
unsafeType |
||||||
|
} |
||||||
|
|
||||||
|
func newUnsafePtrType(cfg *frozenConfig, type1 reflect.Type) *UnsafePtrType { |
||||||
|
return &UnsafePtrType{ |
||||||
|
unsafeType: *newUnsafeType(cfg, type1), |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafePtrType) IsNil(obj interface{}) bool { |
||||||
|
if obj == nil { |
||||||
|
return true |
||||||
|
} |
||||||
|
objEFace := unpackEFace(obj) |
||||||
|
assertType("Type.IsNil argument 1", type2.ptrRType, objEFace.rtype) |
||||||
|
return type2.UnsafeIsNil(objEFace.data) |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafePtrType) UnsafeIsNil(ptr unsafe.Pointer) bool { |
||||||
|
if ptr == nil { |
||||||
|
return true |
||||||
|
} |
||||||
|
return *(*unsafe.Pointer)(ptr) == nil |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafePtrType) LikePtr() bool { |
||||||
|
return true |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafePtrType) Indirect(obj interface{}) interface{} { |
||||||
|
objEFace := unpackEFace(obj) |
||||||
|
assertType("Type.Indirect argument 1", type2.ptrRType, objEFace.rtype) |
||||||
|
return type2.UnsafeIndirect(objEFace.data) |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafePtrType) UnsafeIndirect(ptr unsafe.Pointer) interface{} { |
||||||
|
return packEFace(type2.rtype, *(*unsafe.Pointer)(ptr)) |
||||||
|
} |
@ -0,0 +1,177 @@ |
|||||||
|
package reflect2 |
||||||
|
|
||||||
|
import ( |
||||||
|
"reflect" |
||||||
|
"unsafe" |
||||||
|
) |
||||||
|
|
||||||
|
// sliceHeader is a safe version of SliceHeader used within this package.
|
||||||
|
type sliceHeader struct { |
||||||
|
Data unsafe.Pointer |
||||||
|
Len int |
||||||
|
Cap int |
||||||
|
} |
||||||
|
|
||||||
|
type UnsafeSliceType struct { |
||||||
|
unsafeType |
||||||
|
elemRType unsafe.Pointer |
||||||
|
pElemRType unsafe.Pointer |
||||||
|
elemSize uintptr |
||||||
|
} |
||||||
|
|
||||||
|
func newUnsafeSliceType(cfg *frozenConfig, type1 reflect.Type) SliceType { |
||||||
|
elemType := type1.Elem() |
||||||
|
return &UnsafeSliceType{ |
||||||
|
unsafeType: *newUnsafeType(cfg, type1), |
||||||
|
pElemRType: unpackEFace(reflect.PtrTo(elemType)).data, |
||||||
|
elemRType: unpackEFace(elemType).data, |
||||||
|
elemSize: elemType.Size(), |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafeSliceType) Set(obj interface{}, val interface{}) { |
||||||
|
objEFace := unpackEFace(obj) |
||||||
|
assertType("Type.Set argument 1", type2.ptrRType, objEFace.rtype) |
||||||
|
valEFace := unpackEFace(val) |
||||||
|
assertType("Type.Set argument 2", type2.ptrRType, valEFace.rtype) |
||||||
|
type2.UnsafeSet(objEFace.data, valEFace.data) |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafeSliceType) UnsafeSet(ptr unsafe.Pointer, val unsafe.Pointer) { |
||||||
|
*(*sliceHeader)(ptr) = *(*sliceHeader)(val) |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafeSliceType) IsNil(obj interface{}) bool { |
||||||
|
if obj == nil { |
||||||
|
return true |
||||||
|
} |
||||||
|
objEFace := unpackEFace(obj) |
||||||
|
assertType("Type.IsNil argument 1", type2.ptrRType, objEFace.rtype) |
||||||
|
return type2.UnsafeIsNil(objEFace.data) |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafeSliceType) UnsafeIsNil(ptr unsafe.Pointer) bool { |
||||||
|
if ptr == nil { |
||||||
|
return true |
||||||
|
} |
||||||
|
return (*sliceHeader)(ptr).Data == nil |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafeSliceType) SetNil(obj interface{}) { |
||||||
|
objEFace := unpackEFace(obj) |
||||||
|
assertType("SliceType.SetNil argument 1", type2.ptrRType, objEFace.rtype) |
||||||
|
type2.UnsafeSetNil(objEFace.data) |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafeSliceType) UnsafeSetNil(ptr unsafe.Pointer) { |
||||||
|
header := (*sliceHeader)(ptr) |
||||||
|
header.Len = 0 |
||||||
|
header.Cap = 0 |
||||||
|
header.Data = nil |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafeSliceType) MakeSlice(length int, cap int) interface{} { |
||||||
|
return packEFace(type2.ptrRType, type2.UnsafeMakeSlice(length, cap)) |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafeSliceType) UnsafeMakeSlice(length int, cap int) unsafe.Pointer { |
||||||
|
header := &sliceHeader{unsafe_NewArray(type2.elemRType, cap), length, cap} |
||||||
|
return unsafe.Pointer(header) |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafeSliceType) LengthOf(obj interface{}) int { |
||||||
|
objEFace := unpackEFace(obj) |
||||||
|
assertType("SliceType.Len argument 1", type2.ptrRType, objEFace.rtype) |
||||||
|
return type2.UnsafeLengthOf(objEFace.data) |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafeSliceType) UnsafeLengthOf(obj unsafe.Pointer) int { |
||||||
|
header := (*sliceHeader)(obj) |
||||||
|
return header.Len |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafeSliceType) SetIndex(obj interface{}, index int, elem interface{}) { |
||||||
|
objEFace := unpackEFace(obj) |
||||||
|
assertType("SliceType.SetIndex argument 1", type2.ptrRType, objEFace.rtype) |
||||||
|
elemEFace := unpackEFace(elem) |
||||||
|
assertType("SliceType.SetIndex argument 3", type2.pElemRType, elemEFace.rtype) |
||||||
|
type2.UnsafeSetIndex(objEFace.data, index, elemEFace.data) |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafeSliceType) UnsafeSetIndex(obj unsafe.Pointer, index int, elem unsafe.Pointer) { |
||||||
|
header := (*sliceHeader)(obj) |
||||||
|
elemPtr := arrayAt(header.Data, index, type2.elemSize, "i < s.Len") |
||||||
|
typedmemmove(type2.elemRType, elemPtr, elem) |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafeSliceType) GetIndex(obj interface{}, index int) interface{} { |
||||||
|
objEFace := unpackEFace(obj) |
||||||
|
assertType("SliceType.GetIndex argument 1", type2.ptrRType, objEFace.rtype) |
||||||
|
elemPtr := type2.UnsafeGetIndex(objEFace.data, index) |
||||||
|
return packEFace(type2.pElemRType, elemPtr) |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafeSliceType) UnsafeGetIndex(obj unsafe.Pointer, index int) unsafe.Pointer { |
||||||
|
header := (*sliceHeader)(obj) |
||||||
|
return arrayAt(header.Data, index, type2.elemSize, "i < s.Len") |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafeSliceType) Append(obj interface{}, elem interface{}) { |
||||||
|
objEFace := unpackEFace(obj) |
||||||
|
assertType("SliceType.Append argument 1", type2.ptrRType, objEFace.rtype) |
||||||
|
elemEFace := unpackEFace(elem) |
||||||
|
assertType("SliceType.Append argument 2", type2.pElemRType, elemEFace.rtype) |
||||||
|
type2.UnsafeAppend(objEFace.data, elemEFace.data) |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafeSliceType) UnsafeAppend(obj unsafe.Pointer, elem unsafe.Pointer) { |
||||||
|
header := (*sliceHeader)(obj) |
||||||
|
oldLen := header.Len |
||||||
|
type2.UnsafeGrow(obj, oldLen+1) |
||||||
|
type2.UnsafeSetIndex(obj, oldLen, elem) |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafeSliceType) Cap(obj interface{}) int { |
||||||
|
objEFace := unpackEFace(obj) |
||||||
|
assertType("SliceType.Cap argument 1", type2.ptrRType, objEFace.rtype) |
||||||
|
return type2.UnsafeCap(objEFace.data) |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafeSliceType) UnsafeCap(ptr unsafe.Pointer) int { |
||||||
|
return (*sliceHeader)(ptr).Cap |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafeSliceType) Grow(obj interface{}, newLength int) { |
||||||
|
objEFace := unpackEFace(obj) |
||||||
|
assertType("SliceType.Grow argument 1", type2.ptrRType, objEFace.rtype) |
||||||
|
type2.UnsafeGrow(objEFace.data, newLength) |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafeSliceType) UnsafeGrow(obj unsafe.Pointer, newLength int) { |
||||||
|
header := (*sliceHeader)(obj) |
||||||
|
if newLength <= header.Cap { |
||||||
|
header.Len = newLength |
||||||
|
return |
||||||
|
} |
||||||
|
newCap := calcNewCap(header.Cap, newLength) |
||||||
|
newHeader := (*sliceHeader)(type2.UnsafeMakeSlice(header.Len, newCap)) |
||||||
|
typedslicecopy(type2.elemRType, *newHeader, *header) |
||||||
|
header.Data = newHeader.Data |
||||||
|
header.Cap = newHeader.Cap |
||||||
|
header.Len = newLength |
||||||
|
} |
||||||
|
|
||||||
|
func calcNewCap(cap int, expectedCap int) int { |
||||||
|
if cap == 0 { |
||||||
|
cap = expectedCap |
||||||
|
} else { |
||||||
|
for cap < expectedCap { |
||||||
|
if cap < 1024 { |
||||||
|
cap += cap |
||||||
|
} else { |
||||||
|
cap += cap / 4 |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return cap |
||||||
|
} |
@ -0,0 +1,59 @@ |
|||||||
|
package reflect2 |
||||||
|
|
||||||
|
import ( |
||||||
|
"reflect" |
||||||
|
"unsafe" |
||||||
|
) |
||||||
|
|
||||||
|
type UnsafeStructType struct { |
||||||
|
unsafeType |
||||||
|
likePtr bool |
||||||
|
} |
||||||
|
|
||||||
|
func newUnsafeStructType(cfg *frozenConfig, type1 reflect.Type) *UnsafeStructType { |
||||||
|
return &UnsafeStructType{ |
||||||
|
unsafeType: *newUnsafeType(cfg, type1), |
||||||
|
likePtr: likePtrType(type1), |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafeStructType) LikePtr() bool { |
||||||
|
return type2.likePtr |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafeStructType) Indirect(obj interface{}) interface{} { |
||||||
|
objEFace := unpackEFace(obj) |
||||||
|
assertType("Type.Indirect argument 1", type2.ptrRType, objEFace.rtype) |
||||||
|
return type2.UnsafeIndirect(objEFace.data) |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafeStructType) UnsafeIndirect(ptr unsafe.Pointer) interface{} { |
||||||
|
if type2.likePtr { |
||||||
|
return packEFace(type2.rtype, *(*unsafe.Pointer)(ptr)) |
||||||
|
} |
||||||
|
return packEFace(type2.rtype, ptr) |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafeStructType) FieldByName(name string) StructField { |
||||||
|
structField, found := type2.Type.FieldByName(name) |
||||||
|
if !found { |
||||||
|
return nil |
||||||
|
} |
||||||
|
return newUnsafeStructField(type2, structField) |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafeStructType) Field(i int) StructField { |
||||||
|
return newUnsafeStructField(type2, type2.Type.Field(i)) |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafeStructType) FieldByIndex(index []int) StructField { |
||||||
|
return newUnsafeStructField(type2, type2.Type.FieldByIndex(index)) |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *UnsafeStructType) FieldByNameFunc(match func(string) bool) StructField { |
||||||
|
structField, found := type2.Type.FieldByNameFunc(match) |
||||||
|
if !found { |
||||||
|
panic("field match condition not found in " + type2.Type.String()) |
||||||
|
} |
||||||
|
return newUnsafeStructField(type2, structField) |
||||||
|
} |
@ -0,0 +1,85 @@ |
|||||||
|
package reflect2 |
||||||
|
|
||||||
|
import ( |
||||||
|
"reflect" |
||||||
|
"unsafe" |
||||||
|
) |
||||||
|
|
||||||
|
type unsafeType struct { |
||||||
|
safeType |
||||||
|
rtype unsafe.Pointer |
||||||
|
ptrRType unsafe.Pointer |
||||||
|
} |
||||||
|
|
||||||
|
func newUnsafeType(cfg *frozenConfig, type1 reflect.Type) *unsafeType { |
||||||
|
return &unsafeType{ |
||||||
|
safeType: safeType{ |
||||||
|
Type: type1, |
||||||
|
cfg: cfg, |
||||||
|
}, |
||||||
|
rtype: unpackEFace(type1).data, |
||||||
|
ptrRType: unpackEFace(reflect.PtrTo(type1)).data, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *unsafeType) Set(obj interface{}, val interface{}) { |
||||||
|
objEFace := unpackEFace(obj) |
||||||
|
assertType("Type.Set argument 1", type2.ptrRType, objEFace.rtype) |
||||||
|
valEFace := unpackEFace(val) |
||||||
|
assertType("Type.Set argument 2", type2.ptrRType, valEFace.rtype) |
||||||
|
type2.UnsafeSet(objEFace.data, valEFace.data) |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *unsafeType) UnsafeSet(ptr unsafe.Pointer, val unsafe.Pointer) { |
||||||
|
typedmemmove(type2.rtype, ptr, val) |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *unsafeType) IsNil(obj interface{}) bool { |
||||||
|
objEFace := unpackEFace(obj) |
||||||
|
assertType("Type.IsNil argument 1", type2.ptrRType, objEFace.rtype) |
||||||
|
return type2.UnsafeIsNil(objEFace.data) |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *unsafeType) UnsafeIsNil(ptr unsafe.Pointer) bool { |
||||||
|
return ptr == nil |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *unsafeType) UnsafeNew() unsafe.Pointer { |
||||||
|
return unsafe_New(type2.rtype) |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *unsafeType) New() interface{} { |
||||||
|
return packEFace(type2.ptrRType, type2.UnsafeNew()) |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *unsafeType) PackEFace(ptr unsafe.Pointer) interface{} { |
||||||
|
return packEFace(type2.ptrRType, ptr) |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *unsafeType) RType() uintptr { |
||||||
|
return uintptr(type2.rtype) |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *unsafeType) Indirect(obj interface{}) interface{} { |
||||||
|
objEFace := unpackEFace(obj) |
||||||
|
assertType("Type.Indirect argument 1", type2.ptrRType, objEFace.rtype) |
||||||
|
return type2.UnsafeIndirect(objEFace.data) |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *unsafeType) UnsafeIndirect(obj unsafe.Pointer) interface{} { |
||||||
|
return packEFace(type2.rtype, obj) |
||||||
|
} |
||||||
|
|
||||||
|
func (type2 *unsafeType) LikePtr() bool { |
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
func assertType(where string, expectRType unsafe.Pointer, actualRType unsafe.Pointer) { |
||||||
|
if expectRType != actualRType { |
||||||
|
expectType := reflect.TypeOf(0) |
||||||
|
(*iface)(unsafe.Pointer(&expectType)).data = expectRType |
||||||
|
actualType := reflect.TypeOf(0) |
||||||
|
(*iface)(unsafe.Pointer(&actualType)).data = actualRType |
||||||
|
panic(where + ": expect " + expectType.String() + ", actual " + actualType.String()) |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue