json更新
This commit is contained in:
parent
f5e2b3b76f
commit
3a82defb40
@ -5,7 +5,6 @@ import (
|
||||
"dt_automate/conn"
|
||||
"dt_automate/tool"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/url"
|
||||
"strconv"
|
||||
@ -56,18 +55,15 @@ func Fw_event(cookieStr string) {
|
||||
"referer": "https://11.2.68.146/wnm/frame/index.php",
|
||||
"cookie": cookieStr,
|
||||
}
|
||||
datas := conn.DT_POST("https://11.2.68.146/wnm/get.j", header, bytes.NewBufferString(values.Encode()))["NTOP"].(map[string]interface{})["LogPaging"]
|
||||
var a map[string]interface{}
|
||||
for v, k := range datas.([]interface{}) {
|
||||
b := k.(map[string]interface{})["OutputJSON"].(string)
|
||||
if err := json.Unmarshal([]byte(b), &a); err != nil {
|
||||
log.Fatalf("Failed to unmarshal JSON: %v", err)
|
||||
}
|
||||
fmt.Println(v, a)
|
||||
fmt.Printf("序号:%d,攻击时间:[%s],安全域:%s-%s##攻击源IP:%s#目的源IP:%s:%s,攻击类型:%s,应用协议:%s,请求域名:%s\n", v, a["Time"], a["SrcZoneName"], a["DestZoneName"], a["SrcIPAddr"], a["DestIPAddr"], strconv.FormatFloat(a["DestPort"].(float64), 'f', 0, 64), a["ThreatName"], a["Application"], a["HttpHost"])
|
||||
body := conn.DT_POST("https://11.2.68.146/wnm/get.j", header, bytes.NewBufferString(values.Encode()))
|
||||
var bodys Person
|
||||
json.Unmarshal(body, &bodys)
|
||||
|
||||
for v, k := range bodys.LogPaging {
|
||||
// fmt.Printf("序号:%d,攻击时间:[%s],安全域:%s-%s##攻击源IP:%s#目的源IP:%s:%s,攻击类型:%s,应用协议:%s,请求域名:%s\n", v, a["Time"], a["SrcZoneName"], a["DestZoneName"], a["SrcIPAddr"], a["DestIPAddr"], strconv.FormatFloat(a["DestPort"].(float64), 'f', 0, 64), a["ThreatName"], a["Application"], a["HttpHost"])
|
||||
sheet.Cell("A" + strconv.Itoa(v+1)).SetString(strconv.Itoa(v)) // 第一列 (A1)
|
||||
sheet.Cell("B" + strconv.Itoa(v+1)).SetString(a["Time"].(string))
|
||||
sheet.Cell("C" + strconv.Itoa(v+1)).SetString(a["SrcZoneName"].(string))
|
||||
sheet.Cell("B" + strconv.Itoa(v+1)).SetString(k.Time)
|
||||
sheet.Cell("C" + strconv.Itoa(v+1)).SetString(k.SrcZoneName)
|
||||
sheet.Cell("D" + strconv.Itoa(v+1)).SetString(a["DestZoneName"].(string))
|
||||
sheet.Cell("E" + strconv.Itoa(v+1)).SetString(a["SrcIPAddr"].(string))
|
||||
sheet.Cell("F" + strconv.Itoa(v+1)).SetString(a["DestIPAddr"].(string))
|
||||
@ -84,3 +80,12 @@ func Fw_event(cookieStr string) {
|
||||
log.Fatalf("保存文件时出错: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
type Person struct {
|
||||
NTOP string `json:"ntop"`
|
||||
LogPaging []LogPaging `json:"logpaging"`
|
||||
}
|
||||
type LogPaging struct {
|
||||
Time string `json:"time"`
|
||||
SrcZoneName string `json"srczonename"`
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ import (
|
||||
// headers := map[string]string{
|
||||
// "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
|
||||
// }
|
||||
func DT_POST(urls string, headers map[string]string, bytess io.Reader) map[string]interface{} {
|
||||
func DT_POST(urls string, headers map[string]string, bytess io.Reader) []byte {
|
||||
url, err := url.Parse(urls)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
@ -52,12 +52,13 @@ func DT_POST(urls string, headers map[string]string, bytess io.Reader) map[strin
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
log.Println(string(body))
|
||||
var gcresp map[string]interface{}
|
||||
if err := ScanJson(resp, gcresp); err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
return gcresp
|
||||
// log.Println(string(body))
|
||||
// var gcresp map[string]interface{}
|
||||
// if err := ScanJson(resp, gcresp); err != nil {
|
||||
// log.Println(err)
|
||||
// }
|
||||
|
||||
return body
|
||||
}
|
||||
|
||||
// req 请求体 url 请求地址 headers请求头
|
||||
|
2
go.mod
2
go.mod
@ -3,6 +3,7 @@ module dt_automate
|
||||
go 1.23.6
|
||||
|
||||
require (
|
||||
github.com/Andrew-M-C/go.jsonvalue v1.4.1
|
||||
github.com/Esword618/unioffice v1.4.1
|
||||
github.com/go-sql-driver/mysql v1.9.0
|
||||
github.com/kbinani/screenshot v0.0.0-20250118074034-a3924b7bbc8c
|
||||
@ -19,6 +20,7 @@ require (
|
||||
github.com/godbus/dbus/v5 v5.1.0 // indirect
|
||||
github.com/jezek/xgb v1.1.1 // indirect
|
||||
github.com/lxn/win v0.0.0-20210218163916-a377121e959e // indirect
|
||||
github.com/shopspring/decimal v1.4.0 // indirect
|
||||
github.com/stretchr/testify v1.9.0 // indirect
|
||||
golang.org/x/sys v0.28.0 // indirect
|
||||
)
|
||||
|
14
go.sum
14
go.sum
@ -1,5 +1,7 @@
|
||||
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
||||
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
||||
github.com/Andrew-M-C/go.jsonvalue v1.4.1 h1:MGtqaKy5Z7Xi/hnWaeqWDMwno79uNRt0XoCGHa1pm74=
|
||||
github.com/Andrew-M-C/go.jsonvalue v1.4.1/go.mod h1:EsYbZ97LlOhGUs+7qTwZI9KaJrPe6nK8sEZKEqr70Ww=
|
||||
github.com/Esword618/unioffice v1.4.1 h1:qdcC+FpAPfLU3/WbUoICt1WgDR0tDC9ZPmBx4g3LRXM=
|
||||
github.com/Esword618/unioffice v1.4.1/go.mod h1:8BQw+FmXV1Xfu7UeEtwL8wdk8gfM1Ib0RHqklrRr764=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@ -18,8 +20,12 @@ github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP
|
||||
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
|
||||
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/jezek/xgb v1.1.1 h1:bE/r8ZZtSv7l9gk6nU0mYx51aXrvnyb44892TwSaqS4=
|
||||
github.com/jezek/xgb v1.1.1/go.mod h1:nrhwO0FX/enq75I7Y7G8iN1ubpSGZEiA3v9e9GyRFlk=
|
||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/kbinani/screenshot v0.0.0-20250118074034-a3924b7bbc8c h1:1IlzDla/ZATV/FsRn1ETf7ir91PHS2mrd4VMunEtd9k=
|
||||
github.com/kbinani/screenshot v0.0.0-20250118074034-a3924b7bbc8c/go.mod h1:Pmpz2BLf55auQZ67u3rvyI2vAQvNetkK/4zYUmpauZQ=
|
||||
github.com/lxn/win v0.0.0-20210218163916-a377121e959e h1:H+t6A/QJMbhCSEH5rAuRxh+CtW96g0Or0Fxa9IKr4uc=
|
||||
@ -30,6 +36,12 @@ github.com/playwright-community/playwright-go v0.5001.0 h1:EY3oB+rU9cUp6CLHguWE8
|
||||
github.com/playwright-community/playwright-go v0.5001.0/go.mod h1:kBNWs/w2aJ2ZUp1wEOOFLXgOqvppFngM5OS+qyhl+ZM=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
|
||||
github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
|
||||
github.com/smartystreets/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs=
|
||||
github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
|
||||
github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hgR6gDIPg=
|
||||
github.com/smartystreets/goconvey v1.7.2/go.mod h1:Vw0tHAZW6lzCRk3xgdin6fKYcG+G3Pg9vgXWeJpQFMM=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
@ -42,6 +54,7 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
@ -73,6 +86,7 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
|
121
vendor/github.com/Andrew-M-C/go.jsonvalue/CHANGELOG.md
generated
vendored
Normal file
121
vendor/github.com/Andrew-M-C/go.jsonvalue/CHANGELOG.md
generated
vendored
Normal file
@ -0,0 +1,121 @@
|
||||
<font size=6>Change Log</font>
|
||||
|
||||
[中文](./CHANGELOG_zh-cn.md)
|
||||
|
||||
- [v1.4.1](#v141)
|
||||
- [v1.4.0](#v140)
|
||||
- [v1.3.8](#v138)
|
||||
- [v1.3.7](#v137)
|
||||
- [v1.3.6](#v136)
|
||||
- [v1.3.5](#v135)
|
||||
- [v1.3.4](#v134)
|
||||
- [v1.3.3](#v133)
|
||||
- [v1.3.2](#v132)
|
||||
- [v1.3.1](#v131)
|
||||
- [v1.3.0](#v130)
|
||||
- [v1.2.1](#v121)
|
||||
- [v1.2.0](#v120)
|
||||
- [v1.1.1](#v111)
|
||||
|
||||
## v1.4.1
|
||||
|
||||
- Add `v.At(...).Set(...)` pattern, allowing putting keys ahead (comparing to `v.Set(...).At(...)`).
|
||||
|
||||
## v1.4.0
|
||||
|
||||
- Allow passing parameter with a single slice or array for Get, Set, Append, Insert, Delete methods.
|
||||
- Add GreaterThan, LessThan, GreaterThanOrEqual, LessThanOrEqual methods for number comparation.
|
||||
|
||||
## v1.3.8
|
||||
|
||||
- Fix Issue [#30](https://github.com/Andrew-M-C/go.jsonvalue/issues/30)
|
||||
|
||||
## v1.3.7
|
||||
|
||||
- Fix Issue [#29](https://github.com/Andrew-M-C/go.jsonvalue/issues/29)
|
||||
|
||||
## v1.3.6
|
||||
|
||||
- Fix a floating sign [bug](https://github.com/akbarfa49/go.jsonvalue/commit/278817)
|
||||
- Fix Issue [#27](https://github.com/Andrew-M-C/go.jsonvalue/issues/27)
|
||||
|
||||
## v1.3.5
|
||||
|
||||
- Fix Issue [#26](https://github.com/Andrew-M-C/go.jsonvalue/issues/26)
|
||||
|
||||
## v1.3.4
|
||||
|
||||
Release jsonvalue v1.3.4. Comparing to v1.3.3:
|
||||
|
||||
- `*jsonvalue.V` type now implements following interfaces thus it can used directly in `encoding/json`:
|
||||
- `json.Marshaler`、`json.Unmarshaler`
|
||||
- `encoding.BinaryMarshaler`、`encoding.BinaryUnmarshaler`
|
||||
- Supports importing data types those implement `json.Marshaler` or `encoding.TextMarshaler` interfaces, just like `encoding/json` does.
|
||||
- Add `MustAdd`, `MustAppend`, `MustInsert`, `MustSet`, `MustDelete` methods. These methods will not return sub-values or errors.
|
||||
- This will prevent golangci-lint warning of "return value is not used"
|
||||
- Bug fix: When invoking `Append(xxx).InTheBeginning()`, the sub-value was actually and faulty append to the end.
|
||||
- Pre-allocate some buffer and space when marshaling and unmarshaling. It will speed-up a little bit and save 40% alloc count by average.
|
||||
|
||||
## v1.3.3
|
||||
|
||||
Release jsonvalue v1.3.3. Comparing to v1.3.2:
|
||||
|
||||
- Release Engligh [wiki](https://github.com/Andrew-M-C/go.jsonvalue/blob/master/docs/en/README.md).
|
||||
- Fix #19 and #22.
|
||||
|
||||
## v1.3.2
|
||||
|
||||
Release jsonvalue 1.3.2. Comparing to v1.3.1, [#17](https://github.com/Andrew-M-C/go.jsonvalue/issues/17) is fixed.
|
||||
|
||||
## v1.3.1
|
||||
|
||||
Release jsonvalue 1.3.1. Comparing to v1.3.0:
|
||||
|
||||
- It is available to get key sequences of an unmarshaled object JSON
|
||||
- Supporting marshal object by key sequence of when they are set.
|
||||
- All invisible ASCII characters will be escaped in `\u00XX` format.
|
||||
|
||||
## v1.3.0
|
||||
|
||||
Release v1.3.0. Comparing to v1.2.x:
|
||||
|
||||
- No longer escape % symbol by default.
|
||||
- Add `Import` and `Export` function to support conversion between Go standard types and jsonvalue.
|
||||
- Support generics-like operations in `Set, Append, Insert, Add, New` functions, which allows programmers to set any legal types without specifying types explicitly.
|
||||
- Add `OptIndent` to support indent in marshaling.
|
||||
|
||||
## v1.2.1
|
||||
|
||||
Release v1.2.1. Comparing to v1.2.0:
|
||||
|
||||
- Support not escaping slash symbol / in marshaling. Please refer to `OptEscapeSlash` function.
|
||||
- Support not escaping several HTML symbols in marshaling (issue #13). Please refer to OptEscapeHTML function.
|
||||
- Support not escaping unicodes greater than `\u00FF` in marshaling. Please refer to OptUTF8 function.
|
||||
- Support children-auto-generating in `Append(...).InTheBeginning()` and `Append(...).InTheEnd()`. But keep in mind that Insert operations remains not doing that.
|
||||
- You can override default marshaling options from now on. Please refer to `SetDefaultMarshalOptions` function.
|
||||
|
||||
Other changes:
|
||||
|
||||
- Instead of Travis-CI, I will use Github Actions in order to generate go test reports from now on.
|
||||
|
||||
## v1.2.0
|
||||
|
||||
Release v1.2.0, comparing to v1.1.1:
|
||||
|
||||
- Fix the bug that float-pointed numbers with scientific notation format are not supported. ([issue #8](https://github.com/Andrew-M-C/go.jsonvalue/issues/8))
|
||||
- Add detailed wiki written in simplified Chinese. If you need English one, please leave me an issue.
|
||||
- Deprecate `Opt{}` for additional options, and replace with `OptXxx()` functions.
|
||||
- A first non-forward-compatible feature is released: Parameter formats for `NewFloat64` and `NewFloat32` is changed.
|
||||
- If you want to specify format of float-pointed numbers, please use `NewFloat64f` and `NewFloat32f` instead.
|
||||
- Add `ForRangeArr` and `ForRangeObj` functions, deprecating `IterArray` and `IterObject`.
|
||||
- Support `SetEscapeHTML`. ([issue11](https://github.com/Andrew-M-C/go.jsonvalue/issues/11))
|
||||
- Support converting number to legal JSON data when they are `+/-NaN` and `+/-Inf`.
|
||||
|
||||
## v1.1.1
|
||||
|
||||
Release v1.1.1, comparing to v1.1.0:
|
||||
|
||||
- All functions will NOT return nil `*jsonvalue.V` object instead of an instance with `NotExist` type when error occurs.
|
||||
- Therefore, programmers can use the returned instance for shorter operations.
|
||||
- Supports `MustGet()` function, without error returning.
|
||||
- Supports `String()` for `ValueType` type
|
126
vendor/github.com/Andrew-M-C/go.jsonvalue/CHANGELOG_zh-cn.md
generated
vendored
Normal file
126
vendor/github.com/Andrew-M-C/go.jsonvalue/CHANGELOG_zh-cn.md
generated
vendored
Normal file
@ -0,0 +1,126 @@
|
||||
<font size=6>变更日志</font>
|
||||
|
||||
[English](./CHANGELOG.md)
|
||||
|
||||
- [v1.4.1](#v141)
|
||||
- [v1.4.0](#v140)
|
||||
- [v1.3.8](#v138)
|
||||
- [v1.3.7](#v137)
|
||||
- [v1.3.6](#v136)
|
||||
- [v1.3.5](#v135)
|
||||
- [v1.3.4](#v134)
|
||||
- [v1.3.3](#v133)
|
||||
- [v1.3.2](#v132)
|
||||
- [v1.3.1](#v131)
|
||||
- [v1.3.0](#v130)
|
||||
- [v1.2.1](#v121)
|
||||
- [v1.2.0](#v120)
|
||||
- [v1.1.1](#v111)
|
||||
|
||||
## v1.4.1
|
||||
|
||||
- 新增 `v.At(...).Set(...)` 模式, 相比 `v.Set(...).At(...)` 模式不同的是将 key 放在前面
|
||||
|
||||
## v1.4.0
|
||||
|
||||
- 在 Get, Set, Append, Insert, Delete 等方法中, 允许传递一个切片参数, 用来标识 key 链
|
||||
- 添加 GreaterThan, LessThan, GreaterThanOrEqual, LessThanOrEqual 方法用于数字比较
|
||||
|
||||
## v1.3.8
|
||||
|
||||
- 修复 Issue [#30](https://github.com/Andrew-M-C/go.jsonvalue/issues/30)
|
||||
|
||||
## v1.3.7
|
||||
|
||||
- 修复 Issue [#29](https://github.com/Andrew-M-C/go.jsonvalue/issues/29)
|
||||
|
||||
## v1.3.6
|
||||
|
||||
- 修复一个浮点数符号的 [bug](https://github.com/akbarfa49/go.jsonvalue/commit/278817)
|
||||
- 修复 Issue [#27](https://github.com/Andrew-M-C/go.jsonvalue/issues/27)
|
||||
|
||||
## v1.3.5
|
||||
|
||||
- 修复 Issue [#26](https://github.com/Andrew-M-C/go.jsonvalue/issues/26)
|
||||
|
||||
## v1.3.4
|
||||
|
||||
发布 jsonvalue v1.3.4,相比 v1.3.3:
|
||||
|
||||
- 添加 `*jsonvalue.V` 对以下接口的支持, 使之可以适配 `encoding/json`:
|
||||
- `json.Marshaler`、`json.Unmarshaler`
|
||||
- `encoding.BinaryMarshaler`、`encoding.BinaryUnmarshaler`
|
||||
- `Import` 和 `New` 函数支持导入实现了 `json.Marshaler` 和 `encoding.TextMarshaler` 的数据类型, 就像 `encoding/json` 一样 ([#24](https://github.com/Andrew-M-C/go.jsonvalue/issues/24))
|
||||
- 添加 `MustAdd`, `MustAppend`, `MustInsert`, `MustSet`, `MustDelete` 等方法, 这些方法不返回子值和 error 信息
|
||||
- 可以避免 golangci-lint 的警告提示
|
||||
- Bug 修复: 当 `Append(xxx).InTheBeginning()` 时, 实际上追加到了末尾
|
||||
- 在 Unmarshal 时, 通过预估对象 / 数组大小的方式预创建空间, 略微提升一点点速度, 以及节省平均约 40% 的 alloc 数
|
||||
|
||||
## v1.3.3
|
||||
|
||||
发布 jsonvalue v1.3.3,相比 v1.3.2:
|
||||
|
||||
- 发布英文 [wiki](https://github.com/Andrew-M-C/go.jsonvalue/blob/master/docs/en/README.md)。
|
||||
- 修复了 #19 和 #22。
|
||||
|
||||
## v1.3.2
|
||||
|
||||
发布 jsonvalue 1.3.2,相比 1.3.1,主要是修复了 [#17](https://github.com/Andrew-M-C/go.jsonvalue/issues/17)。
|
||||
|
||||
## v1.3.1
|
||||
|
||||
发布 jsonvalue 1.3.1,相比 1.3.0,改动如下:
|
||||
|
||||
- 支持获取 object 类型的键(key)的顺序
|
||||
- 按照 key 被设置的顺序进行 object 的序列化
|
||||
- 当序列化时,如果遇到 ASCII 的非可打印字符(包括控制字符),均进行 `\u00XX` 转义
|
||||
|
||||
具体说明情参见 [wiki](https://github.com/Andrew-M-C/go.jsonvalue/blob/feature/v1.3.0/docs/zh-cn/12_new_feature.md)
|
||||
|
||||
## v1.3.0
|
||||
|
||||
发布 v1.3.0,相比 v1.2.x,改动如下:
|
||||
|
||||
- 不再默认转义 % 字符
|
||||
- 支持与原生 json 的转换,也即支持从 `struct` 和其他类型中导入为 jsonvalue 类型,也支持将 jsonvalue 导出到 Go 标准类型中
|
||||
- 支持类泛型操作,最直接的影响就是 `Set, Append, Insert, Add, New` 等函数可以传入任意类型
|
||||
- 新增 `OptIndent` 函数以支持可视化锁进
|
||||
|
||||
具体说明情参见 [wiki](https://github.com/Andrew-M-C/go.jsonvalue/blob/feature/v1.3.0/docs/zh-cn/12_new_feature.md)
|
||||
|
||||
## v1.2.1
|
||||
|
||||
发布 v1.2.1,相比 v1.2.1,改动如下:
|
||||
|
||||
- Marshal 时,允许不转义斜杠符号 '/',参见 `OptEscapeSlash` 函数。
|
||||
- Marshal 时,允许不转义几个 HTML 关键符号 (issue #13)。参见 OptEscapeHTML 函数
|
||||
- Marshal 时,对于大于 `\u00FF` 的字符,允许保留 UTF-8 编码,而不进行转义。参见 OptUTF8 函数
|
||||
- `Append(...).InTheBeginning()` 和 `Append(...).InTheEnd()` 操作时,支持自动创建不存在的层级。但 insert 操作依然不会自动创建,这一点请留意
|
||||
- 支持设置默认序列化选项,请参见 SetDefaultMarshalOptions 函数
|
||||
|
||||
其他变更:
|
||||
|
||||
- CI 弃用 Travis-CI,改用 Github Actions
|
||||
|
||||
## v1.2.0
|
||||
|
||||
发布 v1.2.0,相比 v1.1.1,改动如下:
|
||||
|
||||
- 修复不支持科学计数法浮点数的 bug([issue #8](https://github.com/Andrew-M-C/go.jsonvalue/issues/8))
|
||||
- 添加详细的中文 [wiki](https://github.com/Andrew-M-C/go.jsonvalue/blob/master/docs/zh-cn/README.md)。
|
||||
- Marshal 时的额外参数配置,原使用的是 `Opt` 结构体,现推荐改为使用一个或多个 `OptXxx()` 函数
|
||||
- 发布第一个不向前兼容的变更: 修改 `NewFloat64` 和 `NewFloat32` 的入参
|
||||
- 原函数的 `prec` 变量及相关功能改由 `NewFloat64f` 和 `NewFloat32f` 承担。
|
||||
- 添加 `ForRangeArr` 和 `ForRangeObj` 以取代 `IterArray` 和 `IterObject` 函数,参见 [wiki](https://github.com/Andrew-M-C/go.jsonvalue/blob/master/docs/zh-cn/05_iteration.md#%E6%A6%82%E8%BF%B0)
|
||||
- 支持 `SetEscapeHTML`([issue11](https://github.com/Andrew-M-C/go.jsonvalue/issues/11))
|
||||
- 当浮点值中出现 `+/-NaN` 和 `+/-Inf` 时,支持进行特殊转换以符合 JSON 标准
|
||||
|
||||
## v1.1.1
|
||||
|
||||
发布 v1.1.1,相比 v1.1.0,变更如下:
|
||||
|
||||
- 无论是否错误,所有返回 `*jsonvalue.V` 的函数都不会返回 nil。如果错误发生,那么至少会返回一个有效的 `*V` 实例,但是 `Type` 等于 `NotExist`
|
||||
- 这样一来,程序员可以在代码中放心地直接使用返回的 *V 对象,简化代码,而忽略不必要的错误检查。
|
||||
- 支持 `MustGet` 函数,只返回 `*V` 而不返回 error 变量,便于一些级联的代码。
|
||||
- `ValueType` 类型支持 `String()` 函数。
|
||||
|
101
vendor/github.com/Andrew-M-C/go.jsonvalue/LICENSE
generated
vendored
Normal file
101
vendor/github.com/Andrew-M-C/go.jsonvalue/LICENSE
generated
vendored
Normal file
@ -0,0 +1,101 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019-2024 Andrew Min Chang
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
Other dependencies and licenses:
|
||||
|
||||
github.com/shopspring/decimal
|
||||
--------------------------------------------------------------------
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Spring, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
- Based on https://github.com/oguzbilgic/fpd, which has the following license:
|
||||
"""
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013 Oguz Bilgic
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
"""
|
||||
|
||||
github.com/smartystreets/goconvey
|
||||
--------------------------------------------------------------------
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 Smarty
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
Software, and to permit persons to whom the Software is furnished to do so, subject
|
||||
to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
NOTE: Various optional and subordinate components carry their own licensing
|
||||
requirements and restrictions. Use of those components is subject to the terms
|
||||
and conditions outlined the respective license of each component.
|
||||
|
87
vendor/github.com/Andrew-M-C/go.jsonvalue/README.md
generated
vendored
Normal file
87
vendor/github.com/Andrew-M-C/go.jsonvalue/README.md
generated
vendored
Normal file
@ -0,0 +1,87 @@
|
||||
# Jsonvalue - A Fast and Convenient Alternation of Go map[string]interface{}
|
||||
|
||||
[](https://github.com/Andrew-M-C/go.jsonvalue/actions/workflows/go_test_general.yml)
|
||||
[](https://codecov.io/gh/Andrew-M-C/go.jsonvalue)
|
||||
[](https://goreportcard.com/report/github.com/Andrew-M-C/go.jsonvalue)
|
||||
[](https://codebeat.co/projects/github-com-andrew-m-c-go-jsonvalue-master)
|
||||
|
||||
[](https://pkg.go.dev/github.com/Andrew-M-C/go.jsonvalue@v1.4.0)
|
||||
[](https://github.com/Andrew-M-C/go.jsonvalue/tree/v1.4.0)
|
||||
[](https://opensource.org/license/MIT)
|
||||
|
||||
- [Wiki](./docs/en/README.md)
|
||||
- [中文版](./docs/zh-cn/README.md)
|
||||
|
||||
Package **jsonvalue** is for handling unstructured JSON data or customizing JSON marshaling. It is far more faster and convenient than using `interface{}` with `encoding/json`.
|
||||
|
||||
Please refer to [pkg site](https://pkg.go.dev/github.com/Andrew-M-C/go.jsonvalue) or [wiki](./docs/en/README.md) for detailed usage and examples.
|
||||
|
||||
Especially, please check for jsonvalue's [programming scenarios](./docs/en/10_scenarios.md).
|
||||
|
||||
## Import
|
||||
|
||||
Use following statements to import jsonvalue:
|
||||
|
||||
```go
|
||||
import (
|
||||
jsonvalue "github.com/Andrew-M-C/go.jsonvalue"
|
||||
)
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
Sometimes we want to create a complex JSON object like:
|
||||
|
||||
```json
|
||||
{
|
||||
"someObject": {
|
||||
"someObject": {
|
||||
"someObject": {
|
||||
"message": "Hello, JSON!"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
With `jsonvalue`, It is quite simple to implement this:
|
||||
|
||||
```go
|
||||
v := jsonvalue.NewObject()
|
||||
v.MustSet("Hello, JSON").At("someObject", "someObject", "someObject", "message")
|
||||
fmt.Println(v.MustMarshalString())
|
||||
// Output:
|
||||
// {"someObject":{"someObject":{"someObject":{"message":"Hello, JSON!"}}}
|
||||
```
|
||||
|
||||
Similarly, it is quite easy to create sub-arrays like:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"someArray": [
|
||||
"Hello, JSON!"
|
||||
]
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
```go
|
||||
v := jsonvalue.NewArray()
|
||||
v.MustSet("Hello, JSON").At(0, "someObject", 0)
|
||||
fmt.Println(v.MustMarshalString())
|
||||
// Output:
|
||||
// [{"someObject":["Hello, JSON"]}]
|
||||
```
|
||||
|
||||
In opposite, to parse and read the first JSON above, you can use jsonvalue like this:
|
||||
|
||||
```go
|
||||
const raw = `{"someObject": {"someObject": {"someObject": {"message": "Hello, JSON!"}}}}`
|
||||
s := jsonvalue.MustUnmarshalString(s).GetString("someObject", "someObject", "someObject", "message")
|
||||
fmt.Println(s)
|
||||
// Output:
|
||||
// Hello, JSON!
|
||||
```
|
||||
|
||||
However, it is quite complex and annoying in automatically creating array. I strongly suggest using `SetArray()` to create the array first, then use `Append()` or `Insert()` to set array elements. Please refer go [godoc](https://godoc.org/github.com/Andrew-M-C/go.jsonvalue) or [Wiki](./docs/en/README.md).
|
3
vendor/github.com/Andrew-M-C/go.jsonvalue/any_ltgo17.go
generated
vendored
Normal file
3
vendor/github.com/Andrew-M-C/go.jsonvalue/any_ltgo17.go
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
package jsonvalue
|
||||
|
||||
type any = interface{}
|
8
vendor/github.com/Andrew-M-C/go.jsonvalue/codecov.yml
generated
vendored
Normal file
8
vendor/github.com/Andrew-M-C/go.jsonvalue/codecov.yml
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
codecov:
|
||||
bot: laplacezhang@126.com
|
||||
|
||||
coverage:
|
||||
round: down
|
||||
range: "95..97"
|
||||
precision: 2
|
||||
|
136
vendor/github.com/Andrew-M-C/go.jsonvalue/compare.go
generated
vendored
Normal file
136
vendor/github.com/Andrew-M-C/go.jsonvalue/compare.go
generated
vendored
Normal file
@ -0,0 +1,136 @@
|
||||
package jsonvalue
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
"github.com/shopspring/decimal"
|
||||
)
|
||||
|
||||
// GreaterThan returns whether v is greater than another value.
|
||||
//
|
||||
// Both values should be number type, otherwise false will be returned.
|
||||
func (v *V) GreaterThan(another *V) bool {
|
||||
res, _ := greaterThan(v, another)
|
||||
return res
|
||||
}
|
||||
|
||||
// GreaterThanOrEqual returns whether v is greater than or equal to another value.
|
||||
//
|
||||
// Both values should be number type, otherwise false will be returned.
|
||||
func (v *V) GreaterThanOrEqual(another *V) bool {
|
||||
res, _ := greaterOrEqualThan(v, another)
|
||||
return res
|
||||
}
|
||||
|
||||
// LessThan returns whether v is less than another value.
|
||||
//
|
||||
// Both values should be number type, otherwise false will be returned.
|
||||
func (v *V) LessThan(another *V) bool {
|
||||
res, ok := greaterOrEqualThan(v, another)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
return !res
|
||||
}
|
||||
|
||||
// LessThanOrEqual returns whether v is less than or equal to another value.
|
||||
//
|
||||
// Both values should be number type, otherwise false will be returned.
|
||||
func (v *V) LessThanOrEqual(another *V) bool {
|
||||
res, ok := greaterThan(v, another)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
return !res
|
||||
}
|
||||
|
||||
func greaterThan(left, right *V) (result, ok bool) {
|
||||
if left.valueType != Number || right.valueType != Number {
|
||||
return false, false
|
||||
}
|
||||
a1, _ := decimal.NewFromString(string(left.srcByte))
|
||||
a2, _ := decimal.NewFromString(string(right.srcByte))
|
||||
return a1.GreaterThan(a2), true
|
||||
}
|
||||
|
||||
func greaterOrEqualThan(left, right *V) (result, ok bool) {
|
||||
if left.valueType != Number || right.valueType != Number {
|
||||
return false, false
|
||||
}
|
||||
if bytes.Equal(left.srcByte, right.srcByte) {
|
||||
return true, true
|
||||
}
|
||||
a1, _ := decimal.NewFromString(string(left.srcByte))
|
||||
a2, _ := decimal.NewFromString(string(right.srcByte))
|
||||
return a1.GreaterThanOrEqual(a2), true
|
||||
}
|
||||
|
||||
// Equal shows whether the content of two JSON values equal to each other.
|
||||
//
|
||||
// Equal 判断两个 JSON 的内容是否相等
|
||||
func (v *V) Equal(another *V) bool {
|
||||
if v == nil || another == nil {
|
||||
return false
|
||||
}
|
||||
if v.valueType != another.valueType {
|
||||
return false
|
||||
}
|
||||
|
||||
switch v.valueType {
|
||||
default: // including NotExist, Unknown
|
||||
return false
|
||||
case String:
|
||||
return v.valueStr == another.valueStr
|
||||
case Number:
|
||||
return numberEqual(v, another)
|
||||
case Object:
|
||||
return objectEqual(v, another)
|
||||
case Array:
|
||||
return arrayEqual(v, another)
|
||||
case Boolean:
|
||||
return v.valueBool == another.valueBool
|
||||
case Null:
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
func numberEqual(left, right *V) bool {
|
||||
if bytes.Equal(left.srcByte, right.srcByte) {
|
||||
return true
|
||||
}
|
||||
|
||||
d1, _ := decimal.NewFromString(string(left.srcByte))
|
||||
d2, _ := decimal.NewFromString(string(right.srcByte))
|
||||
return d1.Equal(d2)
|
||||
}
|
||||
|
||||
func objectEqual(left, right *V) bool {
|
||||
if len(left.children.object) != len(right.children.object) {
|
||||
return false
|
||||
}
|
||||
|
||||
for k, leftChild := range left.children.object {
|
||||
rightChild, exist := right.children.object[k]
|
||||
if !exist {
|
||||
return false
|
||||
}
|
||||
if !leftChild.v.Equal(rightChild.v) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func arrayEqual(left, right *V) bool {
|
||||
if len(left.children.arr) != len(right.children.arr) {
|
||||
return false
|
||||
}
|
||||
|
||||
for i, leftChild := range left.children.arr {
|
||||
rightChild := right.children.arr[i]
|
||||
if !leftChild.Equal(rightChild) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
201
vendor/github.com/Andrew-M-C/go.jsonvalue/conv.go
generated
vendored
Normal file
201
vendor/github.com/Andrew-M-C/go.jsonvalue/conv.go
generated
vendored
Normal file
@ -0,0 +1,201 @@
|
||||
package jsonvalue
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/Andrew-M-C/go.jsonvalue/internal/buffer"
|
||||
)
|
||||
|
||||
func formatBool(b bool) string {
|
||||
if b {
|
||||
return "true"
|
||||
}
|
||||
return "false"
|
||||
}
|
||||
|
||||
// reference:
|
||||
// - [UTF-16](https://zh.wikipedia.org/zh-cn/UTF-16)
|
||||
// - [JavaScript has a Unicode problem](https://mathiasbynens.be/notes/javascript-unicode)
|
||||
// - [Meaning of escaped unicode characters in JSON](https://stackoverflow.com/questions/21995410/meaning-of-escaped-unicode-characters-in-json)
|
||||
func escapeGreaterUnicodeToBuffByUTF16(r rune, buf buffer.Buffer) {
|
||||
if r <= '\uffff' {
|
||||
_, _ = buf.WriteString(fmt.Sprintf("\\u%04X", r))
|
||||
return
|
||||
}
|
||||
// if r > 0x10FFFF {
|
||||
// // invalid unicode
|
||||
// buf.WriteRune(r)
|
||||
// return
|
||||
// }
|
||||
|
||||
r = r - 0x10000
|
||||
lo := r & 0x003FF
|
||||
hi := (r & 0xFFC00) >> 10
|
||||
_, _ = buf.WriteString(fmt.Sprintf("\\u%04X", hi+0xD800))
|
||||
_, _ = buf.WriteString(fmt.Sprintf("\\u%04X", lo+0xDC00))
|
||||
}
|
||||
|
||||
func escapeGreaterUnicodeToBuffByUTF8(r rune, buf buffer.Buffer) {
|
||||
// Comments below are copied from encoding/json:
|
||||
//
|
||||
// U+2028 is LINE SEPARATOR.
|
||||
// U+2029 is PARAGRAPH SEPARATOR.
|
||||
// They are both technically valid characters in JSON strings,
|
||||
// but don't work in JSONP, which has to be evaluated as JavaScript,
|
||||
// and can lead to security holes there. It is valid JSON to
|
||||
// escape them, so we do so unconditionally.
|
||||
// See http://timelessrepo.com/json-isnt-a-javascript-subset for discussion.
|
||||
if r == '\u2028' || r == '\u2029' {
|
||||
escapeGreaterUnicodeToBuffByUTF16(r, buf)
|
||||
} else {
|
||||
_, _ = buf.WriteRune(r)
|
||||
}
|
||||
}
|
||||
|
||||
func escapeNothing(b byte, buf buffer.Buffer) {
|
||||
_ = buf.WriteByte(b)
|
||||
}
|
||||
|
||||
func escAsciiControlChar(b byte, buf buffer.Buffer) {
|
||||
upper := b >> 4
|
||||
lower := b & 0x0F
|
||||
|
||||
writeChar := func(c byte) {
|
||||
if c < 0xA {
|
||||
_ = buf.WriteByte('0' + c)
|
||||
} else {
|
||||
_ = buf.WriteByte('A' + (c - 0xA))
|
||||
}
|
||||
}
|
||||
|
||||
_, _ = buf.Write([]byte{'\\', 'u', '0', '0'})
|
||||
writeChar(upper)
|
||||
writeChar(lower)
|
||||
}
|
||||
|
||||
func escDoubleQuote(_ byte, buf buffer.Buffer) {
|
||||
_, _ = buf.Write([]byte{'\\', '"'})
|
||||
}
|
||||
|
||||
func escSlash(_ byte, buf buffer.Buffer) {
|
||||
_, _ = buf.Write([]byte{'\\', '/'})
|
||||
}
|
||||
|
||||
func escBackslash(_ byte, buf buffer.Buffer) {
|
||||
_, _ = buf.Write([]byte{'\\', '\\'})
|
||||
}
|
||||
|
||||
func escBackspace(_ byte, buf buffer.Buffer) {
|
||||
_, _ = buf.Write([]byte{'\\', 'b'})
|
||||
}
|
||||
|
||||
func escVertTab(_ byte, buf buffer.Buffer) {
|
||||
_, _ = buf.Write([]byte{'\\', 'f'})
|
||||
}
|
||||
|
||||
func escTab(_ byte, buf buffer.Buffer) {
|
||||
_, _ = buf.Write([]byte{'\\', 't'})
|
||||
}
|
||||
|
||||
func escNewLine(_ byte, buf buffer.Buffer) {
|
||||
_, _ = buf.Write([]byte{'\\', 'n'})
|
||||
}
|
||||
|
||||
func escReturn(_ byte, buf buffer.Buffer) {
|
||||
_, _ = buf.Write([]byte{'\\', 'r'})
|
||||
}
|
||||
|
||||
func escLeftAngle(_ byte, buf buffer.Buffer) {
|
||||
_, _ = buf.Write([]byte{'\\', 'u', '0', '0', '3', 'C'})
|
||||
}
|
||||
|
||||
func escRightAngle(_ byte, buf buffer.Buffer) {
|
||||
_, _ = buf.Write([]byte{'\\', 'u', '0', '0', '3', 'E'})
|
||||
}
|
||||
|
||||
func escAnd(_ byte, buf buffer.Buffer) {
|
||||
_, _ = buf.Write([]byte{'\\', 'u', '0', '0', '2', '6'})
|
||||
}
|
||||
|
||||
// func escPercent(_ byte, buf buffer.Buffer) {
|
||||
// buf.Write([]byte{'\\', 'u', '0', '0', '2', '5'})
|
||||
// }
|
||||
|
||||
func escapeStringToBuff(s string, buf buffer.Buffer, opt *Opt) {
|
||||
for _, r := range s {
|
||||
if r <= 0x7F {
|
||||
b := byte(r)
|
||||
opt.asciiCharEscapingFunc[b](b, buf)
|
||||
} else {
|
||||
opt.unicodeEscapingFunc(r, buf)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func anyToInt(v any) (u int, err error) {
|
||||
if v == nil {
|
||||
return 0, fmt.Errorf("%w: parameter is nil", ErrParameterError)
|
||||
}
|
||||
value := reflect.ValueOf(v)
|
||||
switch value.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return int(value.Int()), nil
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
return int(value.Uint()), nil
|
||||
default:
|
||||
return 0, fmt.Errorf("%v is not a number", reflect.TypeOf(v))
|
||||
}
|
||||
}
|
||||
|
||||
func anyToString(v any) (s string, err error) {
|
||||
if v == nil {
|
||||
return "", fmt.Errorf("%w: parameter is nil", ErrParameterError)
|
||||
}
|
||||
rv := reflect.ValueOf(v)
|
||||
if rv.Type().Kind() == reflect.String {
|
||||
return rv.String(), nil
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("%w: %s is not a string", ErrParameterError, reflect.TypeOf(v).String())
|
||||
}
|
||||
|
||||
func isSliceAndExtractDividedParams(p any) (ok bool, firstParam any, otherParams []any) {
|
||||
v := reflect.ValueOf(p)
|
||||
switch v.Kind() {
|
||||
default:
|
||||
return false, nil, nil
|
||||
case reflect.Slice, reflect.Array:
|
||||
// yes, go on
|
||||
}
|
||||
|
||||
paramCount := v.Len()
|
||||
if paramCount == 0 {
|
||||
return true, nil, nil
|
||||
}
|
||||
|
||||
firstParam = v.Index(0).Interface()
|
||||
|
||||
for i := 1; i < v.Len(); i++ {
|
||||
element := v.Index(i)
|
||||
otherParams = append(otherParams, element.Interface())
|
||||
}
|
||||
return true, firstParam, otherParams
|
||||
}
|
||||
|
||||
func isSliceAndExtractJointParams(p any) (bool, []any) {
|
||||
v := reflect.ValueOf(p)
|
||||
switch v.Kind() {
|
||||
default:
|
||||
return false, nil
|
||||
case reflect.Slice, reflect.Array:
|
||||
// yes, go on
|
||||
}
|
||||
|
||||
res := make([]any, 0, v.Len())
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
element := v.Index(i)
|
||||
res = append(res, element.Interface())
|
||||
}
|
||||
return true, res
|
||||
}
|
99
vendor/github.com/Andrew-M-C/go.jsonvalue/errors.go
generated
vendored
Normal file
99
vendor/github.com/Andrew-M-C/go.jsonvalue/errors.go
generated
vendored
Normal file
@ -0,0 +1,99 @@
|
||||
package jsonvalue
|
||||
|
||||
// Error is equivalent to string and used to create some error constants in this package.
|
||||
// Error constants: http://godoc.org/github.com/Andrew-M-C/go.jsonvalue/#pkg-constants
|
||||
type Error string
|
||||
|
||||
func (e Error) Error() string {
|
||||
return string(e)
|
||||
}
|
||||
|
||||
const (
|
||||
// ErrNilParameter identifies input parameter is nil
|
||||
//
|
||||
// ErrNilParameter 表示参数为空
|
||||
ErrNilParameter = Error("nil parameter")
|
||||
|
||||
// ErrValueUninitialized identifies that a V object is not initialized
|
||||
//
|
||||
// ErrValueUninitialized 表示当前的 jsonvalue 实例未初始化
|
||||
ErrValueUninitialized = Error("jsonvalue instance is not initialized")
|
||||
|
||||
// ErrRawBytesUnrecognized identifies all unexpected raw bytes
|
||||
//
|
||||
// ErrRawBytesUnrecognized 表示无法识别的序列文本
|
||||
ErrRawBytesUnrecognized = Error("unrecognized raw text")
|
||||
|
||||
// ErrNotValidNumberValue shows that a value starts with number or '-' is not eventually a number value
|
||||
//
|
||||
// ErrNotValidNumberValue 表示当前值不是一个合法的数值值
|
||||
ErrNotValidNumberValue = Error("not a valid number value")
|
||||
|
||||
// ErrNotValidBoolValue shows that a value starts with 't' or 'f' is not eventually a bool value
|
||||
//
|
||||
// ErrNotValidBoolValue 表示当前值不是一个合法的布尔值
|
||||
ErrNotValidBoolValue = Error("not a valid bool value")
|
||||
|
||||
// ErrNotValidNullValue shows that a value starts with 'n' is not eventually a bool value
|
||||
//
|
||||
// ErrNotValidNullValue 表示当前不是一个 null 值类型的 JSON
|
||||
ErrNotValidNullValue = Error("not a valid null value")
|
||||
|
||||
// ErrOutOfRange identifies that given position for a JSON array is out of range
|
||||
//
|
||||
// ErrOutOfRange 表示请求数组成员超出数组范围
|
||||
ErrOutOfRange = Error("out of range")
|
||||
|
||||
// ErrNotFound shows that given target is not found in Delete()
|
||||
//
|
||||
// ErrNotFound 表示目标无法找到
|
||||
ErrNotFound = Error("target not found")
|
||||
|
||||
// ErrTypeNotMatch shows that value type is not same as GetXxx()
|
||||
//
|
||||
// ErrTypeNotMatch 表示指定的对象不匹配
|
||||
ErrTypeNotMatch = Error("not match given type")
|
||||
|
||||
// ErrParseNumberFromString shows the error when parsing number from string
|
||||
//
|
||||
// ErrParseNumberFromString 表示从 string 类型的 value 中读取数字失败
|
||||
ErrParseNumberFromString = Error("failed to parse number from string")
|
||||
|
||||
// ErrNotArrayValue shows that operation target value is not an array
|
||||
//
|
||||
// ErrNotArrayValue 表示当前不是一个数组类型 JSON
|
||||
ErrNotArrayValue = Error("not an array typed value")
|
||||
|
||||
// ErrNotObjectValue shows that operation target value is not an valid object
|
||||
//
|
||||
// ErrNotObjectValue 表示当前不是一个合法的对象类型 JSON
|
||||
ErrNotObjectValue = Error("not an object typed value")
|
||||
|
||||
// ErrIllegalString shows that it is not a legal JSON string typed value
|
||||
//
|
||||
// ErrIllegalString 表示字符串不合法
|
||||
ErrIllegalString = Error("illegal string")
|
||||
|
||||
// ErrUnsupportedFloat shows that float value is not supported, like +Inf, -Inf and NaN.
|
||||
//
|
||||
// ErrUnsupportedFloat 表示 float64 是一个不支持的数值,如 +Inf, -Inf 和 NaN
|
||||
ErrUnsupportedFloat = Error("unsupported float value")
|
||||
|
||||
// ErrUnsupportedFloatInOpt shows that float value in option is not supported, like +Inf, -Inf and NaN.
|
||||
//
|
||||
// ErrUnsupportedFloat 表示配置中的 float64 是一个不支持的数值,如 +Inf, -Inf 和 NaN
|
||||
ErrUnsupportedFloatInOpt = Error("unsupported float value in option")
|
||||
|
||||
// ErrMultipleParamNotSupportedWithIfSliceOrArrayGiven indicates that if you
|
||||
// use a slice pr array as first param in Get(...), Set(...).At(...), etc, no
|
||||
// further params are allowed
|
||||
//
|
||||
// ErrMultipleParamNotSupportedWithIfSliceOrArrayGiven 表示如果你在使用 Get(...)、
|
||||
// Set(...).At(...) 等类似方法时, 首参数传入一个切片或数组, 那么不允许再传入更多的参数了
|
||||
ErrMultipleParamNotSupportedWithIfSliceOrArrayGiven = Error("if first param is a slice or array, no further param are allowed")
|
||||
|
||||
// ErrParameterError indicates misc parameter error.
|
||||
//
|
||||
// ErrParameterError 表示各种参数错误
|
||||
ErrParameterError = Error("parameter error")
|
||||
)
|
552
vendor/github.com/Andrew-M-C/go.jsonvalue/get.go
generated
vendored
Normal file
552
vendor/github.com/Andrew-M-C/go.jsonvalue/get.go
generated
vendored
Normal file
@ -0,0 +1,552 @@
|
||||
package jsonvalue
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ================ GET ================
|
||||
|
||||
// Len returns length of an object or array type JSON value.
|
||||
//
|
||||
// Len 返回当前对象类型或数组类型的 JSON 的成员长度。如果不是这两种类型,那么会返回 0。
|
||||
func (v *V) Len() int {
|
||||
switch v.valueType {
|
||||
case Array:
|
||||
return len(v.children.arr)
|
||||
case Object:
|
||||
return len(v.children.object)
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
// Get returns JSON value in specified position. Param formats are like At().
|
||||
//
|
||||
// Get 返回按照参数指定的位置的 JSON 成员值。参数格式与 At() 函数相同
|
||||
func (v *V) Get(firstParam any, otherParams ...any) (*V, error) {
|
||||
return get(v, false, firstParam, otherParams...)
|
||||
}
|
||||
|
||||
// MustGet is same as Get(), but does not return error. If error occurs, a JSON value with
|
||||
// NotExist type will be returned.
|
||||
//
|
||||
// MustGet 与 Get() 函数相同,不过不返回错误。如果发生错误了,那么会返回一个 ValueType() 返回值为 NotExist
|
||||
// 的 JSON 值对象。
|
||||
func (v *V) MustGet(firstParam any, otherParams ...any) *V {
|
||||
res, _ := get(v, false, firstParam, otherParams...)
|
||||
return res
|
||||
}
|
||||
|
||||
func get(v *V, caseless bool, firstParam any, otherParams ...any) (*V, error) {
|
||||
if ok, p1, p2 := isSliceAndExtractDividedParams(firstParam); ok {
|
||||
if len(otherParams) > 0 {
|
||||
return &V{}, ErrMultipleParamNotSupportedWithIfSliceOrArrayGiven
|
||||
}
|
||||
return get(v, caseless, p1, p2...)
|
||||
}
|
||||
child, err := getInCurrentValue(v, caseless, firstParam)
|
||||
if err != nil {
|
||||
return &V{}, err
|
||||
}
|
||||
|
||||
if len(otherParams) == 0 {
|
||||
return child, nil
|
||||
}
|
||||
return get(child, caseless, otherParams[0], otherParams[1:]...)
|
||||
}
|
||||
|
||||
func initCaselessStorage(v *V) {
|
||||
if v.children.lowerCaseKeys != nil {
|
||||
return
|
||||
}
|
||||
v.children.lowerCaseKeys = make(map[string]map[string]struct{}, len(v.children.object))
|
||||
for k := range v.children.object {
|
||||
addCaselessKey(v, k)
|
||||
}
|
||||
}
|
||||
|
||||
func getFromObjectChildren(v *V, caseless bool, key string) (child *V, exist bool) {
|
||||
childProperty, exist := v.children.object[key]
|
||||
if exist {
|
||||
return childProperty.v, true
|
||||
}
|
||||
|
||||
if !caseless {
|
||||
return &V{}, false
|
||||
}
|
||||
|
||||
initCaselessStorage(v)
|
||||
|
||||
lowerCaseKey := strings.ToLower(key)
|
||||
keys, exist := v.children.lowerCaseKeys[lowerCaseKey]
|
||||
if !exist {
|
||||
return &V{}, false
|
||||
}
|
||||
|
||||
for actualKey := range keys {
|
||||
childProperty, exist = v.children.object[actualKey]
|
||||
if exist {
|
||||
return childProperty.v, true
|
||||
}
|
||||
}
|
||||
|
||||
return &V{}, false
|
||||
}
|
||||
|
||||
func getInCurrentValue(v *V, caseless bool, param any) (*V, error) {
|
||||
switch v.valueType {
|
||||
case Array:
|
||||
return getInCurrentArray(v, param)
|
||||
case Object:
|
||||
return getInCurrentObject(v, caseless, param)
|
||||
default:
|
||||
return &V{}, fmt.Errorf("%v type does not supports Get()", v.valueType)
|
||||
}
|
||||
}
|
||||
|
||||
func getInCurrentArray(v *V, param any) (*V, error) {
|
||||
// integer expected
|
||||
pos, err := anyToInt(param)
|
||||
if err != nil {
|
||||
return &V{}, err
|
||||
}
|
||||
child, ok := childAtIndex(v, pos)
|
||||
if !ok {
|
||||
return &V{}, ErrOutOfRange
|
||||
}
|
||||
return child, nil
|
||||
}
|
||||
|
||||
func getInCurrentObject(v *V, caseless bool, param any) (*V, error) {
|
||||
// string expected
|
||||
key, err := anyToString(param)
|
||||
if err != nil {
|
||||
return &V{}, err
|
||||
}
|
||||
child, exist := getFromObjectChildren(v, caseless, key)
|
||||
if !exist {
|
||||
return &V{}, ErrNotFound
|
||||
}
|
||||
return child, nil
|
||||
}
|
||||
|
||||
// GetBytes is similar with v, err := Get(...); v.Bytes(). But if error occurs or Base64 decode error, returns error.
|
||||
//
|
||||
// GetBytes 类似于 v, err := Get(...); v.Bytes(),但如果查询中发生错误,或者 base64 解码错误,则返回错误。
|
||||
func (v *V) GetBytes(firstParam any, otherParams ...any) ([]byte, error) {
|
||||
return getBytes(v, false, firstParam, otherParams...)
|
||||
}
|
||||
|
||||
func getBytes(v *V, caseless bool, firstParam any, otherParams ...any) ([]byte, error) {
|
||||
ret, err := get(v, caseless, firstParam, otherParams...)
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
}
|
||||
if ret.valueType != String {
|
||||
return []byte{}, ErrTypeNotMatch
|
||||
}
|
||||
b, err := internal.b64.DecodeString(ret.valueStr)
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// GetString is equivalent to v, err := Get(...); v.String(). If error occurs, returns "".
|
||||
//
|
||||
// GetString 等效于 v, err := Get(...); v.String()。如果发生错误,则返回 ""。
|
||||
func (v *V) GetString(firstParam any, otherParams ...any) (string, error) {
|
||||
return getString(v, false, firstParam, otherParams...)
|
||||
}
|
||||
|
||||
func getString(v *V, caseless bool, firstParam any, otherParams ...any) (string, error) {
|
||||
ret, err := get(v, caseless, firstParam, otherParams...)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if ret.valueType != String {
|
||||
return "", ErrTypeNotMatch
|
||||
}
|
||||
return ret.String(), nil
|
||||
}
|
||||
|
||||
// GetInt is equivalent to v, err := Get(...); v.Int(). If error occurs, returns 0.
|
||||
//
|
||||
// GetInt 等效于 v, err := Get(...); v.Int()。如果发生错误,则返回 0。
|
||||
func (v *V) GetInt(firstParam any, otherParams ...any) (int, error) {
|
||||
return getInt(v, false, firstParam, otherParams...)
|
||||
}
|
||||
|
||||
func getInt(v *V, caseless bool, firstParam any, otherParams ...any) (int, error) {
|
||||
ret, err := get(v, caseless, firstParam, otherParams...)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
ret, err = getNumberAndErrorFromValue(ret)
|
||||
return ret.Int(), err
|
||||
}
|
||||
|
||||
// GetUint is equivalent to v, err := Get(...); v.Uint(). If error occurs, returns 0.
|
||||
//
|
||||
// GetUint 等效于 v, err := Get(...); v.Uint()。如果发生错误,则返回 0。
|
||||
func (v *V) GetUint(firstParam any, otherParams ...any) (uint, error) {
|
||||
return getUint(v, false, firstParam, otherParams...)
|
||||
}
|
||||
|
||||
func getUint(v *V, caseless bool, firstParam any, otherParams ...any) (uint, error) {
|
||||
ret, err := get(v, caseless, firstParam, otherParams...)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
ret, err = getNumberAndErrorFromValue(ret)
|
||||
return ret.Uint(), err
|
||||
}
|
||||
|
||||
// GetInt64 is equivalent to v, err := Get(...); v.Int64(). If error occurs, returns 0.
|
||||
//
|
||||
// GetInt64 等效于 v, err := Get(...); v.Int64()。如果发生错误,则返回 0。
|
||||
func (v *V) GetInt64(firstParam any, otherParams ...any) (int64, error) {
|
||||
return getInt64(v, false, firstParam, otherParams...)
|
||||
}
|
||||
|
||||
func getInt64(v *V, caseless bool, firstParam any, otherParams ...any) (int64, error) {
|
||||
ret, err := get(v, caseless, firstParam, otherParams...)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
ret, err = getNumberAndErrorFromValue(ret)
|
||||
return ret.Int64(), err
|
||||
}
|
||||
|
||||
// GetUint64 is equivalent to v, err := Get(...); v.Unt64(). If error occurs, returns 0.
|
||||
//
|
||||
// GetUint64 等效于 v, err := Get(...); v.Unt64()。如果发生错误,则返回 0。
|
||||
func (v *V) GetUint64(firstParam any, otherParams ...any) (uint64, error) {
|
||||
return getUint64(v, false, firstParam, otherParams...)
|
||||
}
|
||||
|
||||
func getUint64(v *V, caseless bool, firstParam any, otherParams ...any) (uint64, error) {
|
||||
ret, err := get(v, caseless, firstParam, otherParams...)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
ret, err = getNumberAndErrorFromValue(ret)
|
||||
return ret.Uint64(), err
|
||||
}
|
||||
|
||||
// GetInt32 is equivalent to v, err := Get(...); v.Int32(). If error occurs, returns 0.
|
||||
//
|
||||
// GetInt32 等效于 v, err := Get(...); v.Int32()。如果发生错误,则返回 0。
|
||||
func (v *V) GetInt32(firstParam any, otherParams ...any) (int32, error) {
|
||||
return getInt32(v, false, firstParam, otherParams...)
|
||||
}
|
||||
|
||||
func getInt32(v *V, caseless bool, firstParam any, otherParams ...any) (int32, error) {
|
||||
ret, err := get(v, caseless, firstParam, otherParams...)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
ret, err = getNumberAndErrorFromValue(ret)
|
||||
return ret.Int32(), err
|
||||
}
|
||||
|
||||
// GetUint32 is equivalent to v, err := Get(...); v.Uint32(). If error occurs, returns 0.
|
||||
//
|
||||
// GetUint32 等效于 v, err := Get(...); v.Uint32()。如果发生错误,则返回 0。
|
||||
func (v *V) GetUint32(firstParam any, otherParams ...any) (uint32, error) {
|
||||
return getUint32(v, false, firstParam, otherParams...)
|
||||
}
|
||||
|
||||
func getUint32(v *V, caseless bool, firstParam any, otherParams ...any) (uint32, error) {
|
||||
ret, err := get(v, caseless, firstParam, otherParams...)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
ret, err = getNumberAndErrorFromValue(ret)
|
||||
return ret.Uint32(), err
|
||||
}
|
||||
|
||||
// GetFloat64 is equivalent to v, err := Get(...); v.Float64(). If error occurs, returns 0.0.
|
||||
//
|
||||
// GetFloat64 等效于 v, err := Get(...); v.Float64()。如果发生错误,则返回 0.0。
|
||||
func (v *V) GetFloat64(firstParam any, otherParams ...any) (float64, error) {
|
||||
return getFloat64(v, false, firstParam, otherParams...)
|
||||
}
|
||||
|
||||
func getFloat64(v *V, caseless bool, firstParam any, otherParams ...any) (float64, error) {
|
||||
ret, err := get(v, caseless, firstParam, otherParams...)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
ret, err = getNumberAndErrorFromValue(ret)
|
||||
return ret.Float64(), err
|
||||
}
|
||||
|
||||
// GetFloat32 is equivalent to v, err := Get(...); v.Float32(). If error occurs, returns 0.0.
|
||||
//
|
||||
// GetFloat32 等效于 v, err := Get(...); v.Float32()。如果发生错误,则返回 0.0。
|
||||
func (v *V) GetFloat32(firstParam any, otherParams ...any) (float32, error) {
|
||||
return getFloat32(v, false, firstParam, otherParams...)
|
||||
}
|
||||
|
||||
func getFloat32(v *V, caseless bool, firstParam any, otherParams ...any) (float32, error) {
|
||||
ret, err := get(v, caseless, firstParam, otherParams...)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
ret, err = getNumberAndErrorFromValue(ret)
|
||||
return ret.Float32(), err
|
||||
}
|
||||
|
||||
// GetBool is equivalent to v, err := Get(...); v.Bool(). If error occurs, returns false.
|
||||
//
|
||||
// GetBool 等效于 v, err := Get(...); v.Bool()。如果发生错误,则返回 false。
|
||||
func (v *V) GetBool(firstParam any, otherParams ...any) (bool, error) {
|
||||
return getBool(v, false, firstParam, otherParams...)
|
||||
}
|
||||
|
||||
func getBool(v *V, caseless bool, firstParam any, otherParams ...any) (bool, error) {
|
||||
ret, err := get(v, caseless, firstParam, otherParams...)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
ret, err = getBoolAndErrorFromValue(ret)
|
||||
return ret.Bool(), err
|
||||
}
|
||||
|
||||
// GetNull is equivalent to v, err := Get(...); raise err if error occurs or v.IsNull() == false.
|
||||
//
|
||||
// GetNull 等效于 v, err := Get(...);,如果发生错误或者 v.IsNull() == false 则返回错误。
|
||||
func (v *V) GetNull(firstParam any, otherParams ...any) error {
|
||||
return getNull(v, false, firstParam, otherParams...)
|
||||
}
|
||||
|
||||
func getNull(v *V, caseless bool, firstParam any, otherParams ...any) error {
|
||||
ret, err := get(v, caseless, firstParam, otherParams...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if ret.valueType != Null {
|
||||
return ErrTypeNotMatch
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetObject is equivalent to v, err := Get(...); raise err if error occurs or v.IsObject() == false.
|
||||
//
|
||||
// GetObject 等效于 v, err := Get(...);,如果发生错误或者 v.IsObject() == false 则返回错误。
|
||||
func (v *V) GetObject(firstParam any, otherParams ...any) (*V, error) {
|
||||
return getObject(v, false, firstParam, otherParams...)
|
||||
}
|
||||
|
||||
func getObject(v *V, caseless bool, firstParam any, otherParams ...any) (*V, error) {
|
||||
ret, err := get(v, caseless, firstParam, otherParams...)
|
||||
if err != nil {
|
||||
return &V{}, err
|
||||
}
|
||||
if ret.valueType != Object {
|
||||
return &V{}, ErrTypeNotMatch
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// GetArray is equivalent to v, err := Get(...); raise err if or v.IsArray() == false.
|
||||
//
|
||||
// GetArray 等效于 v, err := Get(...);,如果发生错误或者 v.IsArray() == false 则返回错误。
|
||||
func (v *V) GetArray(firstParam any, otherParams ...any) (*V, error) {
|
||||
return getArray(v, false, firstParam, otherParams...)
|
||||
}
|
||||
|
||||
func getArray(v *V, caseless bool, firstParam any, otherParams ...any) (*V, error) {
|
||||
ret, err := get(v, caseless, firstParam, otherParams...)
|
||||
if err != nil {
|
||||
return &V{}, err
|
||||
}
|
||||
if ret.valueType != Array {
|
||||
return &V{}, ErrTypeNotMatch
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// ================ CASELESS ================
|
||||
|
||||
// Caseless is returned by Caseless(). operations of Caseless type are same as (*V).Get(), but are via caseless key.
|
||||
//
|
||||
// Caseless 类型通过 Caseless() 函数返回。通过 Caseless 接口操作的所有操作均与 (*v).Get()
|
||||
// 相同,但是对 key 进行读取的时候,不区分大小写。
|
||||
type Caseless interface {
|
||||
Get(firstParam any, otherParams ...any) (*V, error)
|
||||
MustGet(firstParam any, otherParams ...any) *V
|
||||
GetBytes(firstParam any, otherParams ...any) ([]byte, error)
|
||||
GetString(firstParam any, otherParams ...any) (string, error)
|
||||
GetInt(firstParam any, otherParams ...any) (int, error)
|
||||
GetUint(firstParam any, otherParams ...any) (uint, error)
|
||||
GetInt64(firstParam any, otherParams ...any) (int64, error)
|
||||
GetUint64(firstParam any, otherParams ...any) (uint64, error)
|
||||
GetInt32(firstParam any, otherParams ...any) (int32, error)
|
||||
GetUint32(firstParam any, otherParams ...any) (uint32, error)
|
||||
GetFloat64(firstParam any, otherParams ...any) (float64, error)
|
||||
GetFloat32(firstParam any, otherParams ...any) (float32, error)
|
||||
GetBool(firstParam any, otherParams ...any) (bool, error)
|
||||
GetNull(firstParam any, otherParams ...any) error
|
||||
GetObject(firstParam any, otherParams ...any) (*V, error)
|
||||
GetArray(firstParam any, otherParams ...any) (*V, error)
|
||||
|
||||
Delete(firstParam any, otherParams ...any) error
|
||||
MustDelete(firstParam any, otherParams ...any)
|
||||
}
|
||||
|
||||
var _ Caseless = (*V)(nil)
|
||||
|
||||
// Caseless returns Caseless interface to support caseless getting.
|
||||
//
|
||||
// IMPORTANT: This function is not gouroutine-safe. Write-mutex (instead of read-mutex)
|
||||
// should be attached in cross-goroutine scenarios.
|
||||
//
|
||||
// Caseless 返回 Caseless 接口,从而实现不区分大小写的 Get 操作。
|
||||
//
|
||||
// 注意: 该函数不是协程安全的,如果在多协程场景下,调用该函数,需要加上写锁,而不能用读锁。
|
||||
func (v *V) Caseless() Caseless {
|
||||
switch v.valueType {
|
||||
default:
|
||||
return v
|
||||
|
||||
case Array, Object:
|
||||
return &caselessOp{
|
||||
v: v,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type caselessOp struct {
|
||||
v *V
|
||||
}
|
||||
|
||||
func (g *caselessOp) Get(firstParam any, otherParams ...any) (*V, error) {
|
||||
return get(g.v, true, firstParam, otherParams...)
|
||||
}
|
||||
|
||||
func (g *caselessOp) MustGet(firstParam any, otherParams ...any) *V {
|
||||
res, _ := get(g.v, true, firstParam, otherParams...)
|
||||
return res
|
||||
}
|
||||
|
||||
func (g *caselessOp) GetBytes(firstParam any, otherParams ...any) ([]byte, error) {
|
||||
return getBytes(g.v, true, firstParam, otherParams...)
|
||||
}
|
||||
|
||||
func (g *caselessOp) GetString(firstParam any, otherParams ...any) (string, error) {
|
||||
return getString(g.v, true, firstParam, otherParams...)
|
||||
}
|
||||
|
||||
func (g *caselessOp) GetInt(firstParam any, otherParams ...any) (int, error) {
|
||||
return getInt(g.v, true, firstParam, otherParams...)
|
||||
}
|
||||
|
||||
func (g *caselessOp) GetUint(firstParam any, otherParams ...any) (uint, error) {
|
||||
return getUint(g.v, true, firstParam, otherParams...)
|
||||
}
|
||||
|
||||
func (g *caselessOp) GetInt64(firstParam any, otherParams ...any) (int64, error) {
|
||||
return getInt64(g.v, true, firstParam, otherParams...)
|
||||
}
|
||||
|
||||
func (g *caselessOp) GetUint64(firstParam any, otherParams ...any) (uint64, error) {
|
||||
return getUint64(g.v, true, firstParam, otherParams...)
|
||||
}
|
||||
|
||||
func (g *caselessOp) GetInt32(firstParam any, otherParams ...any) (int32, error) {
|
||||
return getInt32(g.v, true, firstParam, otherParams...)
|
||||
}
|
||||
|
||||
func (g *caselessOp) GetUint32(firstParam any, otherParams ...any) (uint32, error) {
|
||||
return getUint32(g.v, true, firstParam, otherParams...)
|
||||
}
|
||||
|
||||
func (g *caselessOp) GetFloat64(firstParam any, otherParams ...any) (float64, error) {
|
||||
return getFloat64(g.v, true, firstParam, otherParams...)
|
||||
}
|
||||
|
||||
func (g *caselessOp) GetFloat32(firstParam any, otherParams ...any) (float32, error) {
|
||||
return getFloat32(g.v, true, firstParam, otherParams...)
|
||||
}
|
||||
|
||||
func (g *caselessOp) GetBool(firstParam any, otherParams ...any) (bool, error) {
|
||||
return getBool(g.v, true, firstParam, otherParams...)
|
||||
}
|
||||
|
||||
func (g *caselessOp) GetNull(firstParam any, otherParams ...any) error {
|
||||
return getNull(g.v, true, firstParam, otherParams...)
|
||||
}
|
||||
|
||||
func (g *caselessOp) GetObject(firstParam any, otherParams ...any) (*V, error) {
|
||||
return getObject(g.v, true, firstParam, otherParams...)
|
||||
}
|
||||
|
||||
func (g *caselessOp) GetArray(firstParam any, otherParams ...any) (*V, error) {
|
||||
return getArray(g.v, true, firstParam, otherParams...)
|
||||
}
|
||||
|
||||
func (g *caselessOp) Delete(firstParam any, otherParams ...any) error {
|
||||
return g.v.delete(true, firstParam, otherParams...)
|
||||
}
|
||||
|
||||
func (g *caselessOp) MustDelete(firstParam any, otherParams ...any) {
|
||||
_ = g.v.delete(true, firstParam, otherParams...)
|
||||
}
|
||||
|
||||
// ==== internal value access functions ====
|
||||
|
||||
func getNumberFromNotNumberValue(v *V) *V {
|
||||
if !v.IsString() {
|
||||
return NewInt(0)
|
||||
}
|
||||
if v.valueStr == "" {
|
||||
return NewInt64(0)
|
||||
}
|
||||
ret, _ := newFromNumber(globalPool{}, bytes.TrimSpace([]byte(v.valueStr)))
|
||||
err := parseNumber(ret, globalPool{})
|
||||
if err != nil {
|
||||
return NewInt64(0)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func getNumberAndErrorFromValue(v *V) (*V, error) {
|
||||
switch v.valueType {
|
||||
default:
|
||||
return NewInt(0), ErrTypeNotMatch
|
||||
|
||||
case Number:
|
||||
return v, nil
|
||||
|
||||
case String:
|
||||
ret, _ := newFromNumber(globalPool{}, bytes.TrimSpace([]byte(v.valueStr)))
|
||||
err := parseNumber(ret, globalPool{})
|
||||
if err != nil {
|
||||
return NewInt(0), fmt.Errorf("%w: %v", ErrParseNumberFromString, err)
|
||||
}
|
||||
return ret, ErrTypeNotMatch
|
||||
}
|
||||
}
|
||||
|
||||
func getBoolAndErrorFromValue(v *V) (*V, error) {
|
||||
switch v.valueType {
|
||||
default:
|
||||
return NewBool(false), ErrTypeNotMatch
|
||||
|
||||
case Number:
|
||||
return NewBool(v.Float64() != 0), ErrTypeNotMatch
|
||||
|
||||
case String:
|
||||
if v.valueStr == "true" {
|
||||
return NewBool(true), ErrTypeNotMatch
|
||||
}
|
||||
return NewBool(false), ErrTypeNotMatch
|
||||
|
||||
case Boolean:
|
||||
return v, nil
|
||||
}
|
||||
}
|
598
vendor/github.com/Andrew-M-C/go.jsonvalue/import_export.go
generated
vendored
Normal file
598
vendor/github.com/Andrew-M-C/go.jsonvalue/import_export.go
generated
vendored
Normal file
@ -0,0 +1,598 @@
|
||||
package jsonvalue
|
||||
|
||||
import (
|
||||
"encoding"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Export convert jsonvalue to another type of parameter. The target parameter type should match the type of *V.
|
||||
//
|
||||
// Export 将 *V 转到符合原生 encoding/json 的一个 struct 中。
|
||||
func (v *V) Export(dst any) error {
|
||||
b, err := v.Marshal()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return json.Unmarshal(b, dst)
|
||||
}
|
||||
|
||||
// Import convert json value from a marshal-able parameter to *V. This a experimental function.
|
||||
//
|
||||
// Import 将符合 encoding/json 的 struct 转为 *V 类型。不经过 encoding/json,并且支持 Option.
|
||||
func Import(src any, opts ...Option) (*V, error) {
|
||||
opt := combineOptions(opts)
|
||||
ext := ext{}
|
||||
ext.ignoreOmitempty = opt.ignoreJsonOmitempty
|
||||
v, fu, err := validateValAndReturnParser(reflect.ValueOf(src), ext)
|
||||
if err != nil {
|
||||
return &V{}, err
|
||||
}
|
||||
res, err := fu(v, ext)
|
||||
if err != nil {
|
||||
return &V{}, err
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// parserFunc 处理对应 reflect.Value 的函数
|
||||
type parserFunc func(v reflect.Value, ex ext) (*V, error)
|
||||
|
||||
type ext struct {
|
||||
// standard encoding/json tag
|
||||
omitempty bool
|
||||
toString bool
|
||||
|
||||
// revert of isExported
|
||||
private bool
|
||||
|
||||
// extended jsonvalue options
|
||||
ignoreOmitempty bool
|
||||
}
|
||||
|
||||
func (e ext) shouldOmitEmpty() bool {
|
||||
if e.ignoreOmitempty {
|
||||
return false
|
||||
}
|
||||
return e.omitempty || e.private
|
||||
}
|
||||
|
||||
// validateValAndReturnParser 检查入参合法性并返回相应的处理函数
|
||||
func validateValAndReturnParser(v reflect.Value, ex ext) (out reflect.Value, fu parserFunc, err error) {
|
||||
out = v
|
||||
|
||||
// json.Marshaler and encoding.TextMarshaler
|
||||
if o, f := checkAndParseMarshaler(v); f != nil {
|
||||
// jsonvalue itself
|
||||
if _, ok := v.Interface().(deepCopier); ok {
|
||||
return out, parseJSONValueDeepCopier, nil
|
||||
}
|
||||
return o, f, nil
|
||||
}
|
||||
|
||||
switch v.Kind() {
|
||||
default:
|
||||
// fallthrough
|
||||
// case reflect.Invalid, reflect.Complex64, reflect.Complex128:
|
||||
// fallthrough
|
||||
// case reflect.Chan, reflect.Func, reflect.UnsafePointer:
|
||||
err = fmt.Errorf("jsonvalue: unsupported type: %v", v.Type())
|
||||
|
||||
case reflect.Invalid:
|
||||
fu = parseInvalidValue
|
||||
|
||||
case reflect.Bool:
|
||||
fu = parseBoolValue
|
||||
|
||||
case reflect.Int, reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8:
|
||||
fu = parseIntValue
|
||||
|
||||
case reflect.Uintptr, reflect.Uint, reflect.Uint64, reflect.Uint32, reflect.Uint16, reflect.Uint8:
|
||||
fu = parseUintValue
|
||||
|
||||
case reflect.Float32:
|
||||
fu = parseFloat32Value
|
||||
|
||||
case reflect.Float64:
|
||||
fu = parseFloat64Value
|
||||
|
||||
case reflect.Array:
|
||||
fu = parseArrayValue
|
||||
|
||||
case reflect.Interface:
|
||||
return validateValAndReturnParser(v.Elem(), ex)
|
||||
|
||||
case reflect.Map:
|
||||
switch v.Type().Key().Kind() {
|
||||
default:
|
||||
err = fmt.Errorf("unsupported key type for a map: %v", v.Type().Key())
|
||||
case reflect.String:
|
||||
fu = parseStringMapValue
|
||||
case reflect.Int, reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8:
|
||||
fu = parseIntMapValue
|
||||
case reflect.Uintptr, reflect.Uint, reflect.Uint64, reflect.Uint32, reflect.Uint16, reflect.Uint8:
|
||||
fu = parseUintMapValue
|
||||
}
|
||||
|
||||
case reflect.Ptr:
|
||||
fu = parsePtrValue
|
||||
|
||||
case reflect.Slice:
|
||||
if v.Type() == reflect.TypeOf([]byte{}) {
|
||||
fu = parseBytesValue
|
||||
} else {
|
||||
fu = parseSliceValue
|
||||
}
|
||||
|
||||
case reflect.String:
|
||||
fu = parseStringValue
|
||||
|
||||
case reflect.Struct:
|
||||
fu = parseStructValue
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Hit marshaler if fu is not nil.
|
||||
func checkAndParseMarshaler(v reflect.Value) (out reflect.Value, fu parserFunc) {
|
||||
out = v
|
||||
if !v.IsValid() {
|
||||
return
|
||||
}
|
||||
|
||||
// check type itself
|
||||
if v.Type().Implements(internal.types.JSONMarshaler) {
|
||||
return v, parseJSONMarshaler
|
||||
}
|
||||
if v.Type().Implements(internal.types.TextMarshaler) {
|
||||
return v, parseTextMarshaler
|
||||
}
|
||||
|
||||
// check its origin type
|
||||
if v.Kind() == reflect.Ptr {
|
||||
if v.IsNil() {
|
||||
return
|
||||
}
|
||||
elem := v.Elem()
|
||||
if elem.Type().Implements(internal.types.JSONMarshaler) {
|
||||
return elem, parseJSONMarshaler
|
||||
}
|
||||
if elem.Type().Implements(internal.types.TextMarshaler) {
|
||||
return elem, parseTextMarshaler
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// check its pointer type
|
||||
// referenceType := reflect.PointerTo(v.Type()) // go 1.17 +
|
||||
referenceType := reflect.PtrTo(v.Type())
|
||||
if referenceType.Implements(internal.types.JSONMarshaler) {
|
||||
return getPointerOfValue(v), parseJSONMarshaler
|
||||
}
|
||||
if referenceType.Implements(internal.types.TextMarshaler) {
|
||||
return getPointerOfValue(v), parseTextMarshaler
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// reference:
|
||||
// - [Using reflect to get a pointer to a struct passed as an interface{}](https://groups.google.com/g/golang-nuts/c/KB3_Yj3Ny4c)
|
||||
// - [reflect.Set slice-of-structs value to a struct, without type assertion (because it's unknown)](https://stackoverflow.com/questions/40474682)
|
||||
func getPointerOfValue(v reflect.Value) reflect.Value {
|
||||
vp := reflect.New(reflect.TypeOf(v.Interface()))
|
||||
vp.Elem().Set(v)
|
||||
return vp
|
||||
}
|
||||
|
||||
func parseJSONValueDeepCopier(v reflect.Value, ex ext) (*V, error) {
|
||||
if v.IsNil() {
|
||||
return nil, nil // empty
|
||||
}
|
||||
j, _ := v.Interface().(deepCopier)
|
||||
return j.deepCopy(), nil
|
||||
}
|
||||
|
||||
func parseJSONMarshaler(v reflect.Value, ex ext) (*V, error) {
|
||||
if v.Kind() == reflect.Ptr && v.IsNil() {
|
||||
return nil, nil // empty
|
||||
}
|
||||
marshaler, _ := v.Interface().(json.Marshaler)
|
||||
if marshaler == nil {
|
||||
return nil, nil // empty
|
||||
}
|
||||
b, err := marshaler.MarshalJSON()
|
||||
if err != nil {
|
||||
return &V{}, fmt.Errorf("JSONMarshaler returns error: %w", err)
|
||||
}
|
||||
|
||||
res, err := Unmarshal(b)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("illegal JSON data generated from type '%v', error: %w", v.Type(), err)
|
||||
}
|
||||
|
||||
if ex.shouldOmitEmpty() {
|
||||
switch res.ValueType() {
|
||||
default:
|
||||
return nil, nil
|
||||
case String:
|
||||
if res.String() == "" {
|
||||
return nil, nil
|
||||
}
|
||||
case Number:
|
||||
if res.Float64() == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
case Array, Object:
|
||||
if res.Len() == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
case Boolean:
|
||||
if !res.Bool() {
|
||||
return nil, nil
|
||||
}
|
||||
case Null:
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func parseTextMarshaler(v reflect.Value, ex ext) (*V, error) {
|
||||
if v.Kind() == reflect.Ptr && v.IsNil() {
|
||||
return nil, nil // empty
|
||||
}
|
||||
marshaler, _ := v.Interface().(encoding.TextMarshaler)
|
||||
if marshaler == nil {
|
||||
return NewNull(), nil // empty
|
||||
}
|
||||
b, err := marshaler.MarshalText()
|
||||
if err != nil {
|
||||
return &V{}, err
|
||||
}
|
||||
|
||||
if len(b) == 0 && ex.shouldOmitEmpty() {
|
||||
return nil, nil
|
||||
}
|
||||
return NewString(string(b)), nil
|
||||
}
|
||||
|
||||
func parseInvalidValue(_ reflect.Value, ex ext) (*V, error) {
|
||||
if ex.shouldOmitEmpty() {
|
||||
return nil, nil
|
||||
}
|
||||
return NewNull(), nil
|
||||
}
|
||||
|
||||
func parseBoolValue(v reflect.Value, ex ext) (*V, error) {
|
||||
b := v.Bool()
|
||||
if !b && ex.shouldOmitEmpty() {
|
||||
return nil, nil
|
||||
}
|
||||
if ex.toString {
|
||||
return NewString(fmt.Sprint(b)), nil
|
||||
}
|
||||
return NewBool(b), nil
|
||||
}
|
||||
|
||||
func parseIntValue(v reflect.Value, ex ext) (*V, error) {
|
||||
i := v.Int()
|
||||
if i == 0 && ex.shouldOmitEmpty() {
|
||||
return nil, nil
|
||||
}
|
||||
if ex.toString {
|
||||
return NewString(strconv.FormatInt(i, 10)), nil
|
||||
}
|
||||
return NewInt64(i), nil
|
||||
}
|
||||
|
||||
func parseUintValue(v reflect.Value, ex ext) (*V, error) {
|
||||
u := v.Uint()
|
||||
if u == 0 && ex.shouldOmitEmpty() {
|
||||
return nil, nil
|
||||
}
|
||||
if ex.toString {
|
||||
return NewString(strconv.FormatUint(u, 10)), nil
|
||||
}
|
||||
return NewUint64(u), nil
|
||||
}
|
||||
|
||||
func parseFloat64Value(v reflect.Value, ex ext) (*V, error) {
|
||||
f := v.Float()
|
||||
if f == 0.0 && ex.shouldOmitEmpty() {
|
||||
return nil, nil
|
||||
}
|
||||
if ex.toString {
|
||||
f64 := NewFloat64(f)
|
||||
return NewString(f64.MustMarshalString()), nil
|
||||
}
|
||||
return NewFloat64(f), nil
|
||||
}
|
||||
|
||||
func parseFloat32Value(v reflect.Value, ex ext) (*V, error) {
|
||||
f := v.Float()
|
||||
if f == 0.0 && ex.shouldOmitEmpty() {
|
||||
return nil, nil
|
||||
}
|
||||
if ex.toString {
|
||||
f32 := NewFloat32(float32(f))
|
||||
return NewString(f32.MustMarshalString()), nil
|
||||
}
|
||||
return NewFloat32(float32(f)), nil
|
||||
}
|
||||
|
||||
func parseArrayValue(v reflect.Value, ex ext) (*V, error) {
|
||||
ex.omitempty = false
|
||||
res := NewArray()
|
||||
le := v.Len()
|
||||
|
||||
for i := 0; i < le; i++ {
|
||||
vv := v.Index(i)
|
||||
vv, fu, err := validateValAndReturnParser(vv, ex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
child, err := fu(vv, ex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res.MustAppend(child).InTheEnd()
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func parseMapValue(v reflect.Value, ex ext, keyFunc func(key reflect.Value) string) (*V, error) {
|
||||
if v.IsNil() {
|
||||
return parseNullValue(v, ex)
|
||||
}
|
||||
|
||||
keys := v.MapKeys()
|
||||
if len(keys) == 0 {
|
||||
if ex.shouldOmitEmpty() {
|
||||
return nil, nil
|
||||
}
|
||||
return NewObject(), nil
|
||||
}
|
||||
|
||||
res := NewObject()
|
||||
|
||||
for _, kk := range keys {
|
||||
vv := v.MapIndex(kk)
|
||||
vv, fu, err := validateValAndReturnParser(vv, ex)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
child, err := fu(vv, ex)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
res.MustSet(child).At(keyFunc(kk))
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func parseStringMapValue(v reflect.Value, ex ext) (*V, error) {
|
||||
return parseMapValue(v, ex, func(k reflect.Value) string {
|
||||
return k.String()
|
||||
})
|
||||
}
|
||||
|
||||
func parseIntMapValue(v reflect.Value, ex ext) (*V, error) {
|
||||
return parseMapValue(v, ex, func(k reflect.Value) string {
|
||||
return strconv.FormatInt(k.Int(), 10)
|
||||
})
|
||||
}
|
||||
|
||||
func parseUintMapValue(v reflect.Value, ex ext) (*V, error) {
|
||||
return parseMapValue(v, ex, func(k reflect.Value) string {
|
||||
return strconv.FormatUint(k.Uint(), 10)
|
||||
})
|
||||
}
|
||||
|
||||
func parsePtrValue(v reflect.Value, ex ext) (*V, error) {
|
||||
if v.IsNil() {
|
||||
return parseNullValue(v, ex)
|
||||
}
|
||||
|
||||
v, fu, err := validateValAndReturnParser(v.Elem(), ex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return fu(v, ex)
|
||||
}
|
||||
|
||||
func parseSliceValue(v reflect.Value, ex ext) (*V, error) {
|
||||
if v.IsNil() || v.Len() == 0 {
|
||||
if ex.shouldOmitEmpty() {
|
||||
return nil, nil
|
||||
}
|
||||
return NewArray(), nil
|
||||
}
|
||||
|
||||
return parseArrayValue(v, ex)
|
||||
}
|
||||
|
||||
func parseBytesValue(v reflect.Value, ex ext) (*V, error) {
|
||||
b := v.Interface().([]byte)
|
||||
if len(b) == 0 && ex.shouldOmitEmpty() {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return NewBytes(b), nil
|
||||
}
|
||||
|
||||
func parseStringValue(v reflect.Value, ex ext) (*V, error) {
|
||||
str := v.String()
|
||||
if str == "" && ex.shouldOmitEmpty() {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return NewString(str), nil
|
||||
}
|
||||
|
||||
func parseStructValue(v reflect.Value, ex ext) (*V, error) {
|
||||
t := v.Type()
|
||||
numField := t.NumField()
|
||||
|
||||
res := NewObject()
|
||||
|
||||
for i := 0; i < numField; i++ {
|
||||
vv := v.Field(i)
|
||||
tt := t.Field(i)
|
||||
|
||||
keys, children, err := parseStructFieldValue(vv, tt, ex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for i, k := range keys {
|
||||
v := children[i]
|
||||
res.MustSet(v).At(k)
|
||||
}
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func parseNullValue(_ reflect.Value, ex ext) (*V, error) {
|
||||
if ex.shouldOmitEmpty() {
|
||||
return nil, nil
|
||||
}
|
||||
return NewNull(), nil
|
||||
}
|
||||
|
||||
func parseStructFieldValue(
|
||||
fv reflect.Value, ft reflect.StructField, parentEx ext,
|
||||
) (keys []string, children []*V, err error) {
|
||||
|
||||
if ft.Anonymous {
|
||||
return parseStructAnonymousFieldValue(fv, ft, parentEx)
|
||||
}
|
||||
|
||||
if !fv.CanInterface() {
|
||||
return
|
||||
}
|
||||
|
||||
fieldName, ex := readFieldTag(ft, "json", parentEx)
|
||||
if fieldName == "-" {
|
||||
return
|
||||
}
|
||||
|
||||
fv, fu, err := validateValAndReturnParser(fv, ex)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("parsing field '%s' error: %w", fieldName, err)
|
||||
return
|
||||
}
|
||||
|
||||
child, err := fu(fv, ex)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("parsing field '%s' error: %w", fieldName, err)
|
||||
return
|
||||
}
|
||||
if child != nil {
|
||||
return []string{fieldName}, []*V{child}, nil
|
||||
}
|
||||
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
func parseStructAnonymousFieldValue(
|
||||
fv reflect.Value, ft reflect.StructField, parentEx ext,
|
||||
) (keys []string, children []*V, err error) {
|
||||
|
||||
fieldName, ex := readAnonymousFieldTag(ft, "json", parentEx)
|
||||
if fieldName == "-" {
|
||||
return nil, nil, nil
|
||||
}
|
||||
if fv.Kind() == reflect.Ptr && fv.IsNil() {
|
||||
if ex.shouldOmitEmpty() {
|
||||
return nil, nil, nil
|
||||
}
|
||||
return []string{fieldName}, []*V{NewNull()}, nil
|
||||
}
|
||||
|
||||
fv, fu, err := validateValAndReturnParser(fv, ex)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("parsing anonymous field error: %w", err)
|
||||
return
|
||||
}
|
||||
|
||||
child, err := fu(fv, ex)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("parsing anonymous field error: %w", err)
|
||||
return
|
||||
}
|
||||
if child == nil {
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
switch child.ValueType() {
|
||||
default: // invalid
|
||||
return nil, nil, nil
|
||||
|
||||
case String, Number, Boolean, Null, Array:
|
||||
if ex.private {
|
||||
return nil, nil, nil
|
||||
}
|
||||
return []string{fieldName}, []*V{child}, nil
|
||||
|
||||
case Object:
|
||||
child.RangeObjectsBySetSequence(func(k string, c *V) bool {
|
||||
keys = append(keys, k)
|
||||
children = append(children, c)
|
||||
return true
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func readFieldTag(ft reflect.StructField, name string, parentEx ext) (field string, ex ext) {
|
||||
tg := ft.Tag.Get(name)
|
||||
|
||||
if tg == "" {
|
||||
return ft.Name, ext{
|
||||
ignoreOmitempty: parentEx.ignoreOmitempty,
|
||||
}
|
||||
}
|
||||
|
||||
parts := strings.Split(tg, ",")
|
||||
for i, s := range parts {
|
||||
parts[i] = strings.TrimSpace(s)
|
||||
if i > 0 {
|
||||
if s == "omitempty" {
|
||||
ex.omitempty = true
|
||||
} else if s == "string" {
|
||||
ex.toString = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
field = parts[0]
|
||||
if field == "" {
|
||||
field = ft.Name
|
||||
}
|
||||
ex.ignoreOmitempty = parentEx.ignoreOmitempty
|
||||
return
|
||||
}
|
||||
|
||||
func readAnonymousFieldTag(ft reflect.StructField, name string, parentEx ext) (field string, ex ext) {
|
||||
field, ex = readFieldTag(ft, name, parentEx)
|
||||
|
||||
firstChar := ft.Name[0]
|
||||
if firstChar >= 'A' && firstChar <= 'Z' {
|
||||
ex.private = false
|
||||
} else {
|
||||
ex.private = true
|
||||
}
|
||||
|
||||
return
|
||||
}
|
632
vendor/github.com/Andrew-M-C/go.jsonvalue/insert_append_delete.go
generated
vendored
Normal file
632
vendor/github.com/Andrew-M-C/go.jsonvalue/insert_append_delete.go
generated
vendored
Normal file
@ -0,0 +1,632 @@
|
||||
package jsonvalue
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ================ INSERT ================
|
||||
|
||||
// MARK: INSERT
|
||||
|
||||
// Inserter type is for After() and Before() methods.
|
||||
//
|
||||
// # Should be generated ONLY BY V.Insert() !
|
||||
//
|
||||
// Insert 类型适用于 After() 和 Before() 方法。请注意:该类型仅应由 V.Insert 函数生成!
|
||||
type Inserter interface {
|
||||
// After completes the following operation of Insert(). It inserts value AFTER
|
||||
// specified position.
|
||||
//
|
||||
// The last parameter identifies the position where a new JSON is inserted after,
|
||||
// it should ba an integer, no matter signed or unsigned. If the position is
|
||||
// zero or positive integer, it tells the index of an array. If the position
|
||||
// is negative, it tells the backward index of an array.
|
||||
//
|
||||
// For example, 0 represents the first, and -2 represents the second last.
|
||||
//
|
||||
// After 结束并完成 Insert() 函数的后续插入操作,表示插入到指定位置的前面。
|
||||
//
|
||||
// 在 Before 函数的最后一个参数指定了被插入的 JSON 数组的位置,这个参数应当是一个整型
|
||||
// (有无符号类型均可)。
|
||||
// 如果这个值等于0或者正整数,那么它指定的是在 JSON 数组中的位置(从0开始)。如果这个值是负数,
|
||||
// 那么它指定的是 JSON 数组中从最后一个位置开始算起的位置。
|
||||
//
|
||||
// 举例说明:0 表示第一个位置,而 -2 表示倒数第二个位置。
|
||||
After(firstParam any, otherParams ...any) (*V, error)
|
||||
|
||||
// Before completes the following operation of Insert(). It inserts value BEFORE
|
||||
// specified position.
|
||||
//
|
||||
// The last parameter identifies the position where a new JSON is inserted after,
|
||||
// it should ba an integer, no matter signed or unsigned.
|
||||
// If the position is zero or positive integer, it tells the index of an array.
|
||||
// If the position is negative, it tells the backward index of an array.
|
||||
//
|
||||
// For example, 0 represents the first, and -2 represents the second last.
|
||||
//
|
||||
// Before 结束并完成 Insert() 函数的后续插入操作,表示插入到指定位置的后面。
|
||||
//
|
||||
// 在 Before 函数的最后一个参数指定了被插入的 JSON 数组的位置,这个参数应当是一个整型
|
||||
//(有无符号类型均可)。
|
||||
// 如果这个值等于0或者正整数,那么它指定的是在 JSON 数组中的位置(从0开始)。如果这个值是负数,
|
||||
// 那么它指定的是 JSON 数组中从最后一个位置开始算起的位置。
|
||||
//
|
||||
// 举例说明:0 表示第一个位置,而 -2 表示倒数第二个位置。
|
||||
Before(firstParam any, otherParams ...any) (*V, error)
|
||||
}
|
||||
|
||||
type insert struct {
|
||||
v *V
|
||||
c *V // child
|
||||
|
||||
err error
|
||||
}
|
||||
|
||||
// Insert starts inserting a child JSON value
|
||||
//
|
||||
// Insert 开启一个 JSON 数组成员的插入操作.
|
||||
func (v *V) Insert(child any) Inserter {
|
||||
var ch *V
|
||||
var err error
|
||||
|
||||
if child == nil {
|
||||
ch = NewNull()
|
||||
} else if childV, ok := child.(*V); ok {
|
||||
ch = childV
|
||||
} else {
|
||||
ch, err = Import(child)
|
||||
}
|
||||
|
||||
return &insert{
|
||||
v: v,
|
||||
c: ch,
|
||||
err: err,
|
||||
}
|
||||
}
|
||||
|
||||
// InsertString is equivalent to Insert(jsonvalue.NewString(s))
|
||||
//
|
||||
// InsertString 等效于 Insert(jsonvalue.NewString(s))
|
||||
func (v *V) InsertString(s string) Inserter {
|
||||
return v.Insert(NewString(s))
|
||||
}
|
||||
|
||||
// InsertBool is equivalent to Insert(jsonvalue.NewBool(b))
|
||||
//
|
||||
// InsertBool 等效于 Insert(jsonvalue.NewBool(b))
|
||||
func (v *V) InsertBool(b bool) Inserter {
|
||||
return v.Insert(NewBool(b))
|
||||
}
|
||||
|
||||
// InsertInt is equivalent to Insert(jsonvalue.NewInt(b))
|
||||
//
|
||||
// InsertInt 等效于 Insert(jsonvalue.NewInt(b))
|
||||
func (v *V) InsertInt(i int) Inserter {
|
||||
return v.Insert(NewInt(i))
|
||||
}
|
||||
|
||||
// InsertInt64 is equivalent to Insert(jsonvalue.NewInt64(b))
|
||||
//
|
||||
// InsertInt64 等效于 Insert(jsonvalue.NewInt64(b))
|
||||
func (v *V) InsertInt64(i int64) Inserter {
|
||||
return v.Insert(NewInt64(i))
|
||||
}
|
||||
|
||||
// InsertInt32 is equivalent to Insert(jsonvalue.NewInt32(b))
|
||||
//
|
||||
// InsertInt32 等效于 Insert(jsonvalue.NewInt32(b))
|
||||
func (v *V) InsertInt32(i int32) Inserter {
|
||||
return v.Insert(NewInt32(i))
|
||||
}
|
||||
|
||||
// InsertUint is equivalent to Insert(jsonvalue.NewUint(b))
|
||||
//
|
||||
// InsertUint 等效于 Insert(jsonvalue.NewUint(b))
|
||||
func (v *V) InsertUint(u uint) Inserter {
|
||||
return v.Insert(NewUint(u))
|
||||
}
|
||||
|
||||
// InsertUint64 is equivalent to Insert(jsonvalue.NewUint64(b))
|
||||
//
|
||||
// InsertUint64 等效于 Insert(jsonvalue.NewUint64(b))
|
||||
func (v *V) InsertUint64(u uint64) Inserter {
|
||||
return v.Insert(NewUint64(u))
|
||||
}
|
||||
|
||||
// InsertUint32 is equivalent to Insert(jsonvalue.NewUint32(b))
|
||||
//
|
||||
// InsertUint32 等效于 Insert(jsonvalue.NewUint32(b))
|
||||
func (v *V) InsertUint32(u uint32) Inserter {
|
||||
return v.Insert(NewUint32(u))
|
||||
}
|
||||
|
||||
// InsertFloat64 is equivalent to Insert(jsonvalue.NewFloat64(b))
|
||||
//
|
||||
// InsertFloat64 等效于 Insert(jsonvalue.NewFloat64(b))
|
||||
func (v *V) InsertFloat64(f float64) Inserter {
|
||||
return v.Insert(NewFloat64(f))
|
||||
}
|
||||
|
||||
// InsertFloat32 is equivalent to Insert(jsonvalue.NewFloat32(b))
|
||||
//
|
||||
// InsertFloat32 等效于 Insert(jsonvalue.NewFloat32(b))
|
||||
func (v *V) InsertFloat32(f float32) Inserter {
|
||||
return v.Insert(NewFloat32(f))
|
||||
}
|
||||
|
||||
// InsertNull is equivalent to Insert(jsonvalue.NewNull())
|
||||
//
|
||||
// InsertNull 等效于 Insert(jsonvalue.NewNull())
|
||||
func (v *V) InsertNull() Inserter {
|
||||
return v.Insert(NewNull())
|
||||
}
|
||||
|
||||
// InsertObject is equivalent to Insert(jsonvalue.NewObject())
|
||||
//
|
||||
// InsertObject 等效于 Insert(jsonvalue.NewObject())
|
||||
func (v *V) InsertObject() Inserter {
|
||||
return v.Insert(NewObject())
|
||||
}
|
||||
|
||||
// InsertArray is equivalent to Insert(jsonvalue.NewArray())
|
||||
//
|
||||
// InsertArray 等效于 Insert(jsonvalue.NewArray())
|
||||
func (v *V) InsertArray() Inserter {
|
||||
return v.Insert(NewArray())
|
||||
}
|
||||
|
||||
func (ins *insert) Before(firstParam any, otherParams ...any) (*V, error) {
|
||||
if ins.err != nil {
|
||||
return &V{}, ins.err
|
||||
}
|
||||
if ok, p1, p2 := isSliceAndExtractDividedParams(firstParam); ok {
|
||||
if len(otherParams) > 0 {
|
||||
return &V{}, ErrMultipleParamNotSupportedWithIfSliceOrArrayGiven
|
||||
}
|
||||
return ins.Before(p1, p2...)
|
||||
}
|
||||
v := ins.v
|
||||
c := ins.c
|
||||
if v.valueType == NotExist {
|
||||
return &V{}, ErrValueUninitialized
|
||||
}
|
||||
|
||||
// this is the last iteration
|
||||
paramCount := len(otherParams)
|
||||
if paramCount == 0 {
|
||||
if v.valueType != Array {
|
||||
return &V{}, ErrNotArrayValue
|
||||
}
|
||||
|
||||
pos, err := anyToInt(firstParam)
|
||||
if err != nil {
|
||||
return &V{}, err
|
||||
}
|
||||
|
||||
pos = posAtIndexForInsertBefore(v, pos)
|
||||
if pos < 0 {
|
||||
return &V{}, ErrOutOfRange
|
||||
}
|
||||
insertToArr(v, pos, c)
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// this is not the last iteration
|
||||
child, err := v.GetArray(firstParam, otherParams[:paramCount-1]...)
|
||||
if err != nil {
|
||||
return &V{}, err
|
||||
}
|
||||
|
||||
childIns := &insert{
|
||||
v: child,
|
||||
c: c,
|
||||
}
|
||||
return childIns.Before(otherParams[paramCount-1])
|
||||
}
|
||||
|
||||
func (ins *insert) After(firstParam any, otherParams ...any) (*V, error) {
|
||||
if ins.err != nil {
|
||||
return &V{}, ins.err
|
||||
}
|
||||
if ok, p1, p2 := isSliceAndExtractDividedParams(firstParam); ok {
|
||||
if len(otherParams) > 0 {
|
||||
return &V{}, ErrMultipleParamNotSupportedWithIfSliceOrArrayGiven
|
||||
}
|
||||
return ins.After(p1, p2...)
|
||||
}
|
||||
v := ins.v
|
||||
c := ins.c
|
||||
if nil == v || v.valueType == NotExist {
|
||||
return &V{}, ErrValueUninitialized
|
||||
}
|
||||
|
||||
// this is the last iteration
|
||||
paramCount := len(otherParams)
|
||||
if paramCount == 0 {
|
||||
if v.valueType != Array {
|
||||
return &V{}, ErrNotArrayValue
|
||||
}
|
||||
|
||||
pos, err := anyToInt(firstParam)
|
||||
if err != nil {
|
||||
return &V{}, err
|
||||
}
|
||||
|
||||
pos, appendToEnd := posAtIndexForInsertAfter(v, pos)
|
||||
if pos < 0 {
|
||||
return &V{}, ErrOutOfRange
|
||||
}
|
||||
if appendToEnd {
|
||||
appendToArr(v, c)
|
||||
} else {
|
||||
insertToArr(v, pos, c)
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// this is not the last iteration
|
||||
child, err := v.GetArray(firstParam, otherParams[:paramCount-1]...)
|
||||
if err != nil {
|
||||
return &V{}, err
|
||||
}
|
||||
|
||||
childIns := &insert{
|
||||
v: child,
|
||||
c: c,
|
||||
}
|
||||
return childIns.After(otherParams[paramCount-1])
|
||||
}
|
||||
|
||||
func insertToArr(v *V, pos int, child *V) {
|
||||
v.children.arr = append(v.children.arr, nil)
|
||||
copy(v.children.arr[pos+1:], v.children.arr[pos:])
|
||||
v.children.arr[pos] = child
|
||||
}
|
||||
|
||||
// ================ APPEND ================
|
||||
|
||||
// MARK: APPEND
|
||||
|
||||
// Appender type is for InTheEnd() or InTheBeginning() function.
|
||||
//
|
||||
// Appender 类型是用于 InTheEnd() 和 InTheBeginning() 函数的。使用者可以不用关注这个类型。
|
||||
// 并且这个类型只应当由 V.Append() 产生。
|
||||
type Appender interface {
|
||||
InTheBeginning(params ...any) (*V, error)
|
||||
InTheEnd(params ...any) (*V, error)
|
||||
}
|
||||
|
||||
type appender struct {
|
||||
v *V
|
||||
c *V // child
|
||||
|
||||
err error
|
||||
}
|
||||
|
||||
// Append starts appending a child JSON value to a JSON array.
|
||||
//
|
||||
// Append 开始将一个 JSON 值添加到一个数组中。需结合 InTheEnd() 和 InTheBeginning() 函数使用。
|
||||
func (v *V) Append(child any) Appender {
|
||||
var ch *V
|
||||
var err error
|
||||
|
||||
if child == nil {
|
||||
ch = NewNull()
|
||||
} else if childV, ok := child.(*V); ok {
|
||||
ch = childV
|
||||
} else {
|
||||
ch, err = Import(child)
|
||||
}
|
||||
return &appender{
|
||||
v: v,
|
||||
c: ch,
|
||||
err: err,
|
||||
}
|
||||
}
|
||||
|
||||
// AppendString is equivalent to Append(jsonvalue.NewString(s))
|
||||
//
|
||||
// AppendString 等价于 Append(jsonvalue.NewString(s))
|
||||
func (v *V) AppendString(s string) Appender {
|
||||
return v.Append(NewString(s))
|
||||
}
|
||||
|
||||
// AppendBytes is equivalent to Append(jsonvalue.NewBytes(b))
|
||||
//
|
||||
// AppendBytes 等价于 Append(jsonvalue.NewBytes(b))
|
||||
func (v *V) AppendBytes(b []byte) Appender {
|
||||
return v.Append(NewBytes(b))
|
||||
}
|
||||
|
||||
// AppendBool is equivalent to Append(jsonvalue.NewBool(b))
|
||||
//
|
||||
// AppendBool 等价于 Append(jsonvalue.NewBool(b))
|
||||
func (v *V) AppendBool(b bool) Appender {
|
||||
return v.Append(NewBool(b))
|
||||
}
|
||||
|
||||
// AppendInt is equivalent to Append(jsonvalue.NewInt(b))
|
||||
//
|
||||
// AppendInt 等价于 Append(jsonvalue.NewInt(b))
|
||||
func (v *V) AppendInt(i int) Appender {
|
||||
return v.Append(NewInt(i))
|
||||
}
|
||||
|
||||
// AppendInt64 is equivalent to Append(jsonvalue.NewInt64(b))
|
||||
//
|
||||
// AppendInt64 等价于 Append(jsonvalue.NewInt64(b))
|
||||
func (v *V) AppendInt64(i int64) Appender {
|
||||
return v.Append(NewInt64(i))
|
||||
}
|
||||
|
||||
// AppendInt32 is equivalent to Append(jsonvalue.NewInt32(b))
|
||||
//
|
||||
// AppendInt32 等价于 Append(jsonvalue.NewInt32(b))
|
||||
func (v *V) AppendInt32(i int32) Appender {
|
||||
return v.Append(NewInt32(i))
|
||||
}
|
||||
|
||||
// AppendUint is equivalent to Append(jsonvalue.NewUint(b))
|
||||
//
|
||||
// AppendUint 等价于 Append(jsonvalue.NewUint(b))
|
||||
func (v *V) AppendUint(u uint) Appender {
|
||||
return v.Append(NewUint(u))
|
||||
}
|
||||
|
||||
// AppendUint64 is equivalent to Append(jsonvalue.NewUint64(b))
|
||||
//
|
||||
// AppendUint64 等价于 Append(jsonvalue.NewUint64(b))
|
||||
func (v *V) AppendUint64(u uint64) Appender {
|
||||
return v.Append(NewUint64(u))
|
||||
}
|
||||
|
||||
// AppendUint32 is equivalent to Append(jsonvalue.NewUint32(b))
|
||||
//
|
||||
// AppendUint32 等价于 Append(jsonvalue.NewUint32(b))
|
||||
func (v *V) AppendUint32(u uint32) Appender {
|
||||
return v.Append(NewUint32(u))
|
||||
}
|
||||
|
||||
// AppendFloat64 is equivalent to Append(jsonvalue.NewFloat64(b))
|
||||
//
|
||||
// AppendUint32 等价于 Append(jsonvalue.NewUint32(b))
|
||||
func (v *V) AppendFloat64(f float64) Appender {
|
||||
return v.Append(NewFloat64(f))
|
||||
}
|
||||
|
||||
// AppendFloat32 is equivalent to Append(jsonvalue.NewFloat32(b))
|
||||
//
|
||||
// AppendFloat32 等价于 Append(jsonvalue.NewFloat32(b))
|
||||
func (v *V) AppendFloat32(f float32) Appender {
|
||||
return v.Append(NewFloat32(f))
|
||||
}
|
||||
|
||||
// AppendNull is equivalent to Append(jsonvalue.NewNull())
|
||||
//
|
||||
// AppendNull 等价于 Append(jsonvalue.NewNull())
|
||||
func (v *V) AppendNull() Appender {
|
||||
return v.Append(NewNull())
|
||||
}
|
||||
|
||||
// AppendObject is equivalent to Append(jsonvalue.NewObject())
|
||||
//
|
||||
// AppendObject 等价于 Append(jsonvalue.NewObject())
|
||||
func (v *V) AppendObject() Appender {
|
||||
return v.Append(NewObject())
|
||||
}
|
||||
|
||||
// AppendArray is equivalent to Append(jsonvalue.NewArray())
|
||||
//
|
||||
// AppendArray 等价于 Append(jsonvalue.NewArray())
|
||||
func (v *V) AppendArray() Appender {
|
||||
return v.Append(NewArray())
|
||||
}
|
||||
|
||||
// InTheBeginning completes the following operation of Append().
|
||||
//
|
||||
// InTheBeginning 函数将 Append 函数指定的 JSON 值,添加到参数指定的数组的最前端
|
||||
func (apd *appender) InTheBeginning(params ...any) (*V, error) {
|
||||
v := apd.v
|
||||
c := apd.c
|
||||
if nil == v || v.valueType == NotExist {
|
||||
return &V{}, ErrValueUninitialized
|
||||
}
|
||||
|
||||
// this is the last iteration
|
||||
paramCount := len(params)
|
||||
if paramCount == 0 {
|
||||
if v.valueType != Array {
|
||||
return &V{}, ErrNotArrayValue
|
||||
}
|
||||
if v.Len() == 0 {
|
||||
appendToArr(v, c)
|
||||
} else {
|
||||
insertToArr(v, 0, c)
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
if ok, p := isSliceAndExtractJointParams(params[0]); ok {
|
||||
if len(params) > 1 {
|
||||
return &V{}, ErrMultipleParamNotSupportedWithIfSliceOrArrayGiven
|
||||
}
|
||||
return apd.InTheBeginning(p...)
|
||||
}
|
||||
|
||||
// this is not the last iteration
|
||||
child, err := v.GetArray(params[0], params[1:paramCount]...)
|
||||
if err != nil {
|
||||
if !errors.Is(err, ErrNotFound) {
|
||||
return &V{}, err
|
||||
}
|
||||
child, err = v.SetArray().At(params[0], params[1:]...)
|
||||
if err != nil {
|
||||
return &V{}, err
|
||||
}
|
||||
}
|
||||
|
||||
if child.Len() == 0 {
|
||||
appendToArr(child, c)
|
||||
} else {
|
||||
insertToArr(child, 0, c)
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// InTheEnd completes the following operation of Append().
|
||||
//
|
||||
// InTheEnd 函数将 Append 函数指定的 JSON 值,添加到参数指定的数组的最后面
|
||||
func (apd *appender) InTheEnd(params ...any) (*V, error) {
|
||||
v := apd.v
|
||||
c := apd.c
|
||||
if v.valueType == NotExist {
|
||||
return &V{}, ErrValueUninitialized
|
||||
}
|
||||
|
||||
// this is the last iteration
|
||||
paramCount := len(params)
|
||||
if paramCount == 0 {
|
||||
if v.valueType != Array {
|
||||
return &V{}, ErrNotArrayValue
|
||||
}
|
||||
|
||||
appendToArr(v, c)
|
||||
return c, nil
|
||||
}
|
||||
if ok, p := isSliceAndExtractJointParams(params[0]); ok {
|
||||
if len(params) > 1 {
|
||||
return &V{}, ErrMultipleParamNotSupportedWithIfSliceOrArrayGiven
|
||||
}
|
||||
return apd.InTheEnd(p...)
|
||||
}
|
||||
|
||||
// this is not the last iteration
|
||||
child, err := v.GetArray(params[0], params[1:paramCount]...)
|
||||
if err != nil {
|
||||
if !errors.Is(err, ErrNotFound) {
|
||||
return &V{}, err
|
||||
}
|
||||
child, err = v.SetArray().At(params[0], params[1:]...)
|
||||
if err != nil {
|
||||
return &V{}, err
|
||||
}
|
||||
}
|
||||
|
||||
appendToArr(child, c)
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// ================ DELETE ================
|
||||
|
||||
// MARK: DELETE
|
||||
|
||||
func delFromObjectChildren(v *V, caseless bool, key string) (exist bool) {
|
||||
_, exist = v.children.object[key]
|
||||
if exist {
|
||||
delete(v.children.object, key)
|
||||
delCaselessKey(v, key)
|
||||
return true
|
||||
}
|
||||
|
||||
if !caseless {
|
||||
return false
|
||||
}
|
||||
|
||||
initCaselessStorage(v)
|
||||
|
||||
lowerKey := strings.ToLower(key)
|
||||
keys, exist := v.children.lowerCaseKeys[lowerKey]
|
||||
if !exist {
|
||||
return false
|
||||
}
|
||||
|
||||
for actualKey := range keys {
|
||||
_, exist = v.children.object[actualKey]
|
||||
if exist {
|
||||
delete(v.children.object, actualKey)
|
||||
delCaselessKey(v, actualKey)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Delete deletes specified JSON value. For example, parameters ("data", "list") identifies deleting value in data.list.
|
||||
// While ("list", 1) means deleting the second element from the "list" array.
|
||||
//
|
||||
// Delete 从 JSON 中删除参数指定的对象。比如参数 ("data", "list") 表示删除 data.list 值;参数 ("list", 1) 则表示删除 list
|
||||
// 数组的第2(从1算起)个值。
|
||||
func (v *V) Delete(firstParam any, otherParams ...any) error {
|
||||
return v.delete(false, firstParam, otherParams...)
|
||||
}
|
||||
|
||||
func (v *V) delete(caseless bool, firstParam any, otherParams ...any) error {
|
||||
if ok, p1, p2 := isSliceAndExtractDividedParams(firstParam); ok {
|
||||
if len(otherParams) > 0 {
|
||||
return ErrMultipleParamNotSupportedWithIfSliceOrArrayGiven
|
||||
}
|
||||
return v.delete(caseless, p1, p2...)
|
||||
}
|
||||
|
||||
paramCount := len(otherParams)
|
||||
if paramCount == 0 {
|
||||
return deleteInCurrentValue(v, caseless, firstParam)
|
||||
}
|
||||
|
||||
child, err := get(v, caseless, firstParam, otherParams[:paramCount-1]...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// if child == nil {
|
||||
// return ErrNotFound
|
||||
// }
|
||||
|
||||
return child.delete(caseless, otherParams[paramCount-1])
|
||||
}
|
||||
|
||||
func deleteInCurrentValue(v *V, caseless bool, param any) error {
|
||||
switch v.valueType {
|
||||
case Object:
|
||||
return deleteInCurrentObject(v, caseless, param)
|
||||
case Array:
|
||||
return deleteInCurrentArray(v, param)
|
||||
default:
|
||||
// else, this is an object value
|
||||
return fmt.Errorf("%v type does not supports Delete()", v.valueType)
|
||||
}
|
||||
}
|
||||
|
||||
func deleteInCurrentObject(v *V, caseless bool, param any) error {
|
||||
// string expected
|
||||
key, err := anyToString(param)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if exist := delFromObjectChildren(v, caseless, key); !exist {
|
||||
return ErrNotFound
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func deleteInCurrentArray(v *V, param any) error {
|
||||
// integer expected
|
||||
pos, err := anyToInt(param)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pos = posAtIndexForRead(v, pos)
|
||||
if pos < 0 {
|
||||
return ErrOutOfRange
|
||||
}
|
||||
deleteInArr(v, pos)
|
||||
return nil
|
||||
}
|
||||
|
||||
func deleteInArr(v *V, pos int) {
|
||||
le := len(v.children.arr)
|
||||
v.children.arr[pos] = nil
|
||||
copy(v.children.arr[pos:], v.children.arr[pos+1:])
|
||||
v.children.arr = v.children.arr[:le-1]
|
||||
}
|
245
vendor/github.com/Andrew-M-C/go.jsonvalue/insert_append_delete_must.go
generated
vendored
Normal file
245
vendor/github.com/Andrew-M-C/go.jsonvalue/insert_append_delete_must.go
generated
vendored
Normal file
@ -0,0 +1,245 @@
|
||||
package jsonvalue
|
||||
|
||||
// ================ INSERT ================
|
||||
|
||||
// MustInserter is just like Inserter, but not returning sub-value or error.
|
||||
type MustInserter interface {
|
||||
// After completes the following operation of Insert(). It inserts value AFTER
|
||||
// specified position.
|
||||
//
|
||||
// The last parameter identifies the position where a new JSON is inserted after,
|
||||
// it should ba an integer, no matter signed or unsigned. If the position is
|
||||
// zero or positive integer, it tells the index of an array. If the position
|
||||
// is negative, it tells the backward index of an array.
|
||||
//
|
||||
// For example, 0 represents the first, and -2 represents the second last.
|
||||
//
|
||||
// After 结束并完成 Insert() 函数的后续插入操作,表示插入到指定位置的前面。
|
||||
//
|
||||
// 在 Before 函数的最后一个参数指定了被插入的 JSON 数组的位置,这个参数应当是一个整型
|
||||
// (有无符号类型均可)。
|
||||
// 如果这个值等于0或者正整数,那么它指定的是在 JSON 数组中的位置(从0开始)。如果这个值是负数,
|
||||
// 那么它指定的是 JSON 数组中从最后一个位置开始算起的位置。
|
||||
//
|
||||
// 举例说明:0 表示第一个位置,而 -2 表示倒数第二个位置。
|
||||
After(firstParam any, otherParams ...any)
|
||||
|
||||
// Before completes the following operation of Insert(). It inserts value BEFORE
|
||||
// specified position.
|
||||
//
|
||||
// The last parameter identifies the position where a new JSON is inserted after,
|
||||
// it should ba an integer, no matter signed or unsigned. If the position is
|
||||
// zero or positive integer, it tells the index of an array. If the position
|
||||
// is negative, it tells the backward index of an array.
|
||||
//
|
||||
// For example, 0 represents the first, and -2 represents the second last.
|
||||
//
|
||||
// Before 结束并完成 Insert() 函数的后续插入操作,表示插入到指定位置的后面。
|
||||
//
|
||||
// 在 Before 函数的最后一个参数指定了被插入的 JSON 数组的位置,这个参数应当是一个整型
|
||||
// (有无符号类型均可)。
|
||||
// 如果这个值等于0或者正整数,那么它指定的是在 JSON 数组中的位置(从0开始)。如果这个值是负数,
|
||||
// 那么它指定的是 JSON 数组中从最后一个位置开始算起的位置。
|
||||
//
|
||||
// 举例说明:0 表示第一个位置,而 -2 表示倒数第二个位置。
|
||||
Before(firstParam any, otherParams ...any)
|
||||
}
|
||||
|
||||
type mInsert struct {
|
||||
inserter Inserter
|
||||
}
|
||||
|
||||
// MustInsert is just like Insert, but not returning sub-value or error.
|
||||
func (v *V) MustInsert(child any) MustInserter {
|
||||
ins := v.Insert(child)
|
||||
return &mInsert{
|
||||
inserter: ins,
|
||||
}
|
||||
}
|
||||
|
||||
// MustInsertString is just like InsertString, but not returning sub-value or error.
|
||||
func (v *V) MustInsertString(s string) MustInserter {
|
||||
return v.MustInsert(NewString(s))
|
||||
}
|
||||
|
||||
// MustInsertBool is just like InsertBool, but not returning sub-value or error.
|
||||
func (v *V) MustInsertBool(b bool) MustInserter {
|
||||
return v.MustInsert(NewBool(b))
|
||||
}
|
||||
|
||||
// MustInsertInt is just like InsertInt, but not returning sub-value or error.
|
||||
func (v *V) MustInsertInt(i int) MustInserter {
|
||||
return v.MustInsert(NewInt(i))
|
||||
}
|
||||
|
||||
// MustInsertInt64 is just like InsertInt64, but not returning sub-value or error.
|
||||
func (v *V) MustInsertInt64(i int64) MustInserter {
|
||||
return v.MustInsert(NewInt64(i))
|
||||
}
|
||||
|
||||
// MustInsertInt32 is just like InsertInt32, but not returning sub-value or error.
|
||||
func (v *V) MustInsertInt32(i int32) MustInserter {
|
||||
return v.MustInsert(NewInt32(i))
|
||||
}
|
||||
|
||||
// MustInsertUint is just like InsertUint, but not returning sub-value or error.
|
||||
func (v *V) MustInsertUint(u uint) MustInserter {
|
||||
return v.MustInsert(NewUint(u))
|
||||
}
|
||||
|
||||
// MustInsertUint64 is just like InsertUint64, but not returning sub-value or error.
|
||||
func (v *V) MustInsertUint64(u uint64) MustInserter {
|
||||
return v.MustInsert(NewUint64(u))
|
||||
}
|
||||
|
||||
// MustInsertUint32 is just like InsertUint32, but not returning sub-value or error.
|
||||
func (v *V) MustInsertUint32(u uint32) MustInserter {
|
||||
return v.MustInsert(NewUint32(u))
|
||||
}
|
||||
|
||||
// MustInsertFloat64 is just like InsertFloat64, but not returning sub-value or error.
|
||||
func (v *V) MustInsertFloat64(f float64) MustInserter {
|
||||
return v.MustInsert(NewFloat64(f))
|
||||
}
|
||||
|
||||
// MustInsertFloat32 is just like InsertFloat32, but not returning sub-value or error.
|
||||
func (v *V) MustInsertFloat32(f float32) MustInserter {
|
||||
return v.MustInsert(NewFloat32(f))
|
||||
}
|
||||
|
||||
// MustInsertNull is just like InsertNull, but not returning sub-value or error.
|
||||
func (v *V) MustInsertNull() MustInserter {
|
||||
return v.MustInsert(NewNull())
|
||||
}
|
||||
|
||||
// MustInsertObject is just like InsertObject, but not returning sub-value or error.
|
||||
func (v *V) MustInsertObject() MustInserter {
|
||||
return v.MustInsert(NewObject())
|
||||
}
|
||||
|
||||
// MustInsertArray is just like InsertArray, but not returning sub-value or error.
|
||||
func (v *V) MustInsertArray() MustInserter {
|
||||
return v.MustInsert(NewArray())
|
||||
}
|
||||
|
||||
func (ins *mInsert) Before(firstParam any, otherParams ...any) {
|
||||
_, _ = ins.inserter.Before(firstParam, otherParams...)
|
||||
}
|
||||
|
||||
func (ins *mInsert) After(firstParam any, otherParams ...any) {
|
||||
_, _ = ins.inserter.After(firstParam, otherParams...)
|
||||
}
|
||||
|
||||
// ================ APPEND ================
|
||||
|
||||
// MustAppender is just like Appender, but not returning sub-value or error.
|
||||
type MustAppender interface {
|
||||
// InTheBeginning completes the following operation of Append().
|
||||
//
|
||||
// InTheBeginning 函数将 Append 函数指定的 JSON 值,添加到参数指定的数组的最前端
|
||||
InTheBeginning(params ...any)
|
||||
|
||||
// InTheEnd completes the following operation of Append().
|
||||
//
|
||||
// InTheEnd 函数将 Append 函数指定的 JSON 值,添加到参数指定的数组的最后面
|
||||
InTheEnd(params ...any)
|
||||
}
|
||||
|
||||
type mAppender struct {
|
||||
appender Appender
|
||||
}
|
||||
|
||||
// Append starts appending a child JSON value to a JSON array.
|
||||
//
|
||||
// Append 开始将一个 JSON 值添加到一个数组中。需结合 InTheEnd() 和 InTheBeginning() 函数使用。
|
||||
func (v *V) MustAppend(child any) MustAppender {
|
||||
a := v.Append(child)
|
||||
return &mAppender{
|
||||
appender: a,
|
||||
}
|
||||
}
|
||||
|
||||
// MustAppendString is just like AppendString, but not returning sub-value or error.
|
||||
func (v *V) MustAppendString(s string) MustAppender {
|
||||
return v.MustAppend(NewString(s))
|
||||
}
|
||||
|
||||
// MustAppendBytes is just like AppendBytes, but not returning sub-value or error.
|
||||
func (v *V) MustAppendBytes(b []byte) MustAppender {
|
||||
return v.MustAppend(NewBytes(b))
|
||||
}
|
||||
|
||||
// MustAppendBool is just like AppendBool, but not returning sub-value or error.
|
||||
func (v *V) MustAppendBool(b bool) MustAppender {
|
||||
return v.MustAppend(NewBool(b))
|
||||
}
|
||||
|
||||
// MustAppendInt is just like AppendInt, but not returning sub-value or error.
|
||||
func (v *V) MustAppendInt(i int) MustAppender {
|
||||
return v.MustAppend(NewInt(i))
|
||||
}
|
||||
|
||||
// MustAppendInt64 is just like AppendInt64, but not returning sub-value or error.
|
||||
func (v *V) MustAppendInt64(i int64) MustAppender {
|
||||
return v.MustAppend(NewInt64(i))
|
||||
}
|
||||
|
||||
// MustAppendInt32 is just like AppendInt32, but not returning sub-value or error.
|
||||
func (v *V) MustAppendInt32(i int32) MustAppender {
|
||||
return v.MustAppend(NewInt32(i))
|
||||
}
|
||||
|
||||
// MustAppendUint is just like AppendUint, but not returning sub-value or error.
|
||||
func (v *V) MustAppendUint(u uint) MustAppender {
|
||||
return v.MustAppend(NewUint(u))
|
||||
}
|
||||
|
||||
// MustAppendUint64 is just like AppendUint64, but not returning sub-value or error.
|
||||
func (v *V) MustAppendUint64(u uint64) MustAppender {
|
||||
return v.MustAppend(NewUint64(u))
|
||||
}
|
||||
|
||||
// MustAppendUint32 is just like AppendUint32, but not returning sub-value or error.
|
||||
func (v *V) MustAppendUint32(u uint32) MustAppender {
|
||||
return v.MustAppend(NewUint32(u))
|
||||
}
|
||||
|
||||
// MustAppendFloat64 is just like AppendFloat64, but not returning sub-value or error.
|
||||
func (v *V) MustAppendFloat64(f float64) MustAppender {
|
||||
return v.MustAppend(NewFloat64(f))
|
||||
}
|
||||
|
||||
// MustAppendFloat32 is just like AppendFloat32, but not returning sub-value or error.
|
||||
func (v *V) MustAppendFloat32(f float32) MustAppender {
|
||||
return v.MustAppend(NewFloat32(f))
|
||||
}
|
||||
|
||||
// MustAppendNull is just like AppendNull, but not returning sub-value or error.
|
||||
func (v *V) MustAppendNull() MustAppender {
|
||||
return v.MustAppend(NewNull())
|
||||
}
|
||||
|
||||
// MustAppendObject is just like AppendObject, but not returning sub-value or error.
|
||||
func (v *V) MustAppendObject() MustAppender {
|
||||
return v.MustAppend(NewObject())
|
||||
}
|
||||
|
||||
// MustAppendArray is just like AppendArray, but not returning sub-value or error.
|
||||
func (v *V) MustAppendArray() MustAppender {
|
||||
return v.MustAppend(NewArray())
|
||||
}
|
||||
|
||||
func (apd *mAppender) InTheBeginning(params ...any) {
|
||||
_, _ = apd.appender.InTheBeginning(params...)
|
||||
}
|
||||
|
||||
func (apd *mAppender) InTheEnd(params ...any) {
|
||||
_, _ = apd.appender.InTheEnd(params...)
|
||||
}
|
||||
|
||||
// ================ DELETE ================
|
||||
|
||||
// MustDelete is just like Delete, but not returning error.
|
||||
func (v *V) MustDelete(firstParam any, otherParams ...any) {
|
||||
_ = v.Delete(firstParam, otherParams...)
|
||||
}
|
18
vendor/github.com/Andrew-M-C/go.jsonvalue/internal/buffer/buffer.go
generated
vendored
Normal file
18
vendor/github.com/Andrew-M-C/go.jsonvalue/internal/buffer/buffer.go
generated
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
// Package buffer implements a marshaling buffer for jsonvalue
|
||||
package buffer
|
||||
|
||||
// Buffer defines a buffer type
|
||||
type Buffer interface {
|
||||
WriteByte(byte) error
|
||||
Write(d []byte) (int, error)
|
||||
WriteString(s string) (int, error)
|
||||
WriteRune(r rune) (int, error)
|
||||
Bytes() []byte
|
||||
}
|
||||
|
||||
// NewBuffer returns a buffer
|
||||
func NewBuffer() Buffer {
|
||||
return &buffer{
|
||||
buff: make([]byte, 0, 4096),
|
||||
}
|
||||
}
|
32
vendor/github.com/Andrew-M-C/go.jsonvalue/internal/buffer/buffer_impl.go
generated
vendored
Normal file
32
vendor/github.com/Andrew-M-C/go.jsonvalue/internal/buffer/buffer_impl.go
generated
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
package buffer
|
||||
|
||||
import (
|
||||
"github.com/Andrew-M-C/go.jsonvalue/internal/unsafe"
|
||||
)
|
||||
|
||||
type buffer struct {
|
||||
buff []byte
|
||||
}
|
||||
|
||||
func (b *buffer) WriteByte(c byte) error {
|
||||
b.buff = append(b.buff, c)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *buffer) Write(d []byte) (int, error) {
|
||||
b.buff = append(b.buff, d...)
|
||||
return len(d), nil
|
||||
}
|
||||
|
||||
func (b *buffer) WriteString(s string) (int, error) {
|
||||
d := unsafe.StoB(s)
|
||||
return b.Write(d)
|
||||
}
|
||||
|
||||
func (b *buffer) WriteRune(r rune) (int, error) {
|
||||
return b.WriteString(string(r))
|
||||
}
|
||||
|
||||
func (b *buffer) Bytes() []byte {
|
||||
return b.buff
|
||||
}
|
1
vendor/github.com/Andrew-M-C/go.jsonvalue/internal/buffer/buffer_internal.go
generated
vendored
Normal file
1
vendor/github.com/Andrew-M-C/go.jsonvalue/internal/buffer/buffer_internal.go
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
package buffer
|
18
vendor/github.com/Andrew-M-C/go.jsonvalue/internal/unsafe/unsafe.go
generated
vendored
Normal file
18
vendor/github.com/Andrew-M-C/go.jsonvalue/internal/unsafe/unsafe.go
generated
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
package unsafe
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// BtoS []byte to string
|
||||
func BtoS(b []byte) string {
|
||||
return *(*string)(unsafe.Pointer(&b))
|
||||
}
|
||||
|
||||
// StoB string to []byte
|
||||
func StoB(s string) []byte {
|
||||
sh := (*reflect.SliceHeader)(unsafe.Pointer(&s))
|
||||
sh.Cap = sh.Len
|
||||
return *(*[]byte)(unsafe.Pointer(sh))
|
||||
}
|
150
vendor/github.com/Andrew-M-C/go.jsonvalue/iteration.go
generated
vendored
Normal file
150
vendor/github.com/Andrew-M-C/go.jsonvalue/iteration.go
generated
vendored
Normal file
@ -0,0 +1,150 @@
|
||||
package jsonvalue
|
||||
|
||||
import "sort"
|
||||
|
||||
// Deprecated: ObjectIter is a deprecated type.
|
||||
type ObjectIter struct {
|
||||
K string
|
||||
V *V
|
||||
}
|
||||
|
||||
// Deprecated: ArrayIter is a deprecated type.
|
||||
type ArrayIter struct {
|
||||
I int
|
||||
V *V
|
||||
}
|
||||
|
||||
// RangeObjects goes through each children when this is an object value
|
||||
//
|
||||
// Return true in callback to continue range iteration, while false to break.
|
||||
//
|
||||
// 若当前 JSON 值是一个 object 类型时,RangeObjects 遍历所有的键值对。
|
||||
//
|
||||
// 在回调函数中返回 true 表示继续迭代,返回 false 表示退出迭代
|
||||
func (v *V) RangeObjects(callback func(k string, v *V) bool) {
|
||||
if !v.IsObject() {
|
||||
return
|
||||
}
|
||||
if nil == callback {
|
||||
return
|
||||
}
|
||||
|
||||
for k, c := range v.children.object {
|
||||
ok := callback(k, c.v)
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// RangeObjectsBySetSequence acts just like RangeObjects, but the key sequence
|
||||
// is arranged by when a key is set to the given object.
|
||||
//
|
||||
// RangeObjectsBySetSequence 类似于 RangeObjects 函数, 但是 key 的顺序会依照其被 set
|
||||
// 进这个 object 的顺序传递。
|
||||
func (v *V) RangeObjectsBySetSequence(callback func(k string, v *V) bool) {
|
||||
if !v.IsObject() {
|
||||
return
|
||||
}
|
||||
if nil == callback {
|
||||
return
|
||||
}
|
||||
|
||||
type keysAndID struct {
|
||||
k string
|
||||
id uint32
|
||||
v *V
|
||||
}
|
||||
|
||||
kvs := make([]keysAndID, 0, len(v.children.object))
|
||||
for k, child := range v.children.object {
|
||||
kvs = append(kvs, keysAndID{
|
||||
k: k,
|
||||
id: child.id,
|
||||
v: child.v,
|
||||
})
|
||||
}
|
||||
sort.Slice(kvs, func(i, j int) bool {
|
||||
return kvs[i].id <= kvs[j].id
|
||||
})
|
||||
|
||||
for _, kv := range kvs {
|
||||
ok := callback(kv.k, kv.v)
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Deprecated: IterObjects is deprecated, please Use ForRangeObj() instead.
|
||||
func (v *V) IterObjects() <-chan *ObjectIter {
|
||||
ch := make(chan *ObjectIter, len(v.children.object))
|
||||
|
||||
go func() {
|
||||
for k, c := range v.children.object {
|
||||
ch <- &ObjectIter{
|
||||
K: k,
|
||||
V: c.v,
|
||||
}
|
||||
}
|
||||
close(ch)
|
||||
}()
|
||||
return ch
|
||||
}
|
||||
|
||||
// ForRangeObj returns a map which can be used in for - range block to iteration KVs in a JSON object value.
|
||||
//
|
||||
// ForRangeObj 返回一个 map 类型,用于使用 for - range 块迭代 JSON 对象类型的子成员。
|
||||
func (v *V) ForRangeObj() map[string]*V {
|
||||
res := make(map[string]*V, len(v.children.object))
|
||||
for k, c := range v.children.object {
|
||||
res[k] = c.v
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// RangeArray goes through each children when this is an array value
|
||||
//
|
||||
// Return true in callback to continue range iteration, while false to break.
|
||||
//
|
||||
// 若当前 JSON 值是一个 array 类型时,RangeArray 遍历所有的数组成员。
|
||||
//
|
||||
// 在回调函数中返回 true 表示继续迭代,返回 false 表示退出迭代
|
||||
func (v *V) RangeArray(callback func(i int, v *V) bool) {
|
||||
if !v.IsArray() {
|
||||
return
|
||||
}
|
||||
if nil == callback {
|
||||
return
|
||||
}
|
||||
|
||||
for i, child := range v.children.arr {
|
||||
if ok := callback(i, child); !ok {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Deprecated: IterArray is deprecated, please Use ForRangeArr() instead.
|
||||
func (v *V) IterArray() <-chan *ArrayIter {
|
||||
c := make(chan *ArrayIter, len(v.children.arr))
|
||||
|
||||
go func() {
|
||||
for i, child := range v.children.arr {
|
||||
c <- &ArrayIter{
|
||||
I: i,
|
||||
V: child,
|
||||
}
|
||||
}
|
||||
close(c)
|
||||
}()
|
||||
return c
|
||||
}
|
||||
|
||||
// ForRangeArr returns a slice which can be used in for - range block to iteration KVs in a JSON array value.
|
||||
//
|
||||
// ForRangeObj 返回一个切片,用于使用 for - range 块迭代 JSON 数组类型的子成员。
|
||||
func (v *V) ForRangeArr() []*V {
|
||||
res := make([]*V, 0, len(v.children.arr))
|
||||
return append(res, v.children.arr...)
|
||||
}
|
598
vendor/github.com/Andrew-M-C/go.jsonvalue/jsonvalue.go
generated
vendored
Normal file
598
vendor/github.com/Andrew-M-C/go.jsonvalue/jsonvalue.go
generated
vendored
Normal file
@ -0,0 +1,598 @@
|
||||
// Package jsonvalue is for JSON parsing and setting. It is used in situations those
|
||||
// Go structures cannot achieve, or "map[string]any" could not do properly.
|
||||
//
|
||||
// As a quick start:
|
||||
//
|
||||
// v := jsonvalue.NewObject()
|
||||
// v.SetString("Hello, JSON").At("someObject", "someObject", "someObject", "message") // automatically create sub objects
|
||||
// fmt.Println(v.MustMarshalString()) // marshal to string type. Use MustMarshal if you want []byte instead.
|
||||
// // Output:
|
||||
// // {"someObject":{"someObject":{"someObject":{"message":"Hello, JSON!"}}}
|
||||
//
|
||||
// If you want to parse raw JSON data, use Unmarshal()
|
||||
//
|
||||
// raw := []byte(`{"message":"hello, world"}`)
|
||||
// v, err := jsonvalue.Unmarshal(raw)
|
||||
// s, _ := v.GetString("message")
|
||||
// fmt.Println(s)
|
||||
// // Output:
|
||||
// // hello, world
|
||||
//
|
||||
// jsonvalue 包用于 JSON 的解析(反序列化)和编码(序列化)。通常情况下我们用 struct 来处理
|
||||
// 结构化的 JSON,但是有时候使用 struct 不方便或者是功能不足的时候,go 一般而言使用的是
|
||||
// "map[string]any",但是后者也有很多不方便的地方。本包即是用于替代这些不方便的情况的。
|
||||
//
|
||||
// 快速上手:
|
||||
//
|
||||
// v := jsonvalue.NewObject()
|
||||
// v.SetString("Hello, JSON").At("someObject", "someObject", "someObject", "message") // 自动创建子成员
|
||||
// fmt.Println(v.MustMarshalString()) // 序列化为 string 类型,如果你要 []byte 类型,则使用 MustMarshal 函数。
|
||||
// // 输出:
|
||||
// // {"someObject":{"someObject":{"someObject":{"message":"Hello, JSON!"}}}
|
||||
//
|
||||
// 如果要反序列化原始的 JSON 文本,则使用 Unmarshal():
|
||||
//
|
||||
// raw := []byte(`{"message":"hello, world"}`)
|
||||
// v, err := jsonvalue.Unmarshal(raw)
|
||||
// s, _ := v.GetString("message")
|
||||
// fmt.Println(s)
|
||||
// // 输出:
|
||||
// // hello, world
|
||||
package jsonvalue
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/Andrew-M-C/go.jsonvalue/internal/unsafe"
|
||||
)
|
||||
|
||||
// ValueType identifying JSON value type
|
||||
type ValueType int
|
||||
|
||||
const (
|
||||
// NotExist type tells that this JSON value is not exist or legal
|
||||
NotExist ValueType = iota
|
||||
// String JSON string type
|
||||
String
|
||||
// Number JSON number type
|
||||
Number
|
||||
// Object JSON object type
|
||||
Object
|
||||
// Array JSON array type
|
||||
Array
|
||||
// Boolean JSON boolean type
|
||||
Boolean
|
||||
// Null JSON null type
|
||||
Null
|
||||
// Unknown unknown JSON type
|
||||
Unknown
|
||||
)
|
||||
|
||||
var typeStr = [Unknown + 1]string{
|
||||
"illegal",
|
||||
"string",
|
||||
"number",
|
||||
"object",
|
||||
"array",
|
||||
"boolean",
|
||||
"null",
|
||||
"unknown",
|
||||
}
|
||||
|
||||
// String show the type name of JSON
|
||||
func (t ValueType) String() string {
|
||||
if t > Unknown {
|
||||
t = NotExist
|
||||
} else if t < 0 {
|
||||
t = NotExist
|
||||
}
|
||||
return typeStr[int(t)]
|
||||
}
|
||||
|
||||
// ValueType returns the type of this JSON value.
|
||||
func (v *V) ValueType() ValueType {
|
||||
return v.valueType
|
||||
}
|
||||
|
||||
// V is the main type of jsonvalue, representing a JSON value.
|
||||
//
|
||||
// V 是 jsonvalue 的主类型,表示一个 JSON 值。
|
||||
type V struct {
|
||||
valueType ValueType
|
||||
|
||||
srcByte []byte
|
||||
|
||||
num num
|
||||
valueStr string
|
||||
valueBool bool
|
||||
children children
|
||||
}
|
||||
|
||||
type num struct {
|
||||
negative bool
|
||||
floated bool
|
||||
i64 int64
|
||||
u64 uint64
|
||||
f64 float64
|
||||
}
|
||||
|
||||
type childWithProperty struct {
|
||||
id uint32
|
||||
v *V
|
||||
}
|
||||
|
||||
type children struct {
|
||||
incrID uint32
|
||||
arr []*V
|
||||
object map[string]childWithProperty
|
||||
|
||||
// As official json package supports caseless key accessing, I decide to do it as well
|
||||
lowerCaseKeys map[string]map[string]struct{}
|
||||
}
|
||||
|
||||
func (c *children) deepCopy() children {
|
||||
res := children{
|
||||
incrID: c.incrID,
|
||||
}
|
||||
|
||||
// if length or arr > 0, this must be an array type
|
||||
if len(c.arr) > 0 {
|
||||
for _, v := range c.arr {
|
||||
res.arr = append(res.arr, v.deepCopy())
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// if this is an object?
|
||||
if c.object != nil {
|
||||
res.object = make(map[string]childWithProperty, len(c.object))
|
||||
for key, item := range c.object {
|
||||
res.object[key] = childWithProperty{
|
||||
id: item.id,
|
||||
v: item.v.deepCopy(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// no need to copy lowerCaseKeys because it could be rebuild after calling
|
||||
// Caseless() next time
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
func addCaselessKey(v *V, k string) {
|
||||
if v.children.lowerCaseKeys == nil {
|
||||
return
|
||||
}
|
||||
lowerK := strings.ToLower(k)
|
||||
keys, exist := v.children.lowerCaseKeys[lowerK]
|
||||
if !exist {
|
||||
keys = make(map[string]struct{})
|
||||
v.children.lowerCaseKeys[lowerK] = keys
|
||||
}
|
||||
keys[k] = struct{}{}
|
||||
}
|
||||
|
||||
func delCaselessKey(v *V, k string) {
|
||||
if v.children.lowerCaseKeys == nil {
|
||||
return
|
||||
}
|
||||
lowerK := strings.ToLower(k)
|
||||
keys, exist := v.children.lowerCaseKeys[lowerK]
|
||||
if !exist {
|
||||
return
|
||||
}
|
||||
|
||||
delete(keys, k)
|
||||
|
||||
if len(keys) == 0 {
|
||||
delete(v.children.lowerCaseKeys, lowerK)
|
||||
}
|
||||
}
|
||||
|
||||
// MustUnmarshalString just like UnmarshalString(). If error occurs, a JSON value
|
||||
// with "NotExist" type would be returned, which could do nothing and return nothing
|
||||
// in later use. It is useful to shorten codes.
|
||||
//
|
||||
// MustUnmarshalString 的逻辑与 UnmarshalString() 相同,不过如果错误的话,会返回一个类型未
|
||||
// "NotExist" 的 JSON 值,这个值在后续的操作中将无法返回有效的数据,或者是执行任何有效的操作。
|
||||
// 但起码不会导致程序 panic,便于使用短代码实现一些默认逻辑。
|
||||
func MustUnmarshalString(s string) *V {
|
||||
v, _ := UnmarshalString(s)
|
||||
return v
|
||||
}
|
||||
|
||||
// UnmarshalString is equivalent to Unmarshal([]byte(b)), but more efficient.
|
||||
//
|
||||
// UnmarshalString 等效于 Unmarshal([]byte(b)),但效率更高。
|
||||
func UnmarshalString(s string) (*V, error) {
|
||||
// reference: https://stackoverflow.com/questions/41591097/slice-bounds-out-of-range-when-using-unsafe-pointer
|
||||
// sh := (*reflect.StringHeader)(unsafe.Pointer(&s))
|
||||
// bh := reflect.SliceHeader{
|
||||
// Data: sh.Data,
|
||||
// Len: sh.Len,
|
||||
// Cap: sh.Len,
|
||||
// }
|
||||
// b := *(*[]byte)(unsafe.Pointer(&bh))
|
||||
b := []byte(s)
|
||||
return UnmarshalNoCopy(b)
|
||||
}
|
||||
|
||||
// MustUnmarshal just like Unmarshal(). If error occurs, a JSON value with "NotExist"
|
||||
// type would be returned, which could do nothing and return nothing in later use. It
|
||||
// is useful to shorten codes.
|
||||
//
|
||||
// MustUnmarshal 的逻辑与 Unmarshal() 相同,不过如果错误的话,会返回一个类型未 "NotExist" 的
|
||||
// JSON 值,这个值在后续的操作中将无法返回有效的数据,或者是执行任何有效的操作。但起码不会导致程序
|
||||
// panic,便于使用短代码实现一些默认逻辑。
|
||||
func MustUnmarshal(b []byte) *V {
|
||||
v, _ := Unmarshal(b)
|
||||
return v
|
||||
}
|
||||
|
||||
// Unmarshal parse raw bytes(encoded in UTF-8 or pure AscII) and returns a *V instance.
|
||||
//
|
||||
// Unmarshal 解析原始的字节类型数据(以 UTF-8 或纯 AscII 编码),并返回一个 *V 对象。
|
||||
func Unmarshal(b []byte) (ret *V, err error) {
|
||||
le := len(b)
|
||||
if le == 0 {
|
||||
return nil, ErrNilParameter
|
||||
}
|
||||
|
||||
trueB := make([]byte, len(b))
|
||||
copy(trueB, b)
|
||||
it := iter(trueB)
|
||||
p := newPool(len(b))
|
||||
ret, err = unmarshalWithIter(p, it, 0)
|
||||
p.release()
|
||||
return
|
||||
}
|
||||
|
||||
// MustUnmarshalNoCopy just like UnmarshalNoCopy(). If error occurs, a JSON value
|
||||
// with "NotExist" type would be returned, which could do nothing and return nothing
|
||||
// in later use. It is useful to shorten codes.
|
||||
//
|
||||
// MustUnmarshalNoCopy 的逻辑与 UnmarshalNoCopy() 相同,不过如果错误的话,会返回一个类型未
|
||||
// "NotExist" 的 JSON 值,这个值在后续的操作中将无法返回有效的数据,或者是执行任何有效的操作。
|
||||
// 但起码不会导致程序 panic,便于使用短代码实现一些默认逻辑。
|
||||
func MustUnmarshalNoCopy(b []byte) *V {
|
||||
v, _ := UnmarshalNoCopy(b)
|
||||
return v
|
||||
}
|
||||
|
||||
// UnmarshalNoCopy is same as Unmarshal, but it does not copy another []byte instance
|
||||
// for saving CPU time. But pay attention that the input []byte may be used as buffer
|
||||
// by jsonvalue and mey be modified.
|
||||
//
|
||||
// UnmarshalNoCopy 与 Unmarshal 相同,但是这个函数在解析过程中不会重新复制一个 []byte,对于大
|
||||
// json 的解析而言能够大大节省时间。但请注意传入的 []byte 变量可能会被 jsonvalue 用作缓冲区,并进行修改
|
||||
func UnmarshalNoCopy(b []byte) (ret *V, err error) {
|
||||
le := len(b)
|
||||
if le == 0 {
|
||||
return &V{}, ErrNilParameter
|
||||
}
|
||||
p := newPool(len(b))
|
||||
ret, err = unmarshalWithIter(p, iter(b), 0)
|
||||
p.release()
|
||||
return
|
||||
}
|
||||
|
||||
// ==== type access ====
|
||||
|
||||
// IsObject tells whether value is an object
|
||||
//
|
||||
// IsObject 判断当前值是不是一个对象类型
|
||||
func (v *V) IsObject() bool {
|
||||
return v.valueType == Object
|
||||
}
|
||||
|
||||
// IsArray tells whether value is an array
|
||||
//
|
||||
// IsArray 判断当前值是不是一个数组类型
|
||||
func (v *V) IsArray() bool {
|
||||
return v.valueType == Array
|
||||
}
|
||||
|
||||
// IsString tells whether value is a string
|
||||
//
|
||||
// IsString 判断当前值是不是一个字符串类型
|
||||
func (v *V) IsString() bool {
|
||||
return v.valueType == String
|
||||
}
|
||||
|
||||
// IsNumber tells whether value is a number
|
||||
//
|
||||
// IsNumber 判断当前值是不是一个数字类型
|
||||
func (v *V) IsNumber() bool {
|
||||
return v.valueType == Number
|
||||
}
|
||||
|
||||
// IsFloat tells whether value is a float point number. If there is no decimal point
|
||||
// in original text, it returns false while IsNumber returns true.
|
||||
//
|
||||
// IsFloat 判断当前值是不是一个浮点数类型。如果给定的数不包含小数点,那么即便是数字类型,该函数也会返回 false.
|
||||
func (v *V) IsFloat() bool {
|
||||
if v.valueType != Number {
|
||||
return false
|
||||
}
|
||||
return v.num.floated
|
||||
}
|
||||
|
||||
// IsInteger tells whether value is a fix point integer
|
||||
//
|
||||
// IsNumber 判断当前值是不是一个定点数整型
|
||||
func (v *V) IsInteger() bool {
|
||||
if v.valueType != Number {
|
||||
return false
|
||||
}
|
||||
return !(v.num.floated)
|
||||
}
|
||||
|
||||
// IsNegative tells whether value is a negative number
|
||||
//
|
||||
// IsNegative 判断当前值是不是一个负数
|
||||
func (v *V) IsNegative() bool {
|
||||
if v.valueType != Number {
|
||||
return false
|
||||
}
|
||||
return v.num.negative
|
||||
}
|
||||
|
||||
// IsPositive tells whether value is a positive number
|
||||
//
|
||||
// IsPositive 判断当前值是不是一个正数
|
||||
func (v *V) IsPositive() bool {
|
||||
if v.valueType != Number {
|
||||
return false
|
||||
}
|
||||
return !(v.num.negative)
|
||||
}
|
||||
|
||||
// GreaterThanInt64Max return true when ALL conditions below are met:
|
||||
// 1. It is a number value.
|
||||
// 2. It is a positive integer.
|
||||
// 3. Its value is greater than 0x7fffffffffffffff.
|
||||
//
|
||||
// GreaterThanInt64Max 判断当前值是否超出 int64 可表示的范围。当以下条件均成立时,返回 true,
|
||||
// 否则返回 false:
|
||||
// 1. 是一个数字类型值.
|
||||
// 2. 是一个正整型数字.
|
||||
// 3. 该正整数的值大于 0x7fffffffffffffff.
|
||||
func (v *V) GreaterThanInt64Max() bool {
|
||||
if v.valueType != Number {
|
||||
return false
|
||||
}
|
||||
if v.num.negative {
|
||||
return false
|
||||
}
|
||||
return v.num.u64 > 0x7fffffffffffffff
|
||||
}
|
||||
|
||||
// IsBoolean tells whether value is a boolean
|
||||
//
|
||||
// IsBoolean 判断当前值是不是一个布尔类型
|
||||
func (v *V) IsBoolean() bool {
|
||||
return v.valueType == Boolean
|
||||
}
|
||||
|
||||
// IsNull tells whether value is a null
|
||||
//
|
||||
// IsBoolean 判断当前值是不是一个空类型
|
||||
func (v *V) IsNull() bool {
|
||||
return v.valueType == Null
|
||||
}
|
||||
|
||||
// Bool returns represented bool value. If value is not boolean, returns false.
|
||||
//
|
||||
// Bool 返回布尔类型值。如果当前值不是布尔类型,则判断是否为 string,不是 string 返回 false;
|
||||
// 是 string 的话则返回字面值是否等于 true
|
||||
func (v *V) Bool() bool {
|
||||
if v.valueType == Boolean {
|
||||
return v.valueBool
|
||||
}
|
||||
b, _ := getBoolAndErrorFromValue(v)
|
||||
return b.valueBool
|
||||
}
|
||||
|
||||
// Int returns represented int value. If value is not a number, returns zero.
|
||||
//
|
||||
// Int 返回 int 类型值。如果当前值不是数字类型,则返回 0。
|
||||
func (v *V) Int() int {
|
||||
if v.valueType != Number {
|
||||
return getNumberFromNotNumberValue(v).Int()
|
||||
}
|
||||
return int(v.num.i64)
|
||||
}
|
||||
|
||||
// Uint returns represented uint value. If value is not a number, returns zero.
|
||||
//
|
||||
// Uint 返回 uint 类型值。如果当前值不是数字类型,则返回 0。
|
||||
func (v *V) Uint() uint {
|
||||
if v.valueType != Number {
|
||||
return getNumberFromNotNumberValue(v).Uint()
|
||||
}
|
||||
return uint(v.num.u64)
|
||||
}
|
||||
|
||||
// Int64 returns represented int64 value. If value is not a number, returns zero.
|
||||
//
|
||||
// Int64 返回 int64 类型值。如果当前值不是数字类型,则返回 0。
|
||||
func (v *V) Int64() int64 {
|
||||
if v.valueType != Number {
|
||||
return getNumberFromNotNumberValue(v).Int64()
|
||||
}
|
||||
return int64(v.num.i64)
|
||||
}
|
||||
|
||||
// Uint64 returns represented uint64 value. If value is not a number, returns zero.
|
||||
//
|
||||
// Uint64 返回 uint64 类型值。如果当前值不是数字类型,则返回 0。
|
||||
func (v *V) Uint64() uint64 {
|
||||
if v.valueType != Number {
|
||||
return getNumberFromNotNumberValue(v).Uint64()
|
||||
}
|
||||
return uint64(v.num.u64)
|
||||
}
|
||||
|
||||
// Int32 returns represented int32 value. If value is not a number, returns zero.
|
||||
//
|
||||
// Int32 返回 int32 类型值。如果当前值不是数字类型,则返回 0。
|
||||
func (v *V) Int32() int32 {
|
||||
if v.valueType != Number {
|
||||
return getNumberFromNotNumberValue(v).Int32()
|
||||
}
|
||||
return int32(v.num.i64)
|
||||
}
|
||||
|
||||
// Uint32 returns represented uint32 value. If value is not a number, returns zero.
|
||||
//
|
||||
// Uint32 返回 uint32 类型值。如果当前值不是数字类型,则返回 0。
|
||||
func (v *V) Uint32() uint32 {
|
||||
if v.valueType != Number {
|
||||
return getNumberFromNotNumberValue(v).Uint32()
|
||||
}
|
||||
return uint32(v.num.u64)
|
||||
}
|
||||
|
||||
// Float64 returns represented float64 value. If value is not a number, returns zero.
|
||||
//
|
||||
// Float64 返回 float64 类型值。如果当前值不是数字类型,则返回 0.0。
|
||||
func (v *V) Float64() float64 {
|
||||
if v.valueType != Number {
|
||||
return getNumberFromNotNumberValue(v).Float64()
|
||||
}
|
||||
return v.num.f64
|
||||
}
|
||||
|
||||
// Float32 returns represented float32 value. If value is not a number, returns zero.
|
||||
//
|
||||
// Float32 返回 float32 类型值。如果当前值不是数字类型,则返回 0.0。
|
||||
func (v *V) Float32() float32 {
|
||||
if v.valueType != Number {
|
||||
return getNumberFromNotNumberValue(v).Float32()
|
||||
}
|
||||
return float32(v.num.f64)
|
||||
}
|
||||
|
||||
// Bytes returns represented binary data which is encoded as Base64 string. []byte{}
|
||||
// would be returned if value is
|
||||
// not a string type or base64 decode failed.
|
||||
//
|
||||
// Bytes 返回以 Base64 编码在 string 类型中的二进制数据。如果当前值不是字符串类型,或者是 base64
|
||||
// 编码失败,则返回 []byte{}。
|
||||
func (v *V) Bytes() []byte {
|
||||
if v.valueType != String {
|
||||
return []byte{}
|
||||
}
|
||||
b, err := internal.b64.DecodeString(v.valueStr)
|
||||
if err != nil {
|
||||
return []byte{}
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func (v *V) deepCopy() *V {
|
||||
if v == nil {
|
||||
return &V{}
|
||||
}
|
||||
|
||||
switch v.valueType {
|
||||
default:
|
||||
// fallthrough
|
||||
// case NotExist, Unknown:
|
||||
return &V{}
|
||||
case String:
|
||||
return NewString(v.String())
|
||||
case Number:
|
||||
res := new(globalPool{}, Number)
|
||||
res.num = v.num
|
||||
res.srcByte = v.srcByte
|
||||
return res
|
||||
case Object:
|
||||
res := new(globalPool{}, Object)
|
||||
res.children = v.children.deepCopy()
|
||||
return res
|
||||
case Array:
|
||||
res := new(globalPool{}, Array)
|
||||
res.children = v.children.deepCopy()
|
||||
return res
|
||||
case Boolean:
|
||||
return NewBool(v.Bool())
|
||||
case Null:
|
||||
return NewNull()
|
||||
}
|
||||
}
|
||||
|
||||
type deepCopier interface {
|
||||
deepCopy() *V
|
||||
}
|
||||
|
||||
// String returns represented string value or the description for the jsonvalue.V
|
||||
// instance if it is not a string.
|
||||
//
|
||||
// String 返回 string 类型值。如果当前值不是字符串类型,则返回当前 *V 类型的描述说明。
|
||||
func (v *V) String() string {
|
||||
if v == nil {
|
||||
return "nil"
|
||||
}
|
||||
switch v.valueType {
|
||||
default:
|
||||
return ""
|
||||
case Null:
|
||||
return "null"
|
||||
case Number:
|
||||
if len(v.srcByte) > 0 {
|
||||
return unsafe.BtoS(v.srcByte)
|
||||
}
|
||||
return strconv.FormatFloat(v.num.f64, 'g', -1, 64)
|
||||
case String:
|
||||
return v.valueStr
|
||||
case Boolean:
|
||||
return formatBool(v.valueBool)
|
||||
case Object:
|
||||
return packObjChildren(v)
|
||||
case Array:
|
||||
return packArrChildren(v)
|
||||
}
|
||||
}
|
||||
|
||||
func packObjChildren(v *V) string {
|
||||
buf := bytes.Buffer{}
|
||||
bufObjChildren(v, &buf)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func bufObjChildren(v *V, buf *bytes.Buffer) {
|
||||
buf.WriteByte('{')
|
||||
i := 0
|
||||
for k, v := range v.children.object {
|
||||
if i > 0 {
|
||||
buf.WriteString(", ")
|
||||
}
|
||||
buf.WriteString(k)
|
||||
buf.WriteString(": ")
|
||||
buf.WriteString(v.v.String())
|
||||
i++
|
||||
}
|
||||
buf.WriteByte('}')
|
||||
}
|
||||
|
||||
func packArrChildren(v *V) string {
|
||||
buf := bytes.Buffer{}
|
||||
bufArrChildren(v, &buf)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func bufArrChildren(v *V, buf *bytes.Buffer) {
|
||||
buf.WriteByte('[')
|
||||
v.RangeArray(func(i int, v *V) bool {
|
||||
if i > 0 {
|
||||
buf.WriteString(", ")
|
||||
}
|
||||
buf.WriteString(v.String())
|
||||
return true
|
||||
})
|
||||
buf.WriteByte(']')
|
||||
}
|
112
vendor/github.com/Andrew-M-C/go.jsonvalue/jsonvalue_internal.go
generated
vendored
Normal file
112
vendor/github.com/Andrew-M-C/go.jsonvalue/jsonvalue_internal.go
generated
vendored
Normal file
@ -0,0 +1,112 @@
|
||||
package jsonvalue
|
||||
|
||||
import (
|
||||
"encoding"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
var internal = struct {
|
||||
b64 *base64.Encoding
|
||||
|
||||
defaultMarshalOption *Opt
|
||||
|
||||
predict struct {
|
||||
bytesPerValue uint64
|
||||
calcStorage uint64 // upper 32 bits - size; lower 32 bits - value count
|
||||
}
|
||||
|
||||
types struct {
|
||||
JSONMarshaler reflect.Type
|
||||
TextMarshaler reflect.Type
|
||||
}
|
||||
}{}
|
||||
|
||||
func init() {
|
||||
internal.b64 = base64.StdEncoding
|
||||
internal.defaultMarshalOption = emptyOptions()
|
||||
internalAddPredictSizePerValue(16, 1)
|
||||
|
||||
internal.types.JSONMarshaler = reflect.TypeOf((*json.Marshaler)(nil)).Elem()
|
||||
internal.types.TextMarshaler = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem()
|
||||
}
|
||||
|
||||
func internalLoadPredictSizePerValue() int {
|
||||
if n := atomic.LoadUint64(&internal.predict.bytesPerValue); n > 0 {
|
||||
return int(n)
|
||||
}
|
||||
|
||||
v := atomic.LoadUint64(&internal.predict.calcStorage)
|
||||
total := v >> 32
|
||||
num := v & 0xFFFFFFFF
|
||||
return int(total / num)
|
||||
}
|
||||
|
||||
func internalAddPredictSizePerValue(total, num int) {
|
||||
v := atomic.LoadUint64(&internal.predict.calcStorage)
|
||||
preTotal := v >> 32
|
||||
preNum := v & 0xFFFFFFFF
|
||||
|
||||
nextTotal := uint64(total) + preTotal
|
||||
nextNum := uint64(num) + preNum
|
||||
|
||||
if nextTotal < 0x7FFFFFFF {
|
||||
v := (nextTotal << 32) + nextNum
|
||||
atomic.StoreUint64(&internal.predict.calcStorage, v)
|
||||
return
|
||||
}
|
||||
|
||||
per := nextTotal / nextNum
|
||||
atomic.StoreUint64(&internal.predict.bytesPerValue, per)
|
||||
atomic.StoreUint64(&internal.predict.calcStorage, (per<<32)+1)
|
||||
}
|
||||
|
||||
type pool interface {
|
||||
get() *V
|
||||
}
|
||||
|
||||
type globalPool struct{}
|
||||
|
||||
func (globalPool) get() *V {
|
||||
return &V{}
|
||||
}
|
||||
|
||||
type poolImpl struct {
|
||||
pool []V
|
||||
|
||||
count int
|
||||
actual int // actual counted values
|
||||
|
||||
rawSize int
|
||||
}
|
||||
|
||||
func newPool(rawSize int) *poolImpl {
|
||||
per := internalLoadPredictSizePerValue()
|
||||
cnt := rawSize / per
|
||||
|
||||
p := &poolImpl{
|
||||
pool: make([]V, cnt),
|
||||
count: cnt,
|
||||
actual: 0,
|
||||
rawSize: rawSize,
|
||||
}
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *poolImpl) get() *V {
|
||||
if p.actual < p.count {
|
||||
v := &p.pool[p.actual]
|
||||
p.actual++
|
||||
return v
|
||||
}
|
||||
|
||||
p.actual++
|
||||
return globalPool{}.get()
|
||||
}
|
||||
|
||||
func (p *poolImpl) release() {
|
||||
internalAddPredictSizePerValue(p.rawSize, p.actual)
|
||||
}
|
325
vendor/github.com/Andrew-M-C/go.jsonvalue/marshal.go
generated
vendored
Normal file
325
vendor/github.com/Andrew-M-C/go.jsonvalue/marshal.go
generated
vendored
Normal file
@ -0,0 +1,325 @@
|
||||
package jsonvalue
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math"
|
||||
"strings"
|
||||
|
||||
"github.com/Andrew-M-C/go.jsonvalue/internal/buffer"
|
||||
"github.com/Andrew-M-C/go.jsonvalue/internal/unsafe"
|
||||
)
|
||||
|
||||
// MustMarshal is the same as Marshal. If error occurs, an empty byte slice will be returned.
|
||||
//
|
||||
// MustMarshal 与 Marshal 相同,但是当错误发生时,什么都不做,直接返回空数据
|
||||
func (v *V) MustMarshal(opts ...Option) []byte {
|
||||
ret, err := v.Marshal(opts...)
|
||||
if err != nil {
|
||||
return []byte{}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// MustMarshalString is the same as MarshalString, If error occurs, an empty byte slice will be returned.
|
||||
//
|
||||
// MustMarshalString 与 MarshalString 相同,但是当错误发生时,什么都不做,直接返回空数据
|
||||
func (v *V) MustMarshalString(opt ...Option) string {
|
||||
ret, err := v.MarshalString(opt...)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// Marshal returns marshaled bytes.
|
||||
//
|
||||
// Marshal 返回序列化后的 JSON 字节序列。
|
||||
func (v *V) Marshal(opts ...Option) (b []byte, err error) {
|
||||
if NotExist == v.valueType {
|
||||
return nil, ErrValueUninitialized
|
||||
}
|
||||
|
||||
buf := buffer.NewBuffer()
|
||||
opt := combineOptions(opts)
|
||||
|
||||
err = marshalToBuffer(v, nil, buf, opt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
b = buf.Bytes()
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// MarshalString is same with Marshal, but returns string. It is much more efficient than string(b).
|
||||
//
|
||||
// MarshalString 与 Marshal 相同, 不同的是返回 string 类型。它比 string(b) 操作更高效。
|
||||
func (v *V) MarshalString(opts ...Option) (s string, err error) {
|
||||
b, err := v.Marshal(opts...)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return unsafe.BtoS(b), nil
|
||||
}
|
||||
|
||||
func marshalToBuffer(v *V, parentInfo *ParentInfo, buf buffer.Buffer, opt *Opt) (err error) {
|
||||
switch v.valueType {
|
||||
default:
|
||||
// do nothing
|
||||
case String:
|
||||
marshalString(v, buf, opt)
|
||||
case Boolean:
|
||||
marshalBoolean(v, buf)
|
||||
case Number:
|
||||
err = marshalNumber(v, buf, opt)
|
||||
case Null:
|
||||
marshalNull(buf)
|
||||
case Object:
|
||||
marshalObject(v, parentInfo, buf, opt)
|
||||
case Array:
|
||||
marshalArray(v, parentInfo, buf, opt)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func marshalString(v *V, buf buffer.Buffer, opt *Opt) {
|
||||
_ = buf.WriteByte('"')
|
||||
escapeStringToBuff(v.valueStr, buf, opt)
|
||||
_ = buf.WriteByte('"')
|
||||
}
|
||||
|
||||
func marshalBoolean(v *V, buf buffer.Buffer) {
|
||||
_, _ = buf.WriteString(formatBool(v.valueBool))
|
||||
}
|
||||
|
||||
func marshalNumber(v *V, buf buffer.Buffer, opt *Opt) error {
|
||||
if b := v.srcByte; len(b) > 0 {
|
||||
_, _ = buf.Write(b)
|
||||
return nil
|
||||
}
|
||||
// else, +Inf or -Inf or NaN
|
||||
if math.IsInf(v.num.f64, 1) { // +Inf
|
||||
return marshalInfP(buf, opt)
|
||||
}
|
||||
if math.IsInf(v.num.f64, -1) { // -Inf
|
||||
return marshalInfN(buf, opt)
|
||||
}
|
||||
|
||||
return marshalNaN(buf, opt)
|
||||
}
|
||||
|
||||
func marshalNaN(buf buffer.Buffer, opt *Opt) error {
|
||||
switch opt.FloatNaNHandleType {
|
||||
default:
|
||||
fallthrough
|
||||
case FloatNaNTreatAsError:
|
||||
return fmt.Errorf("%w: %v", ErrUnsupportedFloat, math.NaN())
|
||||
|
||||
case FloatNaNConvertToFloat:
|
||||
if !isValidFloat(opt.FloatNaNToFloat) {
|
||||
return fmt.Errorf("%w: %v", ErrUnsupportedFloatInOpt, opt.FloatNaNToFloat)
|
||||
}
|
||||
b, _ := json.Marshal(opt.FloatNaNToFloat)
|
||||
_, _ = buf.Write(b)
|
||||
|
||||
case FloatNaNNull:
|
||||
_, _ = buf.WriteString("null")
|
||||
|
||||
case FloatNaNConvertToString:
|
||||
if s := opt.FloatNaNToString; s == "" {
|
||||
_, _ = buf.WriteString(`"NaN"`)
|
||||
} else {
|
||||
_ = buf.WriteByte('"')
|
||||
escapeStringToBuff(s, buf, opt)
|
||||
_ = buf.WriteByte('"')
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func marshalInfP(buf buffer.Buffer, opt *Opt) error {
|
||||
switch opt.FloatInfHandleType {
|
||||
default:
|
||||
fallthrough
|
||||
case FloatInfTreatAsError:
|
||||
return fmt.Errorf("%w: %v", ErrUnsupportedFloat, math.Inf(1))
|
||||
|
||||
case FloatInfConvertToFloat:
|
||||
if !isValidFloat(opt.FloatInfToFloat) {
|
||||
return fmt.Errorf("%w: %v", ErrUnsupportedFloatInOpt, opt.FloatInfToFloat)
|
||||
}
|
||||
b, _ := json.Marshal(opt.FloatInfToFloat)
|
||||
_, _ = buf.Write(b)
|
||||
|
||||
case FloatInfNull:
|
||||
_, _ = buf.WriteString("null")
|
||||
|
||||
case FloatInfConvertToString:
|
||||
if s := opt.FloatInfPositiveToString; s == "" {
|
||||
_, _ = buf.WriteString(`"+Inf"`)
|
||||
} else {
|
||||
_ = buf.WriteByte('"')
|
||||
escapeStringToBuff(s, buf, opt)
|
||||
_ = buf.WriteByte('"')
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func marshalInfN(buf buffer.Buffer, opt *Opt) error {
|
||||
switch opt.FloatInfHandleType {
|
||||
default:
|
||||
fallthrough
|
||||
case FloatInfTreatAsError:
|
||||
return fmt.Errorf("%w: %v", ErrUnsupportedFloat, math.Inf(-1))
|
||||
|
||||
case FloatInfConvertToFloat:
|
||||
if !isValidFloat(opt.FloatInfToFloat) {
|
||||
return fmt.Errorf("%w: %v", ErrUnsupportedFloatInOpt, -opt.FloatInfToFloat)
|
||||
}
|
||||
b, _ := json.Marshal(-opt.FloatInfToFloat)
|
||||
_, _ = buf.Write(b)
|
||||
|
||||
case FloatInfNull:
|
||||
_, _ = buf.WriteString("null")
|
||||
|
||||
case FloatInfConvertToString:
|
||||
_ = buf.WriteByte('"')
|
||||
if s := opt.FloatInfNegativeToString; s != "" {
|
||||
escapeStringToBuff(s, buf, opt)
|
||||
} else if opt.FloatInfPositiveToString != "" {
|
||||
s = "-" + strings.TrimLeft(opt.FloatInfPositiveToString, "+")
|
||||
escapeStringToBuff(s, buf, opt)
|
||||
} else {
|
||||
_, _ = buf.WriteString(`-Inf`)
|
||||
}
|
||||
_ = buf.WriteByte('"')
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func isValidFloat(f float64) bool {
|
||||
if math.IsNaN(f) {
|
||||
return false
|
||||
}
|
||||
if math.IsInf(f, 0) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func marshalNull(buf buffer.Buffer) {
|
||||
_, _ = buf.WriteString("null")
|
||||
}
|
||||
|
||||
func marshalObject(v *V, parentInfo *ParentInfo, buf buffer.Buffer, opt *Opt) {
|
||||
if len(v.children.object) == 0 {
|
||||
_, _ = buf.WriteString("{}")
|
||||
return
|
||||
}
|
||||
|
||||
opt.indent.cnt++
|
||||
_ = buf.WriteByte('{')
|
||||
|
||||
if opt.MarshalLessFunc != nil {
|
||||
sov := newSortObjectV(v, parentInfo, opt)
|
||||
sov.marshalObjectWithLessFunc(buf, opt)
|
||||
|
||||
} else if len(opt.MarshalKeySequence) > 0 {
|
||||
sssv := newSortStringSliceV(v, opt)
|
||||
sssv.marshalObjectWithStringSlice(buf, opt)
|
||||
|
||||
} else if opt.marshalBySetSequence {
|
||||
sssv := newSortStringSliceVBySetSeq(v)
|
||||
sssv.marshalObjectWithStringSlice(buf, opt)
|
||||
|
||||
} else {
|
||||
writeObjectKVInRandomizedSequence(v, buf, opt)
|
||||
}
|
||||
|
||||
opt.indent.cnt--
|
||||
if opt.indent.enabled {
|
||||
_ = buf.WriteByte('\n')
|
||||
writeIndent(buf, opt)
|
||||
}
|
||||
_ = buf.WriteByte('}')
|
||||
}
|
||||
|
||||
func writeObjectKVInRandomizedSequence(v *V, buf buffer.Buffer, opt *Opt) {
|
||||
firstWritten := false
|
||||
for k, child := range v.children.object {
|
||||
firstWritten = writeObjectChildren(nil, buf, !firstWritten, k, child.v, opt)
|
||||
}
|
||||
}
|
||||
|
||||
func writeObjectChildren(
|
||||
parentInfo *ParentInfo, buf buffer.Buffer, isFirstOne bool, key string, child *V, opt *Opt,
|
||||
) (written bool) {
|
||||
if child.IsNull() && opt.OmitNull {
|
||||
return false
|
||||
}
|
||||
if !isFirstOne {
|
||||
_ = buf.WriteByte(',')
|
||||
}
|
||||
|
||||
if opt.indent.enabled {
|
||||
_ = buf.WriteByte('\n')
|
||||
writeIndent(buf, opt)
|
||||
}
|
||||
|
||||
_ = buf.WriteByte('"')
|
||||
escapeStringToBuff(key, buf, opt)
|
||||
|
||||
if opt.indent.enabled {
|
||||
_, _ = buf.WriteString("\": ")
|
||||
} else {
|
||||
_, _ = buf.WriteString("\":")
|
||||
}
|
||||
|
||||
_ = marshalToBuffer(child, parentInfo, buf, opt)
|
||||
return true
|
||||
}
|
||||
|
||||
func writeIndent(buf buffer.Buffer, opt *Opt) {
|
||||
_, _ = buf.WriteString(opt.indent.prefix)
|
||||
for i := 0; i < opt.indent.cnt; i++ {
|
||||
_, _ = buf.WriteString(opt.indent.indent)
|
||||
}
|
||||
}
|
||||
|
||||
func marshalArray(v *V, parentInfo *ParentInfo, buf buffer.Buffer, opt *Opt) {
|
||||
if len(v.children.arr) == 0 {
|
||||
_, _ = buf.WriteString("[]")
|
||||
return
|
||||
}
|
||||
|
||||
opt.indent.cnt++
|
||||
_ = buf.WriteByte('[')
|
||||
|
||||
v.RangeArray(func(i int, child *V) bool {
|
||||
if i > 0 {
|
||||
_ = buf.WriteByte(',')
|
||||
}
|
||||
if opt.indent.enabled {
|
||||
_ = buf.WriteByte('\n')
|
||||
writeIndent(buf, opt)
|
||||
}
|
||||
if opt.MarshalLessFunc == nil {
|
||||
_ = marshalToBuffer(child, nil, buf, opt)
|
||||
} else {
|
||||
_ = marshalToBuffer(child, newParentInfo(v, parentInfo, intKey(i)), buf, opt)
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
opt.indent.cnt--
|
||||
if opt.indent.enabled {
|
||||
_ = buf.WriteByte('\n')
|
||||
writeIndent(buf, opt)
|
||||
}
|
||||
_ = buf.WriteByte(']')
|
||||
}
|
44
vendor/github.com/Andrew-M-C/go.jsonvalue/marshaler_unmarshaler.go
generated
vendored
Normal file
44
vendor/github.com/Andrew-M-C/go.jsonvalue/marshaler_unmarshaler.go
generated
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
package jsonvalue
|
||||
|
||||
import (
|
||||
"encoding"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
var (
|
||||
_ json.Marshaler = (*V)(nil)
|
||||
_ json.Unmarshaler = (*V)(nil)
|
||||
|
||||
_ encoding.BinaryMarshaler = (*V)(nil)
|
||||
_ encoding.BinaryUnmarshaler = (*V)(nil)
|
||||
)
|
||||
|
||||
// MarshalJSON implements json.Marshaler
|
||||
func (v *V) MarshalJSON() ([]byte, error) {
|
||||
return v.Marshal()
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements json.Unmarshaler
|
||||
func (v *V) UnmarshalJSON(b []byte) error {
|
||||
res, err := Unmarshal(b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*v = *res
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary implements encoding.BinaryMarshaler
|
||||
func (v *V) MarshalBinary() ([]byte, error) {
|
||||
return v.Marshal()
|
||||
}
|
||||
|
||||
// UnmarshalBinary implements encoding.BinaryUnmarshaler
|
||||
func (v *V) UnmarshalBinary(b []byte) error {
|
||||
res, err := Unmarshal(b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*v = *res
|
||||
return nil
|
||||
}
|
273
vendor/github.com/Andrew-M-C/go.jsonvalue/new.go
generated
vendored
Normal file
273
vendor/github.com/Andrew-M-C/go.jsonvalue/new.go
generated
vendored
Normal file
@ -0,0 +1,273 @@
|
||||
package jsonvalue
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"math"
|
||||
"reflect"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// New generate a new jsonvalue type via given type. If given type is not supported,
|
||||
// the returned type would equal to NotExist. If you are not sure whether given value
|
||||
// type is OK in runtime, use Import() instead.
|
||||
//
|
||||
// New 函数按照给定参数类型创建一个 jsonvalue 类型。如果给定参数不是 JSON 支持的类型, 那么返回的
|
||||
// *V 对象的类型为 NotExist。如果在代码中无法确定入参是否是 JSON 支持的类型, 请改用函数
|
||||
// Import()。
|
||||
func New(value any) *V {
|
||||
v, _ := Import(value)
|
||||
return v
|
||||
}
|
||||
|
||||
// NewString returns an initialized string jsonvalue object
|
||||
//
|
||||
// NewString 用给定的 string 返回一个初始化好的字符串类型的 jsonvalue 值
|
||||
func NewString(s string) *V {
|
||||
v := new(globalPool{}, String)
|
||||
v.valueStr = s
|
||||
return v
|
||||
}
|
||||
|
||||
// NewBytes returns an initialized string with Base64 string by given bytes
|
||||
//
|
||||
// NewBytes 用给定的字节串,返回一个初始化好的字符串类型的 jsonvalue 值,内容是字节串 Base64 之后的字符串。
|
||||
func NewBytes(b []byte) *V {
|
||||
s := base64.StdEncoding.EncodeToString(b)
|
||||
return NewString(s)
|
||||
}
|
||||
|
||||
// NewInt64 returns an initialized num jsonvalue object by int64 type
|
||||
//
|
||||
// NewInt64 用给定的 int64 返回一个初始化好的数字类型的 jsonvalue 值
|
||||
func NewInt64(i int64) *V {
|
||||
v := new(globalPool{}, Number)
|
||||
// v.num = &num{}
|
||||
v.num.floated = false
|
||||
v.num.negative = i < 0
|
||||
v.num.f64 = float64(i)
|
||||
v.num.i64 = i
|
||||
v.num.u64 = uint64(i)
|
||||
s := strconv.FormatInt(v.num.i64, 10)
|
||||
v.srcByte = []byte(s)
|
||||
return v
|
||||
}
|
||||
|
||||
// NewUint64 returns an initialized num jsonvalue object by uint64 type
|
||||
//
|
||||
// NewUint64 用给定的 uint64 返回一个初始化好的数字类型的 jsonvalue 值
|
||||
func NewUint64(u uint64) *V {
|
||||
v := new(globalPool{}, Number)
|
||||
// v.num = &num{}
|
||||
v.num.floated = false
|
||||
v.num.negative = false
|
||||
v.num.f64 = float64(u)
|
||||
v.num.i64 = int64(u)
|
||||
v.num.u64 = u
|
||||
s := strconv.FormatUint(v.num.u64, 10)
|
||||
v.srcByte = []byte(s)
|
||||
return v
|
||||
}
|
||||
|
||||
// NewInt returns an initialized num jsonvalue object by int type
|
||||
//
|
||||
// NewInt 用给定的 int 返回一个初始化好的数字类型的 jsonvalue 值
|
||||
func NewInt(i int) *V {
|
||||
return NewInt64(int64(i))
|
||||
}
|
||||
|
||||
// NewUint returns an initialized num jsonvalue object by uint type
|
||||
//
|
||||
// NewUint 用给定的 uint 返回一个初始化好的数字类型的 jsonvalue 值
|
||||
func NewUint(u uint) *V {
|
||||
return NewUint64(uint64(u))
|
||||
}
|
||||
|
||||
// NewInt32 returns an initialized num jsonvalue object by int32 type
|
||||
//
|
||||
// NewInt32 用给定的 int32 返回一个初始化好的数字类型的 jsonvalue 值
|
||||
func NewInt32(i int32) *V {
|
||||
return NewInt64(int64(i))
|
||||
}
|
||||
|
||||
// NewUint32 returns an initialized num jsonvalue object by uint32 type
|
||||
//
|
||||
// NewUint32 用给定的 uint32 返回一个初始化好的数字类型的 jsonvalue 值
|
||||
func NewUint32(u uint32) *V {
|
||||
return NewUint64(uint64(u))
|
||||
}
|
||||
|
||||
// NewBool returns an initialized boolean jsonvalue object
|
||||
//
|
||||
// NewBool 用给定的 bool 返回一个初始化好的布尔类型的 jsonvalue 值
|
||||
func NewBool(b bool) *V {
|
||||
v := new(globalPool{}, Boolean)
|
||||
v.valueBool = b
|
||||
return v
|
||||
}
|
||||
|
||||
// NewNull returns an initialized null jsonvalue object
|
||||
//
|
||||
// NewNull 返回一个初始化好的 null 类型的 jsonvalue 值
|
||||
func NewNull() *V {
|
||||
v := new(globalPool{}, Null)
|
||||
return v
|
||||
}
|
||||
|
||||
// NewObject returns an object-typed jsonvalue object. If keyValues is specified, it will also create some key-values in
|
||||
// the object. Now we supports basic types only. Such as int/uint, int/int8/int16/int32/int64,
|
||||
// uint/uint8/uint16/uint32/uint64 series, string, bool, nil.
|
||||
//
|
||||
// NewObject 返回一个初始化好的 object 类型的 jsonvalue 值。可以使用可选的 map[string]any 类型参数初始化该 object 的下一级键值对,
|
||||
// 不过目前只支持基础类型,也就是: int/uint, int/int8/int16/int32/int64, uint/uint8/uint16/uint32/uint64, string, bool, nil。
|
||||
func NewObject(keyValues ...M) *V {
|
||||
v := newObject(globalPool{})
|
||||
|
||||
if len(keyValues) > 0 {
|
||||
kv := keyValues[0]
|
||||
if kv != nil {
|
||||
parseNewObjectKV(v, kv)
|
||||
}
|
||||
}
|
||||
|
||||
return v
|
||||
}
|
||||
|
||||
// M is the alias of map[string]any
|
||||
type M map[string]any
|
||||
|
||||
func parseNewObjectKV(v *V, kv M) {
|
||||
for k, val := range kv {
|
||||
rv := reflect.ValueOf(val)
|
||||
switch rv.Kind() {
|
||||
case reflect.Invalid:
|
||||
v.MustSetNull().At(k)
|
||||
case reflect.Bool:
|
||||
v.MustSetBool(rv.Bool()).At(k)
|
||||
case reflect.Int, reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8:
|
||||
v.MustSetInt64(rv.Int()).At(k)
|
||||
case reflect.Uint, reflect.Uint64, reflect.Uint32, reflect.Uint16, reflect.Uint8:
|
||||
v.MustSetUint64(rv.Uint()).At(k)
|
||||
case reflect.Float32, reflect.Float64:
|
||||
v.MustSetFloat64(rv.Float()).At(k)
|
||||
case reflect.String:
|
||||
v.MustSetString(rv.String()).At(k)
|
||||
// case reflect.Map:
|
||||
// if rv.Type().Key().Kind() == reflect.String && rv.Type().Elem().Kind() == reflect.Interface {
|
||||
// if m, ok := rv.Interface().(M); ok {
|
||||
// sub := NewObject(m)
|
||||
// if sub != nil {
|
||||
// v.Set(sub).At(k)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
default:
|
||||
// continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NewArray returns an empty array-typed jsonvalue object
|
||||
//
|
||||
// NewArray 返回一个初始化好的 array 类型的 jsonvalue 值。
|
||||
func NewArray() *V {
|
||||
return newArray(globalPool{})
|
||||
}
|
||||
|
||||
// NewFloat64 returns an initialized num jsonvalue value by float64 type. The format and precision control is the same
|
||||
// with encoding/json: https://github.com/golang/go/blob/master/src/encoding/json/encode.go#L575
|
||||
//
|
||||
// NewFloat64 根据指定的 flout64 类型返回一个初始化好的数字类型的 jsonvalue 值。数字转出来的字符串格式参照 encoding/json 中的逻辑。
|
||||
func NewFloat64(f float64) *V {
|
||||
abs := math.Abs(f)
|
||||
format := byte('f')
|
||||
if abs < 1e-6 || abs >= 1e21 {
|
||||
format = byte('e')
|
||||
}
|
||||
|
||||
return newFloat64f(globalPool{}, f, format, -1, 64)
|
||||
}
|
||||
|
||||
// NewFloat64f returns an initialized num jsonvalue value by float64 type. The format and prec parameter are used in
|
||||
// strconv.FormatFloat(). Only 'f', 'E', 'e', 'G', 'g' formats are supported, other formats will be mapped to 'g'.
|
||||
//
|
||||
// NewFloat64f 根据指定的 float64 类型返回一个初始化好的数字类型的 jsonvalue 值。其中参数 format 和 prec 分别用于
|
||||
// strconv.FormatFloat() 函数. 只有 'f'、'E'、'e'、'G'、'g' 格式是支持的,其他配置均统一映射为 'g'。
|
||||
func NewFloat64f(f float64, format byte, prec int) *V {
|
||||
if err := validateFloat64Format(format); err != nil {
|
||||
format = 'g'
|
||||
}
|
||||
return newFloat64f(globalPool{}, f, format, prec, 64)
|
||||
}
|
||||
|
||||
// NewFloat32 returns an initialized num jsonvalue value by float32 type. The format and precision control is the same
|
||||
// with encoding/json: https://github.com/golang/go/blob/master/src/encoding/json/encode.go#L575
|
||||
//
|
||||
// NewFloat32 根据指定的 float32 类型返回一个初始化好的数字类型的 jsonvalue 值。数字转出来的字符串格式参照 encoding/json 中的逻辑。
|
||||
func NewFloat32(f float32) *V {
|
||||
f64 := float64(f)
|
||||
abs := math.Abs(f64)
|
||||
format := byte('f')
|
||||
if abs < 1e-6 || abs >= 1e21 {
|
||||
format = byte('e')
|
||||
}
|
||||
|
||||
return newFloat64f(globalPool{}, f64, format, -1, 32)
|
||||
}
|
||||
|
||||
// NewFloat32f returns an initialized num jsonvalue value by float64 type. The format and prec parameter are used in
|
||||
// strconv.FormatFloat(). Only 'f', 'E', 'e', 'G', 'g' formats are supported, other formats will be mapped to 'g'.
|
||||
//
|
||||
// NewFloat32f 根据指定的 float64 类型返回一个初始化好的数字类型的 jsonvalue 值。其中参数 format 和 prec 分别用于
|
||||
// strconv.FormatFloat() 函数. 只有 'f'、'E'、'e'、'G'、'g' 格式是支持的,其他配置均统一映射为 'g'。
|
||||
func NewFloat32f(f float32, format byte, prec int) *V {
|
||||
if err := validateFloat64Format(format); err != nil {
|
||||
format = 'g'
|
||||
}
|
||||
return newFloat64f(globalPool{}, float64(f), format, prec, 64)
|
||||
}
|
||||
|
||||
// -------- internal functions --------
|
||||
|
||||
func new(p pool, t ValueType) *V {
|
||||
v := pool.get(p)
|
||||
v.valueType = t
|
||||
return v
|
||||
}
|
||||
|
||||
func newObject(p pool) *V {
|
||||
v := new(p, Object)
|
||||
v.children.object = make(map[string]childWithProperty)
|
||||
v.children.lowerCaseKeys = nil
|
||||
return v
|
||||
}
|
||||
|
||||
func newArray(p pool) *V {
|
||||
v := new(p, Array)
|
||||
return v
|
||||
}
|
||||
|
||||
func newFloat64f(p pool, f float64, format byte, prec, bitSize int) *V {
|
||||
v := new(p, Number)
|
||||
// v.num = &num{}
|
||||
v.num.negative = f < 0
|
||||
v.num.f64 = f
|
||||
v.num.i64 = int64(f)
|
||||
v.num.u64 = uint64(f)
|
||||
|
||||
if isValidFloat(f) {
|
||||
s := strconv.FormatFloat(f, format, prec, bitSize)
|
||||
v.srcByte = []byte(s)
|
||||
}
|
||||
|
||||
return v
|
||||
}
|
||||
|
||||
func validateFloat64Format(f byte) error {
|
||||
switch f {
|
||||
case 'f', 'E', 'e', 'G', 'g':
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("unsupported float value in option: %c", f)
|
||||
}
|
||||
}
|
634
vendor/github.com/Andrew-M-C/go.jsonvalue/option.go
generated
vendored
Normal file
634
vendor/github.com/Andrew-M-C/go.jsonvalue/option.go
generated
vendored
Normal file
@ -0,0 +1,634 @@
|
||||
package jsonvalue
|
||||
|
||||
import "github.com/Andrew-M-C/go.jsonvalue/internal/buffer"
|
||||
|
||||
const (
|
||||
initialArrayCapacity = 32
|
||||
asciiSize = 128
|
||||
)
|
||||
|
||||
// Deprecated: Opt is the option of jsonvalue in marshaling. This type is deprecated,
|
||||
// please use OptXxxx() functions instead.
|
||||
//
|
||||
// Opt 表示序列化当前 jsonvalue 类型时的参数。这个类型后续可能不再迭代新字段了,请改用 OptXxxx() 函数进行配置。
|
||||
type Opt struct {
|
||||
// OmitNull tells how to handle null json value. The default value is false.
|
||||
// If OmitNull is true, null value will be omitted when marshaling.
|
||||
//
|
||||
// OmitNull 表示是否忽略 JSON 中的 null 类型值。默认为 false.
|
||||
OmitNull bool
|
||||
|
||||
// ignoreJsonOmitempty ignore json tag "omitempty", which means that every data
|
||||
// would be parsed into *jsonvalue.V
|
||||
ignoreJsonOmitempty bool
|
||||
|
||||
// MarshalLessFunc is used to handle sequences of marshaling. Since object is
|
||||
// implemented by hash map, the sequence of keys is unexpectable. For situations
|
||||
// those need settled JSON key-value sequence, please use MarshalLessFunc.
|
||||
//
|
||||
// Note: Elements in an array value would NOT trigger this function as they are
|
||||
// already sorted.
|
||||
//
|
||||
// We provides a example DefaultStringSequence. It is quite useful when calculating
|
||||
// idempotence of a JSON text, as key-value sequences should be fixed.
|
||||
//
|
||||
// MarshalLessFunc 用于处理序列化 JSON 对象类型时,键值对的顺序。由于 object 类型是采用 go
|
||||
// 原生的 map 类型,采用哈希算法实现,
|
||||
// 因此其键值对的顺序是不可控的。而为了提高效率,jsonvalue 的内部实现中并不会刻意保存键值对的顺序。
|
||||
// 如果有必要在序列化时固定键值对顺序的话,
|
||||
// 可以使用这个函数。
|
||||
//
|
||||
// 注意:array 类型中键值对的顺序不受这个函数的影响
|
||||
//
|
||||
// 此外,我们提供了一个例子: DefaultStringSequence。当需要计算 JSON 文本的幂等值时,
|
||||
// 由于需要不变的键值对顺序,因此这个函数是非常有用的。
|
||||
MarshalLessFunc MarshalLessFunc
|
||||
|
||||
// MarshalKeySequence is used to handle sequance of marshaling. This is much simpler
|
||||
// than MarshalLessFunc, just pass a string slice identifying key sequence. For keys
|
||||
// those are not in this slice, they would be appended in the end according to result
|
||||
// of Go string comparing. Therefore this parameter is useful for ensure idempotence.
|
||||
//
|
||||
// MarshalKeySequence 也用于处理序列化时的键值对顺序。与 MarshalLessFunc 不同,这个只需要用字符串
|
||||
// 切片的形式指定键的顺序即可,实现上更为简易和直观。对于那些不在指定切片中的键,那么将会统一放在结尾,
|
||||
// 并且按照 go 字符串对比的结果排序。也可以保证幂等。
|
||||
MarshalKeySequence []string
|
||||
keySequence map[string]int // generated from MarshalKeySequence
|
||||
|
||||
// marshalBySetSequence enables object key sequence by when it is set.
|
||||
//
|
||||
// 按照 key 被设置的顺序处理序列化时的 marshal 顺序
|
||||
marshalBySetSequence bool
|
||||
|
||||
// FloatNaNHandleType tells what to deal with float NaN.
|
||||
//
|
||||
// FloatNaNHandleType 表示当处理 float 的时候,如果遇到了 NaN 的话,要如何处理。
|
||||
FloatNaNHandleType FloatNaNHandleType
|
||||
// FloatNaNToString works with FloatNaNHandleType = FloatNaNConvertToString. It tells
|
||||
// what string to replace to with NaN. If not specified, NaN will be set as string "NaN".
|
||||
//
|
||||
// FloatNaNToString 搭配 FloatNaNHandleType = FloatNaNConvertToString 使用,表示将 NaN
|
||||
// 映射为哪个字符串。这个值如果不指定,则默认会被设置为字符串 "NaN"
|
||||
FloatNaNToString string
|
||||
// FloatNaNToFloat works with FloatNaNHandleType = FloatNaNConvertToFloat. It tells
|
||||
// what float number will be mapped to as for NaN. NaN, +Inf or -Inf are not allowed
|
||||
// for this option.
|
||||
//
|
||||
// FloatNaNToFloat 搭配 FloatNaNHandleType = FloatNaNConvertToFloat 使用,表示将 NaN
|
||||
// 映射为哪个 float64 值。不允许指定为 NaN, +Inf 或 -Inf。如果不指定,则映射为 0。
|
||||
FloatNaNToFloat float64
|
||||
|
||||
// FloatInfHandleType tells what to deal with float +Inf and -Inf.
|
||||
//
|
||||
// FloatInfHandleType 表示当处理 float 的时候,如果遇到了 +Inf 和 -Inf 的话,要如何处理。
|
||||
FloatInfHandleType FloatInfHandleType
|
||||
// FloatInfPositiveToString works with FloatInfHandleType = FloatInfConvertToFloat.
|
||||
// It tells what float number will be mapped to as for +Inf. If not specified, +Inf
|
||||
// will be set as string "+Inf".
|
||||
//
|
||||
// FloatInfPositiveToString 搭配 FloatInfHandleType = FloatInfConvertToFloat 使用,
|
||||
// 表示将 NaN 映射为哪个字符串。
|
||||
// 这个值如果不指定,则默认会被设置为字符串 "+Inf"
|
||||
FloatInfPositiveToString string
|
||||
// FloatInfNegativeToString works with FloatInfHandleType = FloatInfConvertToFloat.
|
||||
// It tells what float number will be mapped to as for -Inf. If not specified, -Inf
|
||||
// will be set as string "-" + strings.TrimLeft(FloatInfPositiveToString, "+").
|
||||
//
|
||||
// FloatInfNegativeToString 搭配 FloatInfHandleType = FloatInfConvertToFloat 使用,
|
||||
// 表示将 NaN 映射为哪个字符串。这个值如果不指定,则默认会被设置为字符串 "-" + strings.TrimLeft(FloatInfPositiveToString, "+")
|
||||
FloatInfNegativeToString string
|
||||
// FloatInfToFloat works with FloatInfHandleType = FloatInfConvertToFloat. It tells
|
||||
// what float numbers will be mapped to as for +Inf. And -Inf will be specified as
|
||||
// the negative value of this option. +Inf or -Inf are not allowed for this option.
|
||||
//
|
||||
// FloatInfToFloat 搭配 FloatInfHandleType = FloatInfConvertToFloat 使用,表示将 +Inf
|
||||
// 映射为哪个 float64 值。而 -Inf 则会被映射为这个值的负数。不允许指定为 NaN, +Inf 或 -Inf。
|
||||
// 如果不指定,则映射为 0
|
||||
FloatInfToFloat float64
|
||||
|
||||
// unicodeEscapingFunc defines how to escaping a unicode greater than 0x7F to buffer.
|
||||
unicodeEscapingFunc func(r rune, buf buffer.Buffer)
|
||||
|
||||
// asciiCharEscapingFunc defines how to marshal bytes lower than 0x80.
|
||||
asciiCharEscapingFunc [asciiSize]func(b byte, buf buffer.Buffer)
|
||||
|
||||
// escProperties
|
||||
escProperties escapingProperties
|
||||
|
||||
// indent
|
||||
indent struct {
|
||||
enabled bool
|
||||
prefix string
|
||||
indent string
|
||||
cnt int
|
||||
}
|
||||
}
|
||||
|
||||
type FloatNaNHandleType uint8
|
||||
|
||||
const (
|
||||
// FloatNaNTreatAsError indicates that error will be returned when a float number
|
||||
// is NaN when marshaling.
|
||||
//
|
||||
// FloatNaNTreatAsError 表示当 marshal 遇到 NaN 时,返回错误。这是默认选项。
|
||||
FloatNaNTreatAsError FloatNaNHandleType = 0
|
||||
// FloatNaNConvertToFloat indicates that NaN will be replaced as another float
|
||||
// number when marshaling. This option works with option FloatNaNToFloat.
|
||||
//
|
||||
// FloatNaNConvertToFloat 表示当 marshal 遇到 NaN 时,将值置为另一个数。搭配 FloatNaNToFloat
|
||||
// 选项使用。
|
||||
FloatNaNConvertToFloat FloatNaNHandleType = 1
|
||||
// FloatNaNNull indicates that NaN key-value pair will be set as null when marshaling.
|
||||
//
|
||||
// FloatNaNNull 表示当 marshal 遇到 NaN 时,则将值设置为 null
|
||||
FloatNaNNull FloatNaNHandleType = 2
|
||||
// FloatNaNConvertToString indicates that NaN will be replaced as a string when
|
||||
// marshaling. This option works with option FloatNaNToString.
|
||||
//
|
||||
// FloatNaNConvertToString 表示当 marshal 遇到 NaN 时,将值设置为一个字符串。搭配
|
||||
// FloatNaNToString 选项使用。
|
||||
FloatNaNConvertToString FloatNaNHandleType = 3
|
||||
)
|
||||
|
||||
type FloatInfHandleType uint8
|
||||
|
||||
const (
|
||||
// FloatInfTreatAsError indicates that error will be returned when a float number
|
||||
// is Inf or -Inf when marshaling.
|
||||
//
|
||||
// FloatInfTreatAsError 表示当 marshal 遇到 Inf 或 -Inf 时,返回错误。这是默认选项。
|
||||
FloatInfTreatAsError FloatInfHandleType = 0
|
||||
// FloatInfConvertToFloat indicates that Inf and -Inf will be replaced as another
|
||||
// float number when marshaling. This option works with option FloatInfToFloat.
|
||||
//
|
||||
// FloatInfConvertToFloat 表示当 marshal 遇到 Inf 或 -Inf 时,将值置为另一个数。搭配
|
||||
// FloatInfToFloat 选项使用。
|
||||
FloatInfConvertToFloat FloatInfHandleType = 1
|
||||
// FloatInfNull indicates that Inf or -Inf key-value pair will be set as null
|
||||
// when marshaling.
|
||||
//
|
||||
// FloatInfNull 表示当 marshal 遇到 Inf 和 -Inf 时,则将值设置为 null
|
||||
FloatInfNull FloatInfHandleType = 2
|
||||
// FloatInfConvertToString indicates that Inf anf -Inf will be replaced as a
|
||||
// string when marshaling. This option works with option FloatInfPositiveToString
|
||||
// and FloatInfNegativeToString.
|
||||
//
|
||||
// FloatInfConvertToString 表示当 marshal 遇到 Inf 和 -Inf 时,将值设置为一个字符串。
|
||||
// 搭配 FloatInfPositiveToString FloatInfNegativeToString 选项使用。
|
||||
FloatInfConvertToString FloatInfHandleType = 3
|
||||
)
|
||||
|
||||
// Option is used for additional options when marshaling. Can be either a Opt{}
|
||||
// (not pointer to it) or other options generated by jsonvalue.OptXxxx() functions.
|
||||
//
|
||||
// Option 表示用于序列化的额外选项。可以是一个 Opt{} 结构体值(而不是它的指针),或者是使用
|
||||
// jsonvalue.OptXxxx() 函数生成的选项。
|
||||
type Option interface {
|
||||
mergeTo(*Opt)
|
||||
}
|
||||
|
||||
func (o Opt) mergeTo(tgt *Opt) {
|
||||
*tgt = o
|
||||
}
|
||||
|
||||
// SetDefaultMarshalOptions set default option for marshaling. It is quite
|
||||
// useful to invoke this function once in certern init funciton. Or you can
|
||||
// invoke it after main entry. It is goroutine-safe.
|
||||
//
|
||||
// Please keep in mind that it takes effect globally and affects ALL marshaling
|
||||
// behaviors in the future until the process ends. Please ensure that these
|
||||
// options are acceptable for ALL future marshaling.
|
||||
//
|
||||
// However, you can still add additional options in later marshaling.
|
||||
//
|
||||
// SetDefaultMarshalOptions 设置序列化时的默认参数。使用方可以在 init 函数阶段,或者是
|
||||
// main 函数启动后立刻调用该函数,以调整序列化时的默认行为。这个函数是协程安全的。
|
||||
//
|
||||
// 请记住,这个函数影响的是后续所有的序列化行为,请确保这个配置对后续的其他操作是可行的。
|
||||
//
|
||||
// 当然,你也可以在后续的操作中,基于原先配置的默认选项基础上,添加其他附加选项。
|
||||
func SetDefaultMarshalOptions(opts ...Option) {
|
||||
opt := emptyOptions()
|
||||
opt.combineOptionsFrom(opts)
|
||||
internal.defaultMarshalOption = opt
|
||||
}
|
||||
|
||||
// ResetDefaultMarshalOptions reset default marshaling options to system default.
|
||||
//
|
||||
// ResetDefaultMarshalOptions 重设序列化时的默认选项为系统最原始的版本。
|
||||
func ResetDefaultMarshalOptions() {
|
||||
internal.defaultMarshalOption = emptyOptions()
|
||||
}
|
||||
|
||||
func emptyOptions() *Opt {
|
||||
return &Opt{}
|
||||
}
|
||||
|
||||
func getDefaultOptions() *Opt {
|
||||
res := *internal.defaultMarshalOption
|
||||
return &res
|
||||
}
|
||||
|
||||
func combineOptions(opts []Option) *Opt {
|
||||
opt := getDefaultOptions()
|
||||
opt.combineOptionsFrom(opts)
|
||||
return opt
|
||||
}
|
||||
|
||||
func (opt *Opt) combineOptionsFrom(opts []Option) {
|
||||
for _, o := range opts {
|
||||
o.mergeTo(opt)
|
||||
}
|
||||
opt.parseEscapingFuncs()
|
||||
}
|
||||
|
||||
// ==== OmitNull ====
|
||||
|
||||
// OptOmitNull configures OmitNull field in Opt{}, identifying whether null values
|
||||
// should be omitted when marshaling.
|
||||
//
|
||||
// OptOmitNull 配置 Opt{} 中的 OmitNull 字段,表示是否忽略 null 值。
|
||||
func OptOmitNull(b bool) Option {
|
||||
return &optOmitNull{b: b}
|
||||
}
|
||||
|
||||
type optOmitNull struct {
|
||||
b bool
|
||||
}
|
||||
|
||||
func (o *optOmitNull) mergeTo(opt *Opt) {
|
||||
opt.OmitNull = o.b
|
||||
}
|
||||
|
||||
// ==== IgnoreOmitempty ====
|
||||
|
||||
// OptIgnoreOmitempty is used in Import() and New() function. This option tells
|
||||
// jsonvalue to ignore json tag "omitempty", which means that every field would
|
||||
// be parsed into *jsonvalue.V.
|
||||
//
|
||||
// OptIgnoreOmitempty 用在 Import 和 New() 函数中。这个选项将会忽略 json 标签中的
|
||||
// "omitempty" 参数。换句话说, 所有的字段都会被解析并包装到 *jsonvalue.V 值中。
|
||||
func OptIgnoreOmitempty() Option {
|
||||
return optIgnoreOmitempty{}
|
||||
}
|
||||
|
||||
type optIgnoreOmitempty struct{}
|
||||
|
||||
func (optIgnoreOmitempty) mergeTo(opt *Opt) {
|
||||
opt.ignoreJsonOmitempty = true
|
||||
}
|
||||
|
||||
// ==== MarshalLessFunc ===
|
||||
|
||||
// OptKeySequenceWithLessFunc configures MarshalLessFunc field in Opt{}, which defines
|
||||
// key sequence when marshaling.
|
||||
//
|
||||
// OptKeySequenceWithLessFunc 配置 Opt{} 中的 MarshalLessFunc 字段,配置序列化时的键顺序。
|
||||
func OptKeySequenceWithLessFunc(f MarshalLessFunc) Option {
|
||||
return &optMarshalLessFunc{f: f}
|
||||
}
|
||||
|
||||
// OptDefaultStringSequence configures MarshalLessFunc field in Opt{} as jsonvalue.DefaultStringSequence,
|
||||
// which is dictionary sequence.
|
||||
//
|
||||
// OptDefaultStringSequence 配置 Opt{} 中的 MarshalLessFunc 字段为 jsonvalue.DefaultStringSequence,也就是字典序。
|
||||
func OptDefaultStringSequence() Option {
|
||||
return &optMarshalLessFunc{f: DefaultStringSequence}
|
||||
}
|
||||
|
||||
type optMarshalLessFunc struct {
|
||||
f MarshalLessFunc
|
||||
}
|
||||
|
||||
func (o *optMarshalLessFunc) mergeTo(opt *Opt) {
|
||||
if o.f != nil {
|
||||
opt.MarshalLessFunc = o.f
|
||||
opt.MarshalKeySequence = nil
|
||||
opt.keySequence = nil
|
||||
opt.marshalBySetSequence = false
|
||||
}
|
||||
}
|
||||
|
||||
// ==== MarshalKeySequence ====
|
||||
|
||||
// OptKeySequence configures MarshalKeySequence field in Opt{}.
|
||||
//
|
||||
// OptKeySequence 配置 Opt{} 中的 MarshalKeySequence 字段。
|
||||
func OptKeySequence(seq []string) Option {
|
||||
return &optMarshalKeySequence{seq: seq}
|
||||
}
|
||||
|
||||
type optMarshalKeySequence struct {
|
||||
seq []string
|
||||
}
|
||||
|
||||
func (o *optMarshalKeySequence) mergeTo(opt *Opt) {
|
||||
opt.MarshalLessFunc = nil
|
||||
opt.MarshalKeySequence = o.seq
|
||||
opt.keySequence = nil
|
||||
opt.marshalBySetSequence = false
|
||||
}
|
||||
|
||||
// ==== marshalBySetSequence ====
|
||||
|
||||
// OptSetSequence tells that when marshaling an object, the key will be sorted by
|
||||
// the time they are added into or refreshed in its parent object. The later a key
|
||||
//
|
||||
// is set or updated, the later it and its value will be marshaled.
|
||||
//
|
||||
// OptSetSequence 指定在序列化 object 时,按照一个 key 被设置时的顺序进行序列化。如果一个
|
||||
// key 越晚添加到 object 类型,则在序列化的时候越靠后。
|
||||
func OptSetSequence() Option {
|
||||
return optSetSequence{}
|
||||
}
|
||||
|
||||
type optSetSequence struct{}
|
||||
|
||||
func (optSetSequence) mergeTo(opt *Opt) {
|
||||
opt.MarshalLessFunc = nil
|
||||
opt.MarshalKeySequence = nil
|
||||
opt.keySequence = nil
|
||||
opt.marshalBySetSequence = true
|
||||
}
|
||||
|
||||
// ==== FloatNaNConvertToFloat ====
|
||||
|
||||
// OptFloatNaNToFloat tells that when marshaling float NaN, replace it as another
|
||||
// valid float number.
|
||||
//
|
||||
// OptFloatNaNToFloat 指定当遇到 NaN 时,将值替换成一个有效的 float 值。
|
||||
func OptFloatNaNToFloat(f float64) Option {
|
||||
return &optFloatNaNConvertToFloat{f: f}
|
||||
}
|
||||
|
||||
type optFloatNaNConvertToFloat struct {
|
||||
f float64
|
||||
}
|
||||
|
||||
func (o *optFloatNaNConvertToFloat) mergeTo(opt *Opt) {
|
||||
opt.FloatNaNHandleType = FloatNaNConvertToFloat
|
||||
opt.FloatNaNToFloat = o.f
|
||||
}
|
||||
|
||||
// ==== FloatNaNNull ====
|
||||
|
||||
// OptFloatNaNToNull will replace a float value to null if it is NaN.
|
||||
//
|
||||
// OptFloatNaNToNull 表示当遇到 NaN 时,将值替换成 null
|
||||
func OptFloatNaNToNull() Option {
|
||||
return optFloatNaNNull{}
|
||||
}
|
||||
|
||||
type optFloatNaNNull struct{}
|
||||
|
||||
func (optFloatNaNNull) mergeTo(opt *Opt) {
|
||||
opt.FloatNaNHandleType = FloatNaNNull
|
||||
}
|
||||
|
||||
// ==== FloatNaNConvertToString ====
|
||||
|
||||
// OptFloatNaNToStringNaN will replace a float value to string "NaN" if it is NaN.
|
||||
//
|
||||
// OptFloatNaNToStringNaN 表示遇到 NaN 时,将其替换成字符串 "NaN"
|
||||
func OptFloatNaNToStringNaN() Option {
|
||||
return &optFloatNaNConvertToString{s: "NaN"}
|
||||
}
|
||||
|
||||
// OptFloatNaNToString will replace a float value to specified string if it is NaN.
|
||||
// If empty string is given, will replace as "NaN".
|
||||
//
|
||||
// OptFloatNaNToString 表示当遇到 NaN 时,将其替换成指定的字符串。如果指定空字符串,则替换成 "NaN"
|
||||
func OptFloatNaNToString(s string) Option {
|
||||
return &optFloatNaNConvertToString{s: s}
|
||||
}
|
||||
|
||||
type optFloatNaNConvertToString struct {
|
||||
s string
|
||||
}
|
||||
|
||||
func (o *optFloatNaNConvertToString) mergeTo(opt *Opt) {
|
||||
opt.FloatNaNHandleType = FloatNaNConvertToString
|
||||
opt.FloatNaNToString = o.s
|
||||
}
|
||||
|
||||
// ==== FloatInfConvertToFloat ====
|
||||
|
||||
// OptFloatInfToFloat will replace a +Inf float value to specified f, while -f if
|
||||
// the value is -Inf.
|
||||
//
|
||||
// OptFloatInfToFloat 表示当遇到 +Inf 时,将其替换成另一个 float 值;如果是 -Inf,则会替换成其取负数。
|
||||
func OptFloatInfToFloat(f float64) Option {
|
||||
return &optFloatInfConvertToFloat{f: f}
|
||||
}
|
||||
|
||||
type optFloatInfConvertToFloat struct {
|
||||
f float64
|
||||
}
|
||||
|
||||
func (o *optFloatInfConvertToFloat) mergeTo(opt *Opt) {
|
||||
opt.FloatInfHandleType = FloatInfConvertToFloat
|
||||
opt.FloatInfToFloat = o.f
|
||||
}
|
||||
|
||||
// ==== FloatInfNull ====
|
||||
|
||||
// OptFloatInfToNull will replace a float value to null if it is +/-Inf.
|
||||
//
|
||||
// OptFloatInfToNull 表示当遇到 +/-Inf 时,将值替换成 null
|
||||
func OptFloatInfToNull() Option {
|
||||
return optFloatInfNull{}
|
||||
}
|
||||
|
||||
type optFloatInfNull struct{}
|
||||
|
||||
func (optFloatInfNull) mergeTo(opt *Opt) {
|
||||
opt.FloatInfHandleType = FloatInfNull
|
||||
}
|
||||
|
||||
// ==== FloatInfConvertToString ====
|
||||
|
||||
// OptFloatInfToStringInf will replace a +Inf value to string "+Inf", while -Inf to "-Inf"
|
||||
//
|
||||
// OptFloatInfToStringInf 表示遇到 +/-Inf 时,相应地将其替换成字符串 "+Inf" 和 "-Inf"
|
||||
func OptFloatInfToStringInf() Option {
|
||||
return &optFloatInfConvertToString{}
|
||||
}
|
||||
|
||||
// OptFloatInfToString tells what string to replace when marshaling +Inf and -Inf numbers.
|
||||
//
|
||||
// OptFloatInfToString 表示遇到 +/-Inf 时,将其替换成什么字符串。
|
||||
func OptFloatInfToString(positiveInf, negativeInf string) Option {
|
||||
return &optFloatInfConvertToString{
|
||||
positive: positiveInf,
|
||||
negative: negativeInf,
|
||||
}
|
||||
}
|
||||
|
||||
type optFloatInfConvertToString struct {
|
||||
positive string
|
||||
negative string
|
||||
}
|
||||
|
||||
func (o *optFloatInfConvertToString) mergeTo(opt *Opt) {
|
||||
opt.FloatInfHandleType = FloatInfConvertToString
|
||||
opt.FloatInfPositiveToString = o.positive
|
||||
opt.FloatInfNegativeToString = o.negative
|
||||
}
|
||||
|
||||
// ==== escapeHTML ====
|
||||
|
||||
// OptEscapeHTML specifies whether problematic HTML characters should be escaped
|
||||
// inside JSON quoted strings. The default behavior is to escape &, <, and > to
|
||||
// \u0026, \u003c, and \u003e to avoid certain safety problems that can arise when
|
||||
// embedding JSON in HTML. If not specified, HTML symbols above will be escaped by
|
||||
// default.
|
||||
//
|
||||
// OptEscapeHTML 指定部分 HTML 符号是否会被转义。相关的 HTML 符号为 &, <, > 三个。如无指定,
|
||||
// 则默认会被转义
|
||||
func OptEscapeHTML(on bool) Option {
|
||||
return optEscapeHTML(on)
|
||||
}
|
||||
|
||||
type optEscapeHTML bool
|
||||
|
||||
func (o optEscapeHTML) mergeTo(opt *Opt) {
|
||||
if o {
|
||||
opt.escProperties = opt.escProperties.clear(escapeWithoutHTML)
|
||||
} else {
|
||||
opt.escProperties = opt.escProperties.set(escapeWithoutHTML)
|
||||
}
|
||||
}
|
||||
|
||||
// ==== do or do not not use ASCII escaping ====
|
||||
|
||||
// OptUTF8 specifies that all unicodes greater than 0x7F, will NOT be escaped by
|
||||
// \uXXXX format but UTF-8.
|
||||
//
|
||||
// OptUTF8 指定使用 UTF-8 编码。也就是说针对大于 0x7F 的 unicode 字符,将不会使用默认的 \uXXXX
|
||||
// 格式进行编码,而是直接使用 UTF-8。
|
||||
func OptUTF8() Option {
|
||||
return optUTF8(true)
|
||||
}
|
||||
|
||||
type optUTF8 bool
|
||||
|
||||
func (o optUTF8) mergeTo(opt *Opt) {
|
||||
opt.escProperties = opt.escProperties.set(escapeUTF8)
|
||||
}
|
||||
|
||||
// ==== ignore slash ====
|
||||
|
||||
// OptEscapeSlash specifies whether we should escape slash (/) symbol. In JSON standard,
|
||||
// this character should be escaped as '\/'. But non-escaping will not affect anything.
|
||||
// If not specfied, slash will be escaped by default.
|
||||
//
|
||||
// OptEscapeSlash 指定是否需要转移斜杠 (/) 符号。在 JSON 标准中这个符号是需要被转移为 '\/' 的,
|
||||
//
|
||||
// 但是不转义这个符号也不会带来什么问题。如无明确指定,如无指定,默认情况下,斜杠是会被转义的。
|
||||
func OptEscapeSlash(on bool) Option {
|
||||
return optEscSlash(on)
|
||||
}
|
||||
|
||||
type optEscSlash bool
|
||||
|
||||
func (o optEscSlash) mergeTo(opt *Opt) {
|
||||
if o {
|
||||
opt.escProperties = opt.escProperties.clear(escapeIgnoreSlash)
|
||||
} else {
|
||||
opt.escProperties = opt.escProperties.set(escapeIgnoreSlash)
|
||||
}
|
||||
}
|
||||
|
||||
// escapingProperties is a bit mask, showing the option for escaping
|
||||
// characters.
|
||||
//
|
||||
// escapingProperties 是一个位掩码,表明转义特殊字符的方法
|
||||
type escapingProperties uint8
|
||||
|
||||
const (
|
||||
escapeUTF8 = 0
|
||||
escapeWithoutHTML = 1
|
||||
escapeIgnoreSlash = 2
|
||||
)
|
||||
|
||||
func (esc escapingProperties) set(mask escapingProperties) escapingProperties {
|
||||
return esc | (1 << mask)
|
||||
}
|
||||
|
||||
func (esc escapingProperties) clear(mask escapingProperties) escapingProperties {
|
||||
return esc & ^(1 << mask)
|
||||
}
|
||||
|
||||
func (esc escapingProperties) has(mask escapingProperties) bool {
|
||||
return esc == esc.set(mask)
|
||||
}
|
||||
|
||||
// parseEscapingFuncs parse escaping functions by escapingProperties.
|
||||
func (o *Opt) parseEscapingFuncs() {
|
||||
// init bytes lower than 0x80
|
||||
for i := range o.asciiCharEscapingFunc {
|
||||
o.asciiCharEscapingFunc[i] = escapeNothing
|
||||
}
|
||||
|
||||
iterate := func(from, to int, fu func(b byte, buf buffer.Buffer)) {
|
||||
for i := from; i <= to; i++ {
|
||||
o.asciiCharEscapingFunc[i] = fu
|
||||
}
|
||||
}
|
||||
|
||||
// ASCII control bytes should always escaped
|
||||
iterate(0x00, 0x07, escAsciiControlChar)
|
||||
// 0x08 is \b, encoding/json marshal as \u0008, but according to JSON standard, it should be "\b"
|
||||
iterate(0x0E, 0x1F, escAsciiControlChar)
|
||||
o.asciiCharEscapingFunc[0x7F] = escAsciiControlChar // encoding/json does not escape DEL
|
||||
|
||||
// ASCII characters always to be escaped
|
||||
o.asciiCharEscapingFunc['"'] = escDoubleQuote
|
||||
o.asciiCharEscapingFunc['/'] = escSlash
|
||||
o.asciiCharEscapingFunc['\\'] = escBackslash
|
||||
o.asciiCharEscapingFunc['\b'] = escBackspace
|
||||
o.asciiCharEscapingFunc['\f'] = escVertTab
|
||||
o.asciiCharEscapingFunc['\t'] = escTab
|
||||
o.asciiCharEscapingFunc['\n'] = escNewLine
|
||||
o.asciiCharEscapingFunc['\r'] = escReturn
|
||||
o.asciiCharEscapingFunc['<'] = escLeftAngle
|
||||
o.asciiCharEscapingFunc['>'] = escRightAngle
|
||||
o.asciiCharEscapingFunc['&'] = escAnd
|
||||
// o.asciiCharEscapingFunc['%'] = escPercent
|
||||
|
||||
// unicodes >= 0x80
|
||||
if o.escProperties.has(escapeUTF8) {
|
||||
o.unicodeEscapingFunc = escapeGreaterUnicodeToBuffByUTF8
|
||||
} else {
|
||||
o.unicodeEscapingFunc = escapeGreaterUnicodeToBuffByUTF16
|
||||
}
|
||||
|
||||
// ignore slash?
|
||||
if o.escProperties.has(escapeIgnoreSlash) {
|
||||
o.asciiCharEscapingFunc['/'] = escapeNothing
|
||||
}
|
||||
|
||||
// without HTML?
|
||||
if o.escProperties.has(escapeWithoutHTML) {
|
||||
o.asciiCharEscapingFunc['<'] = escapeNothing
|
||||
o.asciiCharEscapingFunc['>'] = escapeNothing
|
||||
o.asciiCharEscapingFunc['&'] = escapeNothing
|
||||
}
|
||||
}
|
||||
|
||||
// ==== indent ====
|
||||
|
||||
// OptIndent appliesiIndent to format the output.
|
||||
//
|
||||
// OptIndent 指定序列化时的缩进。
|
||||
func OptIndent(prefix, indent string) Option {
|
||||
return optionIndent{prefix, indent}
|
||||
}
|
||||
|
||||
type optionIndent [2]string
|
||||
|
||||
func (o optionIndent) mergeTo(opt *Opt) {
|
||||
opt.indent.enabled = true
|
||||
opt.indent.prefix = o[0]
|
||||
opt.indent.indent = o[1]
|
||||
}
|
412
vendor/github.com/Andrew-M-C/go.jsonvalue/set.go
generated
vendored
Normal file
412
vendor/github.com/Andrew-M-C/go.jsonvalue/set.go
generated
vendored
Normal file
@ -0,0 +1,412 @@
|
||||
package jsonvalue
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// Setter type is for At() only.
|
||||
//
|
||||
// Setter 类型仅用于 At() 函数。
|
||||
type Setter interface {
|
||||
// At completes the following operation of Set(). It defines position of value
|
||||
// in Set() and return the new value set.
|
||||
//
|
||||
// The usage of At() is perhaps the most important. This function will recursively
|
||||
// search for child value, and set the new value specified by Set() or SetXxx()
|
||||
// series functions. Please unfold and read the following examples, they are important.
|
||||
//
|
||||
// At 完成 Set() 函数的后续操作并设置相应的子成员。其参数指定了应该在哪个位置设置子成员,
|
||||
// 并且返回被设置的子成员对象。
|
||||
//
|
||||
// 该函数的用法恐怕是 jsonvalue 中最重要的内容了:该函数会按照给定的可变参数递归地一层一层查找
|
||||
// JSON 值的子成员,并且设置到指定的位置上。设置的逻辑说明起来比较抽象,请打开以下的例子以了解,
|
||||
// 这非常重要。
|
||||
At(firstParam any, otherParams ...any) (*V, error)
|
||||
}
|
||||
|
||||
type setter struct {
|
||||
v *V
|
||||
c *V // child
|
||||
|
||||
err error
|
||||
}
|
||||
|
||||
// Set starts setting a child JSON value. Any legal JSON value typped parameter
|
||||
// is accepted, such as string, int, float, bool, nil, *jsonvalue.V, or even
|
||||
// a struct or map or slice.
|
||||
//
|
||||
// Please refer to examples of "func (set Setter) At(...)"
|
||||
//
|
||||
// https://godoc.org/github.com/Andrew-M-C/go.jsonvalue/#Set.At
|
||||
//
|
||||
// Set 开始设置一个 JSON 子成员。任何合法的 JSON 类型都可以作为参数, 比如 string, int,
|
||||
// float, bool, nil, *jsonvalue.V 等类型, 甚至也支持结构体、map、切片、数组。
|
||||
//
|
||||
// 请参见 "func (set Setter) At(...)" 例子.
|
||||
//
|
||||
// https://godoc.org/github.com/Andrew-M-C/go.jsonvalue/#Set.At
|
||||
func (v *V) Set(child any) Setter {
|
||||
var ch *V
|
||||
var err error
|
||||
|
||||
if child == nil {
|
||||
ch = NewNull()
|
||||
} else if childV, ok := child.(*V); ok {
|
||||
ch = childV
|
||||
} else {
|
||||
ch, err = Import(child)
|
||||
}
|
||||
|
||||
return &setter{
|
||||
v: v,
|
||||
c: ch,
|
||||
err: err,
|
||||
}
|
||||
}
|
||||
|
||||
// SetString is equivalent to Set(jsonvalue.NewString(s))
|
||||
//
|
||||
// SetString 等效于 Set(jsonvalue.NewString(s))
|
||||
func (v *V) SetString(s string) Setter {
|
||||
return v.Set(NewString(s))
|
||||
}
|
||||
|
||||
// SetBytes is equivalent to Set(NewString(base64.StdEncoding.EncodeToString(b)))
|
||||
//
|
||||
// SetBytes 等效于 Set(NewString(base64.StdEncoding.EncodeToString(b)))
|
||||
func (v *V) SetBytes(b []byte) Setter {
|
||||
s := internal.b64.EncodeToString(b)
|
||||
return v.SetString(s)
|
||||
}
|
||||
|
||||
// SetBool is equivalent to Set(jsonvalue.NewBool(b))
|
||||
//
|
||||
// SetBool 等效于 Set(jsonvalue.NewBool(b))
|
||||
func (v *V) SetBool(b bool) Setter {
|
||||
return v.Set(NewBool(b))
|
||||
}
|
||||
|
||||
// SetInt is equivalent to Set(jsonvalue.NewInt(b))
|
||||
//
|
||||
// SetInt 等效于 Set(jsonvalue.NewInt(b))
|
||||
func (v *V) SetInt(i int) Setter {
|
||||
return v.Set(NewInt(i))
|
||||
}
|
||||
|
||||
// SetInt64 is equivalent to Set(jsonvalue.NewInt64(b))
|
||||
//
|
||||
// SetInt64 等效于 Set(jsonvalue.NewInt64(b))
|
||||
func (v *V) SetInt64(i int64) Setter {
|
||||
return v.Set(NewInt64(i))
|
||||
}
|
||||
|
||||
// SetInt32 is equivalent to Set(jsonvalue.NewInt32(b))
|
||||
//
|
||||
// SetInt32 等效于 Set(jsonvalue.NewInt32(b))
|
||||
func (v *V) SetInt32(i int32) Setter {
|
||||
return v.Set(NewInt32(i))
|
||||
}
|
||||
|
||||
// SetUint is equivalent to Set(jsonvalue.NewUint(b))
|
||||
//
|
||||
// SetUint 等效于 Set(jsonvalue.NewUint(b))
|
||||
func (v *V) SetUint(u uint) Setter {
|
||||
return v.Set(NewUint(u))
|
||||
}
|
||||
|
||||
// SetUint64 is equivalent to Set(jsonvalue.NewUint64(b))
|
||||
//
|
||||
// SetUint64 is equivalent to Set(jsonvalue.NewUint64(b))
|
||||
func (v *V) SetUint64(u uint64) Setter {
|
||||
return v.Set(NewUint64(u))
|
||||
}
|
||||
|
||||
// SetUint32 is equivalent to Set(jsonvalue.NewUint32(b))
|
||||
//
|
||||
// SetUint32 等效于 Set(jsonvalue.NewUint32(b))
|
||||
func (v *V) SetUint32(u uint32) Setter {
|
||||
return v.Set(NewUint32(u))
|
||||
}
|
||||
|
||||
// SetFloat64 is equivalent to Set(jsonvalue.NewFloat64(b))
|
||||
//
|
||||
// SetFloat64 等效于 Set(jsonvalue.NewFloat64(b))
|
||||
func (v *V) SetFloat64(f float64) Setter {
|
||||
return v.Set(NewFloat64(f))
|
||||
}
|
||||
|
||||
// SetFloat32 is equivalent to Set(jsonvalue.NewFloat32(b))
|
||||
//
|
||||
// SetFloat32 等效于 Set(jsonvalue.NewFloat32(b))
|
||||
func (v *V) SetFloat32(f float32) Setter {
|
||||
return v.Set(NewFloat32(f))
|
||||
}
|
||||
|
||||
// SetNull is equivalent to Set(jsonvalue.NewNull())
|
||||
//
|
||||
// SetNull 等效于 Set(jsonvalue.NewNull())
|
||||
func (v *V) SetNull() Setter {
|
||||
return v.Set(NewNull())
|
||||
}
|
||||
|
||||
// SetObject is equivalent to Set(jsonvalue.NewObject())
|
||||
//
|
||||
// SetObject 等效于 Set(jsonvalue.NewObject())
|
||||
func (v *V) SetObject() Setter {
|
||||
return v.Set(NewObject())
|
||||
}
|
||||
|
||||
// SetArray is equivalent to Set(jsonvalue.NewArray())
|
||||
//
|
||||
// SetArray 等效于 Set(jsonvalue.NewArray())
|
||||
func (v *V) SetArray() Setter {
|
||||
return v.Set(NewArray())
|
||||
}
|
||||
|
||||
func setToObjectChildren(v *V, key string, child *V) {
|
||||
v.children.incrID++
|
||||
v.children.object[key] = childWithProperty{
|
||||
id: v.children.incrID,
|
||||
v: child,
|
||||
}
|
||||
addCaselessKey(v, key)
|
||||
}
|
||||
|
||||
func (s *setter) At(firstParam any, otherParams ...any) (*V, error) {
|
||||
if s.err != nil {
|
||||
return &V{}, s.err
|
||||
}
|
||||
if ok, p1, p2 := isSliceAndExtractDividedParams(firstParam); ok {
|
||||
if len(otherParams) > 0 {
|
||||
return &V{}, ErrMultipleParamNotSupportedWithIfSliceOrArrayGiven
|
||||
}
|
||||
return s.At(p1, p2...)
|
||||
}
|
||||
v := s.v
|
||||
c := s.c
|
||||
if nil == v || v.valueType == NotExist {
|
||||
return &V{}, ErrValueUninitialized
|
||||
}
|
||||
if nil == c || c.valueType == NotExist {
|
||||
return &V{}, ErrValueUninitialized
|
||||
}
|
||||
|
||||
// this is the last iteration
|
||||
if len(otherParams) == 0 {
|
||||
return s.atLastParam(firstParam)
|
||||
}
|
||||
|
||||
// this is not the last iterarion
|
||||
if v.valueType == Object {
|
||||
return s.atObject(firstParam, otherParams)
|
||||
}
|
||||
|
||||
// array type
|
||||
if v.valueType == Array {
|
||||
return s.atArray(firstParam, otherParams)
|
||||
}
|
||||
|
||||
// illegal type
|
||||
return &V{}, fmt.Errorf("%v type does not supports Set()", v.valueType)
|
||||
}
|
||||
|
||||
func (s *setter) atLastParam(p any) (*V, error) {
|
||||
v := s.v
|
||||
c := s.c
|
||||
switch v.valueType {
|
||||
default:
|
||||
return &V{}, fmt.Errorf("%v type does not supports Set()", v.valueType)
|
||||
|
||||
case Object:
|
||||
var k string
|
||||
k, err := anyToString(p)
|
||||
if err != nil {
|
||||
return &V{}, err
|
||||
}
|
||||
setToObjectChildren(v, k, c)
|
||||
return c, nil
|
||||
|
||||
case Array:
|
||||
pos, err := anyToInt(p)
|
||||
if err != nil {
|
||||
return &V{}, err
|
||||
}
|
||||
err = setAtIndex(v, c, pos)
|
||||
if err != nil {
|
||||
return &V{}, err
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (s *setter) atObject(firstParam any, otherParams []any) (*V, error) {
|
||||
v := s.v
|
||||
c := s.c
|
||||
k, err := anyToString(firstParam)
|
||||
if err != nil {
|
||||
return &V{}, err
|
||||
}
|
||||
child, exist := getFromObjectChildren(v, false, k)
|
||||
if !exist {
|
||||
if _, err := anyToString(otherParams[0]); err == nil {
|
||||
child = NewObject()
|
||||
} else if i, err := anyToInt(otherParams[0]); err == nil {
|
||||
if i != 0 {
|
||||
return &V{}, ErrOutOfRange
|
||||
}
|
||||
child = NewArray()
|
||||
} else {
|
||||
return &V{}, fmt.Errorf("unexpected type %v for Set()", reflect.TypeOf(otherParams[0]))
|
||||
}
|
||||
}
|
||||
next := &setter{
|
||||
v: child,
|
||||
c: c,
|
||||
}
|
||||
_, err = next.At(otherParams[0], otherParams[1:]...)
|
||||
if err != nil {
|
||||
return &V{}, err
|
||||
}
|
||||
if !exist {
|
||||
setToObjectChildren(v, k, child)
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (s *setter) atArray(firstParam any, otherParams []any) (*V, error) {
|
||||
v := s.v
|
||||
c := s.c
|
||||
pos, err := anyToInt(firstParam)
|
||||
if err != nil {
|
||||
return &V{}, err
|
||||
}
|
||||
child, ok := childAtIndex(v, pos)
|
||||
isNewChild := false
|
||||
if !ok {
|
||||
isNewChild = true
|
||||
if _, err := anyToString(otherParams[0]); err == nil {
|
||||
child = NewObject()
|
||||
} else if i, err := anyToInt(otherParams[0]); err == nil {
|
||||
if i != 0 {
|
||||
return &V{}, ErrOutOfRange
|
||||
}
|
||||
child = NewArray()
|
||||
} else {
|
||||
return &V{}, fmt.Errorf("unexpected type %v for Set()", reflect.TypeOf(otherParams[0]))
|
||||
}
|
||||
}
|
||||
next := &setter{
|
||||
v: child,
|
||||
c: c,
|
||||
}
|
||||
_, err = next.At(otherParams[0], otherParams[1:]...)
|
||||
if err != nil {
|
||||
return &V{}, err
|
||||
}
|
||||
// OK to add this object
|
||||
if isNewChild {
|
||||
appendToArr(v, child)
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func posAtIndexForSet(v *V, pos int) (newPos int, appendToEnd bool) {
|
||||
if pos == len(v.children.arr) {
|
||||
return pos, true
|
||||
}
|
||||
pos = posAtIndexForRead(v, pos)
|
||||
return pos, false
|
||||
}
|
||||
|
||||
func posAtIndexForInsertBefore(v *V, pos int) (newPos int) {
|
||||
le := len(v.children.arr)
|
||||
if le == 0 {
|
||||
return -1
|
||||
}
|
||||
|
||||
if pos == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
if pos < 0 {
|
||||
pos += le
|
||||
if pos < 0 {
|
||||
return -1
|
||||
}
|
||||
return pos
|
||||
}
|
||||
|
||||
if pos >= le {
|
||||
return -1
|
||||
}
|
||||
|
||||
return pos
|
||||
}
|
||||
|
||||
func posAtIndexForInsertAfter(v *V, pos int) (newPos int, appendToEnd bool) {
|
||||
le := len(v.children.arr)
|
||||
if le == 0 {
|
||||
return -1, false
|
||||
}
|
||||
|
||||
if pos == -1 {
|
||||
return le, true
|
||||
}
|
||||
|
||||
if pos < 0 {
|
||||
pos += le
|
||||
if pos < 0 {
|
||||
return -1, false
|
||||
}
|
||||
return pos + 1, false
|
||||
}
|
||||
|
||||
if pos >= le {
|
||||
return -1, false
|
||||
}
|
||||
|
||||
return pos + 1, false
|
||||
}
|
||||
|
||||
func posAtIndexForRead(v *V, pos int) int {
|
||||
le := len(v.children.arr)
|
||||
if le == 0 {
|
||||
return -1
|
||||
}
|
||||
|
||||
if pos < 0 {
|
||||
pos += le
|
||||
if pos < 0 {
|
||||
return -1
|
||||
}
|
||||
return pos
|
||||
}
|
||||
|
||||
if pos >= le {
|
||||
return -1
|
||||
}
|
||||
|
||||
return pos
|
||||
}
|
||||
|
||||
func childAtIndex(v *V, pos int) (*V, bool) { // if nil returned, means that just push
|
||||
pos = posAtIndexForRead(v, pos)
|
||||
if pos < 0 {
|
||||
return &V{}, false
|
||||
}
|
||||
return v.children.arr[pos], true
|
||||
}
|
||||
|
||||
func setAtIndex(v *V, child *V, pos int) error {
|
||||
pos, appendToEnd := posAtIndexForSet(v, pos)
|
||||
if pos < 0 {
|
||||
return ErrOutOfRange
|
||||
}
|
||||
if appendToEnd {
|
||||
v.children.arr = append(v.children.arr, child)
|
||||
} else {
|
||||
v.children.arr[pos] = child
|
||||
}
|
||||
return nil
|
||||
}
|
162
vendor/github.com/Andrew-M-C/go.jsonvalue/set_must.go
generated
vendored
Normal file
162
vendor/github.com/Andrew-M-C/go.jsonvalue/set_must.go
generated
vendored
Normal file
@ -0,0 +1,162 @@
|
||||
package jsonvalue
|
||||
|
||||
// MARK: v.MustSet(xxx).At(xxx)
|
||||
|
||||
// MustSetter is just like Setter, but not returning sub-value or error.
|
||||
type MustSetter interface {
|
||||
// At completes the following operation of Set(). It defines position of value
|
||||
// in Set() and return the new value set.
|
||||
//
|
||||
// The usage of At() is perhaps the most important. This function will recursively
|
||||
// search for child value, and set the new value specified by Set() or SetXxx()
|
||||
// series functions. Please unfold and read the following examples, they are important.
|
||||
//
|
||||
// At 完成 Set() 函数的后续操作并设置相应的子成员。其参数指定了应该在哪个位置设置子成员,
|
||||
// 并且返回被设置的子成员对象。
|
||||
//
|
||||
// 该函数的用法恐怕是 jsonvalue 中最重要的内容了:该函数会按照给定的可变参数递归地一层一层查找
|
||||
// JSON 值的子成员,并且设置到指定的位置上。设置的逻辑说明起来比较抽象,请打开以下的例子以了解,
|
||||
// 这非常重要。
|
||||
At(firstParam any, otherParams ...any)
|
||||
}
|
||||
|
||||
type mSetter struct {
|
||||
setter Setter
|
||||
}
|
||||
|
||||
// MustSet is just like Set, but not returning sub-value or error.
|
||||
func (v *V) MustSet(child any) MustSetter {
|
||||
setter := v.Set(child)
|
||||
return mSetter{
|
||||
setter: setter,
|
||||
}
|
||||
}
|
||||
|
||||
// MustSetString is equivalent to Set(jsonvalue.NewString(s))
|
||||
//
|
||||
// MustSetString 等效于 Set(jsonvalue.NewString(s))
|
||||
func (v *V) MustSetString(s string) MustSetter {
|
||||
return v.MustSet(NewString(s))
|
||||
}
|
||||
|
||||
// MustSetBytes is equivalent to Set(NewString(base64.StdEncoding.EncodeToString(b)))
|
||||
//
|
||||
// MustSetBytes 等效于 Set(NewString(base64.StdEncoding.EncodeToString(b)))
|
||||
func (v *V) MustSetBytes(b []byte) MustSetter {
|
||||
s := internal.b64.EncodeToString(b)
|
||||
return v.MustSetString(s)
|
||||
}
|
||||
|
||||
// MustSetBool is equivalent to Set(jsonvalue.NewBool(b))
|
||||
//
|
||||
// MustSetBool 等效于 Set(jsonvalue.NewBool(b))
|
||||
func (v *V) MustSetBool(b bool) MustSetter {
|
||||
return v.MustSet(NewBool(b))
|
||||
}
|
||||
|
||||
// MustSetInt is equivalent to Set(jsonvalue.NewInt(b))
|
||||
//
|
||||
// MustSetInt 等效于 Set(jsonvalue.NewInt(b))
|
||||
func (v *V) MustSetInt(i int) MustSetter {
|
||||
return v.MustSet(NewInt(i))
|
||||
}
|
||||
|
||||
// MustSetInt64 is equivalent to Set(jsonvalue.NewInt64(b))
|
||||
//
|
||||
// MustSetInt64 等效于 Set(jsonvalue.NewInt64(b))
|
||||
func (v *V) MustSetInt64(i int64) MustSetter {
|
||||
return v.MustSet(NewInt64(i))
|
||||
}
|
||||
|
||||
// MustSetInt32 is equivalent to Set(jsonvalue.NewInt32(b))
|
||||
//
|
||||
// MustSetInt32 等效于 Set(jsonvalue.NewInt32(b))
|
||||
func (v *V) MustSetInt32(i int32) MustSetter {
|
||||
return v.MustSet(NewInt32(i))
|
||||
}
|
||||
|
||||
// MustSetUint is equivalent to Set(jsonvalue.NewUint(b))
|
||||
//
|
||||
// MustSetUint 等效于 Set(jsonvalue.NewUint(b))
|
||||
func (v *V) MustSetUint(u uint) MustSetter {
|
||||
return v.MustSet(NewUint(u))
|
||||
}
|
||||
|
||||
// MustSetUint64 is equivalent to Set(jsonvalue.NewUint64(b))
|
||||
//
|
||||
// MustSetUint64 is equivalent to Set(jsonvalue.NewUint64(b))
|
||||
func (v *V) MustSetUint64(u uint64) MustSetter {
|
||||
return v.MustSet(NewUint64(u))
|
||||
}
|
||||
|
||||
// MustSetUint32 is equivalent to Set(jsonvalue.NewUint32(b))
|
||||
//
|
||||
// MustSetUint32 等效于 Set(jsonvalue.NewUint32(b))
|
||||
func (v *V) MustSetUint32(u uint32) MustSetter {
|
||||
return v.MustSet(NewUint32(u))
|
||||
}
|
||||
|
||||
// MustSetFloat64 is equivalent to Set(jsonvalue.NewFloat64(b))
|
||||
//
|
||||
// MustSetFloat64 等效于 Set(jsonvalue.NewFloat64(b))
|
||||
func (v *V) MustSetFloat64(f float64) MustSetter {
|
||||
return v.MustSet(NewFloat64(f))
|
||||
}
|
||||
|
||||
// MustSetFloat32 is equivalent to Set(jsonvalue.NewFloat32(b))
|
||||
//
|
||||
// MustSetFloat32 等效于 Set(jsonvalue.NewFloat32(b))
|
||||
func (v *V) MustSetFloat32(f float32) MustSetter {
|
||||
return v.MustSet(NewFloat32(f))
|
||||
}
|
||||
|
||||
// MustSetNull is equivalent to Set(jsonvalue.NewNull())
|
||||
//
|
||||
// MustSetNull 等效于 Set(jsonvalue.NewNull())
|
||||
func (v *V) MustSetNull() MustSetter {
|
||||
return v.MustSet(NewNull())
|
||||
}
|
||||
|
||||
// MustSetObject is equivalent to Set(jsonvalue.NewObject())
|
||||
//
|
||||
// MustSetObject 等效于 Set(jsonvalue.NewObject())
|
||||
func (v *V) MustSetObject() MustSetter {
|
||||
return v.MustSet(NewObject())
|
||||
}
|
||||
|
||||
// MustSetArray is equivalent to Set(jsonvalue.NewArray())
|
||||
//
|
||||
// MustSetArray 等效于 Set(jsonvalue.NewArray())
|
||||
func (v *V) MustSetArray() MustSetter {
|
||||
return v.MustSet(NewArray())
|
||||
}
|
||||
|
||||
func (s mSetter) At(firstParam any, otherParams ...any) {
|
||||
_, _ = s.setter.At(firstParam, otherParams...)
|
||||
}
|
||||
|
||||
// MARK: v.At(xxx).Set(xxx)
|
||||
|
||||
// AtSetter works like v.MustSet(...).At(...), just with different sequence.
|
||||
type AtSetter interface {
|
||||
Set(subValue any)
|
||||
}
|
||||
|
||||
// At works like v.MustSet(...).At(...), just with different sequence.
|
||||
func (v *V) At(firstParam any, otherParams ...any) AtSetter {
|
||||
return atSetter{
|
||||
v: v,
|
||||
firstParam: firstParam,
|
||||
otherParams: otherParams,
|
||||
}
|
||||
}
|
||||
|
||||
type atSetter struct {
|
||||
v *V
|
||||
firstParam any
|
||||
otherParams []any
|
||||
}
|
||||
|
||||
func (a atSetter) Set(sub any) {
|
||||
a.v.MustSet(sub).At(a.firstParam, a.otherParams...)
|
||||
}
|
326
vendor/github.com/Andrew-M-C/go.jsonvalue/sort.go
generated
vendored
Normal file
326
vendor/github.com/Andrew-M-C/go.jsonvalue/sort.go
generated
vendored
Normal file
@ -0,0 +1,326 @@
|
||||
package jsonvalue
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/Andrew-M-C/go.jsonvalue/internal/buffer"
|
||||
)
|
||||
|
||||
// ---------------- array sorting ----------------
|
||||
|
||||
// ArrayLessFunc is used in SortArray(), identifying which member is ahead.
|
||||
//
|
||||
// ArrayLessFunc 用于 SortArray() 函数中,指定两个成员谁在前面。
|
||||
type ArrayLessFunc func(v1, v2 *V) bool
|
||||
|
||||
// SortArray is used to re-arrange sequence of the array. Invokers should pass less function for sorting.
|
||||
// Nothing would happens either lessFunc is nil or v is not an array.
|
||||
//
|
||||
// SortArray 用于对 array 类型的 JSON 的子成员进行重新排序。基本逻辑与 sort.Sort 函数相同。当 lessFunc 为 nil,或者当前 JSON 不是一个
|
||||
// array 类型时,什么变化都不会发生。
|
||||
func (v *V) SortArray(lessFunc ArrayLessFunc) {
|
||||
if nil == lessFunc {
|
||||
return
|
||||
}
|
||||
if !v.IsArray() {
|
||||
return
|
||||
}
|
||||
|
||||
sav := newSortV(v, lessFunc)
|
||||
sav.Sort()
|
||||
}
|
||||
|
||||
type sortArrayV struct {
|
||||
v *V
|
||||
lessFunc ArrayLessFunc
|
||||
}
|
||||
|
||||
func newSortV(v *V, lessFunc ArrayLessFunc) *sortArrayV {
|
||||
sav := sortArrayV{
|
||||
v: v,
|
||||
lessFunc: lessFunc,
|
||||
}
|
||||
return &sav
|
||||
}
|
||||
|
||||
func (v *sortArrayV) Sort() {
|
||||
sort.Sort(v)
|
||||
}
|
||||
|
||||
func (v *sortArrayV) Len() int {
|
||||
return len(v.v.children.arr)
|
||||
}
|
||||
|
||||
func (v *sortArrayV) Less(i, j int) bool {
|
||||
v1 := v.v.children.arr[i]
|
||||
v2 := v.v.children.arr[j]
|
||||
return v.lessFunc(v1, v2)
|
||||
}
|
||||
|
||||
func (v *sortArrayV) Swap(i, j int) {
|
||||
v.v.children.arr[i], v.v.children.arr[j] = v.v.children.arr[j], v.v.children.arr[i]
|
||||
}
|
||||
|
||||
// ---------------- marshal sorting ----------------
|
||||
|
||||
// Key is the element of KeyPath
|
||||
//
|
||||
// Key 是 KeyPath 类型的成员
|
||||
type Key struct {
|
||||
s string
|
||||
i int
|
||||
}
|
||||
|
||||
func intKey(i int) Key {
|
||||
return Key{i: i}
|
||||
}
|
||||
|
||||
func stringKey(s string) Key {
|
||||
return Key{s: s}
|
||||
}
|
||||
|
||||
// String returns string value of a key
|
||||
//
|
||||
// String 返回当前键值对的键的描述
|
||||
func (k *Key) String() string {
|
||||
if k.s != "" {
|
||||
return k.s
|
||||
}
|
||||
return strconv.Itoa(k.i)
|
||||
}
|
||||
|
||||
// IsString tells if current key is a string, which indicates a child of an object.
|
||||
//
|
||||
// IsString 判断当前的键是不是一个 string 类型,如果是的话,那么它是一个 object JSON 的子成员。
|
||||
func (k *Key) IsString() bool {
|
||||
return k.s != ""
|
||||
}
|
||||
|
||||
// Int returns int value of a key.
|
||||
//
|
||||
// Int 返回当前键值对的 int 值。
|
||||
func (k *Key) Int() int {
|
||||
if k.s == "" {
|
||||
return k.i
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// IsInt tells if current key is a integer, which indicates a child of an array
|
||||
//
|
||||
// IsInt 判断当前的键是不是一个整型类型,如果是的话,那么它是一个 array JSON 的子成员。
|
||||
func (k *Key) IsInt() bool {
|
||||
return k.s == ""
|
||||
}
|
||||
|
||||
// KeyPath identifies a full path of keys of object in jsonvalue.
|
||||
//
|
||||
// KeyPath 表示一个对象在指定 jsonvalue 中的完整的键路径。
|
||||
type KeyPath []*Key
|
||||
|
||||
// String returns last element of key path.
|
||||
//
|
||||
// String 返回 KeyPath 的最后一个成员的描述。
|
||||
func (p KeyPath) String() (s string) {
|
||||
buff := bytes.Buffer{}
|
||||
buff.WriteRune('[')
|
||||
|
||||
defer func() {
|
||||
buff.WriteRune(']')
|
||||
s = buff.String()
|
||||
}()
|
||||
|
||||
for i, k := range p {
|
||||
if i > 0 {
|
||||
buff.WriteRune(' ')
|
||||
}
|
||||
if k.IsInt() {
|
||||
s := strconv.Itoa(k.Int())
|
||||
buff.WriteString(s)
|
||||
} else {
|
||||
buff.WriteRune('"')
|
||||
escapeStringToBuff(k.String(), &buff, getDefaultOptions())
|
||||
buff.WriteRune('"')
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// ParentInfo show information of parent of a JSON value.
|
||||
//
|
||||
// ParentInfo 表示一个 JSON 值的父节点信息。
|
||||
type ParentInfo struct {
|
||||
Parent *V
|
||||
KeyPath KeyPath
|
||||
}
|
||||
|
||||
func newParentInfo(v *V, nilableParentInfo *ParentInfo, key Key) *ParentInfo {
|
||||
if nil == nilableParentInfo {
|
||||
return &ParentInfo{
|
||||
Parent: v,
|
||||
KeyPath: KeyPath{&key},
|
||||
}
|
||||
}
|
||||
|
||||
return &ParentInfo{
|
||||
Parent: v,
|
||||
KeyPath: append(nilableParentInfo.KeyPath, &key),
|
||||
}
|
||||
}
|
||||
|
||||
// MarshalLessFunc is used in marshaling, for sorting marshaled data.
|
||||
//
|
||||
// MarshalLessFunc 用于序列化,指定 object 类型的 JSON 的键值对顺序。
|
||||
type MarshalLessFunc func(nilableParent *ParentInfo, key1, key2 string, v1, v2 *V) bool
|
||||
|
||||
// DefaultStringSequence simply use strings.Compare() to define the sequence
|
||||
// of various key-value pairs of an object value.
|
||||
// This function is used in Opt.MarshalLessFunc.
|
||||
//
|
||||
// DefaultStringSequence 使用 strings.Compare() 函数来判断键值对的顺序。用于 Opt.MarshalLessFunc。
|
||||
func DefaultStringSequence(parent *ParentInfo, key1, key2 string, v1, v2 *V) bool {
|
||||
return strings.Compare(key1, key2) <= 0
|
||||
}
|
||||
|
||||
func (sov *sortObjectV) marshalObjectWithLessFunc(buf buffer.Buffer, opt *Opt) {
|
||||
// sort
|
||||
sort.Sort(sov)
|
||||
|
||||
// marshal
|
||||
firstWritten := false
|
||||
for i, key := range sov.keys {
|
||||
child := sov.values[i]
|
||||
par := newParentInfo(child, sov.parentInfo, stringKey(key))
|
||||
firstWritten = writeObjectChildren(par, buf, !firstWritten, key, child, opt)
|
||||
}
|
||||
}
|
||||
|
||||
type sortObjectV struct {
|
||||
parentInfo *ParentInfo
|
||||
lessFunc MarshalLessFunc
|
||||
keys []string
|
||||
values []*V
|
||||
}
|
||||
|
||||
func (sov *sortObjectV) Len() int {
|
||||
return len(sov.values)
|
||||
}
|
||||
|
||||
func (sov *sortObjectV) Less(i, j int) bool {
|
||||
return sov.lessFunc(sov.parentInfo, sov.keys[i], sov.keys[j], sov.values[i], sov.values[j])
|
||||
}
|
||||
|
||||
func (sov *sortObjectV) Swap(i, j int) {
|
||||
sov.keys[i], sov.keys[j] = sov.keys[j], sov.keys[i]
|
||||
sov.values[i], sov.values[j] = sov.values[j], sov.values[i]
|
||||
}
|
||||
|
||||
func newSortObjectV(v *V, parentInfo *ParentInfo, opt *Opt) *sortObjectV {
|
||||
sov := sortObjectV{
|
||||
parentInfo: parentInfo,
|
||||
lessFunc: opt.MarshalLessFunc,
|
||||
keys: make([]string, 0, len(v.children.object)),
|
||||
values: make([]*V, 0, len(v.children.object)),
|
||||
}
|
||||
for k, child := range v.children.object {
|
||||
sov.keys = append(sov.keys, k)
|
||||
sov.values = append(sov.values, child.v)
|
||||
}
|
||||
|
||||
return &sov
|
||||
}
|
||||
|
||||
// marshalObjectWithStringSlice use a slice to determine sequence of object
|
||||
func (sssv *sortStringSliceV) marshalObjectWithStringSlice(buf buffer.Buffer, opt *Opt) {
|
||||
// sort
|
||||
sort.Sort(sssv)
|
||||
|
||||
// marshal
|
||||
firstWritten := false
|
||||
for i, key := range sssv.keys {
|
||||
child := sssv.values[i]
|
||||
firstWritten = writeObjectChildren(nil, buf, !firstWritten, key, child, opt)
|
||||
}
|
||||
}
|
||||
|
||||
type sortStringSliceV struct {
|
||||
v *V
|
||||
seq map[string]int
|
||||
keys []string
|
||||
values []*V
|
||||
}
|
||||
|
||||
func newSortStringSliceV(v *V, opt *Opt) *sortStringSliceV {
|
||||
if nil == opt.keySequence {
|
||||
opt.keySequence = make(map[string]int, len(opt.MarshalKeySequence))
|
||||
for i, str := range opt.MarshalKeySequence {
|
||||
opt.keySequence[str] = i
|
||||
}
|
||||
}
|
||||
|
||||
sssv := sortStringSliceV{
|
||||
v: v,
|
||||
seq: opt.keySequence,
|
||||
keys: make([]string, 0, v.Len()),
|
||||
values: make([]*V, 0, v.Len()),
|
||||
}
|
||||
for k, child := range v.children.object {
|
||||
sssv.keys = append(sssv.keys, k)
|
||||
sssv.values = append(sssv.values, child.v)
|
||||
}
|
||||
|
||||
return &sssv
|
||||
}
|
||||
|
||||
func newSortStringSliceVBySetSeq(v *V) *sortStringSliceV {
|
||||
keySequence := make(map[string]int, len(v.children.object))
|
||||
for k, child := range v.children.object {
|
||||
keySequence[k] = int(child.id)
|
||||
}
|
||||
|
||||
sssv := sortStringSliceV{
|
||||
v: v,
|
||||
seq: keySequence,
|
||||
keys: make([]string, 0, v.Len()),
|
||||
values: make([]*V, 0, v.Len()),
|
||||
}
|
||||
for k, child := range v.children.object {
|
||||
sssv.keys = append(sssv.keys, k)
|
||||
sssv.values = append(sssv.values, child.v)
|
||||
}
|
||||
|
||||
return &sssv
|
||||
}
|
||||
|
||||
func (sssv *sortStringSliceV) Len() int {
|
||||
return len(sssv.values)
|
||||
}
|
||||
|
||||
func (sssv *sortStringSliceV) Less(i, j int) bool {
|
||||
k1 := sssv.keys[i]
|
||||
k2 := sssv.keys[j]
|
||||
|
||||
seq1, exist1 := sssv.seq[k1]
|
||||
seq2, exist2 := sssv.seq[k2]
|
||||
|
||||
if exist1 {
|
||||
if exist2 {
|
||||
return seq1 < seq2
|
||||
}
|
||||
return true
|
||||
}
|
||||
if exist2 {
|
||||
return false
|
||||
}
|
||||
|
||||
return k1 <= k2
|
||||
}
|
||||
|
||||
func (sssv *sortStringSliceV) Swap(i, j int) {
|
||||
sssv.keys[i], sssv.keys[j] = sssv.keys[j], sssv.keys[i]
|
||||
sssv.values[i], sssv.values[j] = sssv.values[j], sssv.values[i]
|
||||
}
|
900
vendor/github.com/Andrew-M-C/go.jsonvalue/unmarshal.go
generated
vendored
Normal file
900
vendor/github.com/Andrew-M-C/go.jsonvalue/unmarshal.go
generated
vendored
Normal file
@ -0,0 +1,900 @@
|
||||
package jsonvalue
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/Andrew-M-C/go.jsonvalue/internal/unsafe"
|
||||
)
|
||||
|
||||
// ================ OUTER UNMARSHAL ================
|
||||
|
||||
// unmarshalWithIter parse bytes with unknown value type.
|
||||
func unmarshalWithIter(p pool, it iter, offset int) (v *V, err error) {
|
||||
end := len(it)
|
||||
offset, reachEnd := it.skipBlanks(offset)
|
||||
if reachEnd {
|
||||
return &V{}, fmt.Errorf("%w, cannot find any symbol characters found", ErrRawBytesUnrecognized)
|
||||
}
|
||||
|
||||
chr := it[offset]
|
||||
switch chr {
|
||||
case '{':
|
||||
v, offset, err = unmarshalObjectWithIterUnknownEnd(p, it, offset, end)
|
||||
|
||||
case '[':
|
||||
v, offset, err = unmarshalArrayWithIterUnknownEnd(p, it, offset, end)
|
||||
|
||||
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-':
|
||||
var n *V
|
||||
n, offset, _, err = it.parseNumber(p, offset)
|
||||
if err == nil {
|
||||
v = n
|
||||
}
|
||||
|
||||
case '"':
|
||||
var sectLenWithoutQuote int
|
||||
var sectEnd int
|
||||
sectLenWithoutQuote, sectEnd, err = it.parseStrFromBytesForwardWithQuote(offset)
|
||||
if err == nil {
|
||||
v, err = NewString(unsafe.BtoS(it[offset+1:offset+1+sectLenWithoutQuote])), nil
|
||||
offset = sectEnd
|
||||
}
|
||||
|
||||
case 't':
|
||||
offset, err = it.parseTrue(offset)
|
||||
if err == nil {
|
||||
v = NewBool(true)
|
||||
}
|
||||
|
||||
case 'f':
|
||||
offset, err = it.parseFalse(offset)
|
||||
if err == nil {
|
||||
v = NewBool(false)
|
||||
}
|
||||
|
||||
case 'n':
|
||||
offset, err = it.parseNull(offset)
|
||||
if err == nil {
|
||||
v = NewNull()
|
||||
}
|
||||
|
||||
default:
|
||||
return &V{}, fmt.Errorf("%w, invalid character \\u%04X at Position %d", ErrRawBytesUnrecognized, chr, offset)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return &V{}, err
|
||||
}
|
||||
|
||||
if offset, reachEnd = it.skipBlanks(offset, end); !reachEnd {
|
||||
return &V{}, fmt.Errorf("%w, unnecessary trailing data remains at Position %d", ErrRawBytesUnrecognized, offset)
|
||||
}
|
||||
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// unmarshalArrayWithIterUnknownEnd is similar with unmarshalArrayWithIter, though should start with '[',
|
||||
// but it does not known where its ']' is
|
||||
func unmarshalArrayWithIterUnknownEnd(p pool, it iter, offset, right int) (_ *V, end int, err error) {
|
||||
offset++
|
||||
arr := newArray(p)
|
||||
|
||||
reachEnd := false
|
||||
|
||||
for offset < right {
|
||||
// search for ending ']'
|
||||
offset, reachEnd = it.skipBlanks(offset, right)
|
||||
if reachEnd {
|
||||
// ']' not found
|
||||
return nil, -1, fmt.Errorf("%w, cannot find ']'", ErrNotArrayValue)
|
||||
}
|
||||
|
||||
chr := it[offset]
|
||||
switch chr {
|
||||
case ']':
|
||||
return arr, offset + 1, nil
|
||||
|
||||
case ',':
|
||||
offset++
|
||||
|
||||
case '{':
|
||||
v, sectEnd, err := unmarshalObjectWithIterUnknownEnd(p, it, offset, right)
|
||||
if err != nil {
|
||||
return nil, -1, err
|
||||
}
|
||||
appendToArr(arr, v)
|
||||
offset = sectEnd
|
||||
|
||||
case '[':
|
||||
v, sectEnd, err := unmarshalArrayWithIterUnknownEnd(p, it, offset, right)
|
||||
if err != nil {
|
||||
return nil, -1, err
|
||||
}
|
||||
appendToArr(arr, v)
|
||||
offset = sectEnd
|
||||
|
||||
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-':
|
||||
var v *V
|
||||
v, sectEnd, _, err := it.parseNumber(p, offset)
|
||||
if err != nil {
|
||||
return nil, -1, err
|
||||
}
|
||||
appendToArr(arr, v)
|
||||
offset = sectEnd
|
||||
|
||||
case '"':
|
||||
sectLenWithoutQuote, sectEnd, err := it.parseStrFromBytesForwardWithQuote(offset)
|
||||
if err != nil {
|
||||
return nil, -1, err
|
||||
}
|
||||
v := NewString(unsafe.BtoS(it[offset+1 : offset+1+sectLenWithoutQuote]))
|
||||
appendToArr(arr, v)
|
||||
offset = sectEnd
|
||||
|
||||
case 't':
|
||||
sectEnd, err := it.parseTrue(offset)
|
||||
if err != nil {
|
||||
return nil, -1, err
|
||||
}
|
||||
appendToArr(arr, NewBool(true))
|
||||
offset = sectEnd
|
||||
|
||||
case 'f':
|
||||
sectEnd, err := it.parseFalse(offset)
|
||||
if err != nil {
|
||||
return nil, -1, err
|
||||
}
|
||||
appendToArr(arr, NewBool(false))
|
||||
offset = sectEnd
|
||||
|
||||
case 'n':
|
||||
sectEnd, err := it.parseNull(offset)
|
||||
if err != nil {
|
||||
return nil, -1, err
|
||||
}
|
||||
appendToArr(arr, NewNull())
|
||||
offset = sectEnd
|
||||
|
||||
default:
|
||||
return nil, -1, fmt.Errorf("%w, invalid character \\u%04X at Position %d", ErrRawBytesUnrecognized, chr, offset)
|
||||
}
|
||||
}
|
||||
|
||||
return nil, -1, fmt.Errorf("%w, cannot find ']'", ErrNotArrayValue)
|
||||
}
|
||||
|
||||
func appendToArr(v *V, child *V) {
|
||||
if v.children.arr == nil {
|
||||
v.children.arr = make([]*V, 0, initialArrayCapacity)
|
||||
}
|
||||
v.children.arr = append(v.children.arr, child)
|
||||
}
|
||||
|
||||
// unmarshalObjectWithIterUnknownEnd unmarshal object from raw bytes. it[offset] must be '{'
|
||||
func unmarshalObjectWithIterUnknownEnd(p pool, it iter, offset, right int) (_ *V, end int, err error) {
|
||||
offset++
|
||||
obj := newObject(p)
|
||||
|
||||
keyStart, keyEnd := 0, 0
|
||||
colonFound := false
|
||||
|
||||
reachEnd := false
|
||||
|
||||
keyNotFoundErr := func() error {
|
||||
if keyEnd == 0 {
|
||||
return fmt.Errorf(
|
||||
"%w, missing key for another value at Position %d", ErrNotObjectValue, offset,
|
||||
)
|
||||
}
|
||||
if !colonFound {
|
||||
return fmt.Errorf(
|
||||
"%w, missing colon for key at Position %d", ErrNotObjectValue, offset,
|
||||
)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
valNotFoundErr := func() error {
|
||||
if keyEnd > 0 {
|
||||
return fmt.Errorf(
|
||||
"%w, missing value for key '%s' at Position %d",
|
||||
ErrNotObjectValue, unsafe.BtoS(it[keyStart:keyEnd]), keyStart,
|
||||
)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
for offset < right {
|
||||
offset, reachEnd = it.skipBlanks(offset, right)
|
||||
if reachEnd {
|
||||
// '}' not found
|
||||
return nil, -1, fmt.Errorf("%w, cannot find '}'", ErrNotObjectValue)
|
||||
}
|
||||
|
||||
chr := it[offset]
|
||||
switch chr {
|
||||
case '}':
|
||||
if err = valNotFoundErr(); err != nil {
|
||||
return nil, -1, err
|
||||
}
|
||||
return obj, offset + 1, nil
|
||||
|
||||
case ',':
|
||||
if err = valNotFoundErr(); err != nil {
|
||||
return nil, -1, err
|
||||
}
|
||||
offset++
|
||||
// continue
|
||||
|
||||
case ':':
|
||||
if colonFound {
|
||||
return nil, -1, fmt.Errorf("%w, duplicate colon at Position %d", ErrNotObjectValue, keyStart)
|
||||
}
|
||||
colonFound = true
|
||||
if err = keyNotFoundErr(); err != nil {
|
||||
return nil, -1, err
|
||||
}
|
||||
offset++
|
||||
// continue
|
||||
|
||||
case '{':
|
||||
if err = keyNotFoundErr(); err != nil {
|
||||
return nil, -1, err
|
||||
}
|
||||
v, sectEnd, err := unmarshalObjectWithIterUnknownEnd(p, it, offset, right)
|
||||
if err != nil {
|
||||
return nil, -1, err
|
||||
}
|
||||
setToObjectChildren(obj, unsafe.BtoS(it[keyStart:keyEnd]), v)
|
||||
keyEnd, colonFound = 0, false
|
||||
offset = sectEnd
|
||||
|
||||
case '[':
|
||||
if err = keyNotFoundErr(); err != nil {
|
||||
return nil, -1, err
|
||||
}
|
||||
v, sectEnd, err := unmarshalArrayWithIterUnknownEnd(p, it, offset, right)
|
||||
if err != nil {
|
||||
return nil, -1, err
|
||||
}
|
||||
setToObjectChildren(obj, unsafe.BtoS(it[keyStart:keyEnd]), v)
|
||||
keyEnd, colonFound = 0, false
|
||||
offset = sectEnd
|
||||
|
||||
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-':
|
||||
if err = keyNotFoundErr(); err != nil {
|
||||
return nil, -1, err
|
||||
}
|
||||
var v *V
|
||||
v, sectEnd, _, err := it.parseNumber(p, offset)
|
||||
if err != nil {
|
||||
return nil, -1, err
|
||||
}
|
||||
setToObjectChildren(obj, unsafe.BtoS(it[keyStart:keyEnd]), v)
|
||||
keyEnd, colonFound = 0, false
|
||||
offset = sectEnd
|
||||
|
||||
case '"':
|
||||
if keyEnd > 0 {
|
||||
// string value
|
||||
if !colonFound {
|
||||
return nil, -1, fmt.Errorf("%w, missing value for key '%s' at Position %d",
|
||||
ErrNotObjectValue, unsafe.BtoS(it[keyStart:keyEnd]), keyStart,
|
||||
)
|
||||
}
|
||||
sectLenWithoutQuote, sectEnd, err := it.parseStrFromBytesForwardWithQuote(offset)
|
||||
if err != nil {
|
||||
return nil, -1, err
|
||||
}
|
||||
v := NewString(unsafe.BtoS(it[offset+1 : offset+1+sectLenWithoutQuote]))
|
||||
setToObjectChildren(obj, unsafe.BtoS(it[keyStart:keyEnd]), v)
|
||||
keyEnd, colonFound = 0, false
|
||||
offset = sectEnd
|
||||
|
||||
} else {
|
||||
// string key
|
||||
sectLenWithoutQuote, sectEnd, err := it.parseStrFromBytesForwardWithQuote(offset)
|
||||
if err != nil {
|
||||
return nil, -1, err
|
||||
}
|
||||
keyStart, keyEnd = offset+1, offset+1+sectLenWithoutQuote
|
||||
offset = sectEnd
|
||||
}
|
||||
|
||||
case 't':
|
||||
if err = keyNotFoundErr(); err != nil {
|
||||
return nil, -1, err
|
||||
}
|
||||
sectEnd, err := it.parseTrue(offset)
|
||||
if err != nil {
|
||||
return nil, -1, err
|
||||
}
|
||||
setToObjectChildren(obj, unsafe.BtoS(it[keyStart:keyEnd]), NewBool(true))
|
||||
keyEnd, colonFound = 0, false
|
||||
offset = sectEnd
|
||||
|
||||
case 'f':
|
||||
if err = keyNotFoundErr(); err != nil {
|
||||
return nil, -1, err
|
||||
}
|
||||
sectEnd, err := it.parseFalse(offset)
|
||||
if err != nil {
|
||||
return nil, -1, err
|
||||
}
|
||||
setToObjectChildren(obj, unsafe.BtoS(it[keyStart:keyEnd]), NewBool(false))
|
||||
keyEnd, colonFound = 0, false
|
||||
offset = sectEnd
|
||||
|
||||
case 'n':
|
||||
if err = keyNotFoundErr(); err != nil {
|
||||
return nil, -1, err
|
||||
}
|
||||
sectEnd, err := it.parseNull(offset)
|
||||
if err != nil {
|
||||
return nil, -1, err
|
||||
}
|
||||
setToObjectChildren(obj, unsafe.BtoS(it[keyStart:keyEnd]), NewNull())
|
||||
keyEnd, colonFound = 0, false
|
||||
offset = sectEnd
|
||||
|
||||
default:
|
||||
return nil, -1, fmt.Errorf("%w, invalid character \\u%04X at Position %d", ErrRawBytesUnrecognized, chr, offset)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nil, -1, fmt.Errorf("%w, cannot find '}'", ErrNotObjectValue)
|
||||
}
|
||||
|
||||
// parseNumber parse a number string. Reference:
|
||||
//
|
||||
// - [ECMA-404 The JSON Data Interchange Standard](https://www.json.org/json-en.html)
|
||||
func parseNumber(v *V, p pool) (err error) {
|
||||
it := iter(v.srcByte)
|
||||
|
||||
parsed, end, reachEnd, err := it.parseNumber(p, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !reachEnd {
|
||||
return fmt.Errorf("invalid character: 0x%02x", v.srcByte[end])
|
||||
}
|
||||
|
||||
*v = *parsed
|
||||
return nil
|
||||
}
|
||||
|
||||
// ==== simple object parsing ====
|
||||
func newFromNumber(p pool, b []byte) (ret *V, err error) {
|
||||
v := new(p, Number)
|
||||
v.srcByte = b
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// ================ GENERAL UNMARSHALING ================
|
||||
|
||||
// iter is used to iterate []byte text
|
||||
type iter []byte
|
||||
|
||||
func (it iter) parseStrFromBytesForwardWithQuote(offset int) (sectLenWithoutQuote int, sectEnd int, err error) {
|
||||
offset++ // skip "
|
||||
end := len(it)
|
||||
sectEnd = offset
|
||||
|
||||
shift := func(i *int, le int) {
|
||||
if end-*i < le {
|
||||
err = fmt.Errorf(
|
||||
"%w, expect at least %d remaining bytes, but got %d at Position %d",
|
||||
ErrIllegalString, end-*i, le, *i,
|
||||
)
|
||||
return
|
||||
}
|
||||
it.memcpy(sectEnd, *i, le)
|
||||
sectEnd += le
|
||||
*i += le
|
||||
}
|
||||
|
||||
// iterate every byte
|
||||
for i := offset; i < end; {
|
||||
chr := it[i]
|
||||
|
||||
// ACSII?
|
||||
switch {
|
||||
case chr == '\\':
|
||||
err = it.handleEscapeStart(&i, §End)
|
||||
case chr == '"':
|
||||
// found end quote
|
||||
return sectEnd - offset, i + 1, nil
|
||||
case chr <= 0x7F:
|
||||
// shift(&i, 1)
|
||||
it[sectEnd] = it[i]
|
||||
i++
|
||||
sectEnd++
|
||||
case runeIdentifyingBytes2(chr):
|
||||
shift(&i, 2)
|
||||
case runeIdentifyingBytes3(chr):
|
||||
shift(&i, 3)
|
||||
case runeIdentifyingBytes4(chr):
|
||||
shift(&i, 4)
|
||||
default:
|
||||
err = fmt.Errorf("%w: illegal UTF8 string at Position %d", ErrIllegalString, i)
|
||||
}
|
||||
if err != nil {
|
||||
return -1, -1, err
|
||||
}
|
||||
}
|
||||
|
||||
err = errors.New("ending double quote of a string is not found")
|
||||
return
|
||||
}
|
||||
|
||||
func (it iter) handleEscapeStart(i *int, sectEnd *int) error {
|
||||
if len(it)-1-*i < 1 {
|
||||
return errors.New("escape symbol not followed by another character")
|
||||
}
|
||||
|
||||
chr := it[*i+1]
|
||||
switch chr {
|
||||
default:
|
||||
return fmt.Errorf("unrecognized character 0x%02X after escape symbol", chr)
|
||||
case '"', '\'', '/', '\\':
|
||||
it[*sectEnd] = chr
|
||||
*sectEnd++
|
||||
*i += 2
|
||||
case 'b':
|
||||
it[*sectEnd] = '\b'
|
||||
*sectEnd++
|
||||
*i += 2
|
||||
case 'f':
|
||||
it[*sectEnd] = '\f'
|
||||
*sectEnd++
|
||||
*i += 2
|
||||
case 'r':
|
||||
it[*sectEnd] = '\r'
|
||||
*sectEnd++
|
||||
*i += 2
|
||||
case 'n':
|
||||
it[*sectEnd] = '\n'
|
||||
*sectEnd++
|
||||
*i += 2
|
||||
case 't':
|
||||
it[*sectEnd] = '\t'
|
||||
*sectEnd++
|
||||
*i += 2
|
||||
case 'u':
|
||||
return it.handleEscapeUnicodeStartWithEnd(i, len(it)-1, sectEnd)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (it iter) handleEscapeUnicodeStartWithEnd(i *int, end int, sectEnd *int) (err error) {
|
||||
if end-*i <= 5 {
|
||||
return errors.New("escape symbol not followed by another character")
|
||||
}
|
||||
|
||||
b3 := chrToHex(it[*i+2], &err)
|
||||
b2 := chrToHex(it[*i+3], &err)
|
||||
b1 := chrToHex(it[*i+4], &err)
|
||||
b0 := chrToHex(it[*i+5], &err)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
r := (rune(b3) << 12) + (rune(b2) << 8) + (rune(b1) << 4) + rune(b0)
|
||||
|
||||
// this rune is smaller than 0x10000
|
||||
if r <= 0xD7FF || r >= 0xE000 {
|
||||
le := it.assignASCIICodedRune(*sectEnd, r)
|
||||
*i += 6
|
||||
*sectEnd += le
|
||||
return nil
|
||||
}
|
||||
|
||||
// reference: [JSON 序列化中的转义和 Unicode 编码](https://cloud.tencent.com/developer/article/1625557/)
|
||||
// should get another unicode-escaped character
|
||||
if end-*i <= 11 {
|
||||
return fmt.Errorf("insufficient UTF-16 data at offset %d", *i)
|
||||
}
|
||||
if it[*i+6] != '\\' || it[*i+7] != 'u' {
|
||||
return fmt.Errorf("expect unicode escape character at position %d but not", *i+6)
|
||||
}
|
||||
|
||||
ex3 := chrToHex(it[*i+8], &err)
|
||||
ex2 := chrToHex(it[*i+9], &err)
|
||||
ex1 := chrToHex(it[*i+10], &err)
|
||||
ex0 := chrToHex(it[*i+11], &err)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
ex := (rune(ex3) << 12) + (rune(ex2) << 8) + (rune(ex1) << 4) + rune(ex0)
|
||||
if ex < 0xDC00 {
|
||||
return fmt.Errorf(
|
||||
"%w, expect second UTF-16 encoding but got 0x04%X at position %d",
|
||||
ErrIllegalString, r, *i+8,
|
||||
)
|
||||
}
|
||||
ex -= 0xDC00
|
||||
if ex > 0x03FF {
|
||||
return fmt.Errorf(
|
||||
"%w, expect second UTF-16 encoding but got 0x04%X at position %d",
|
||||
ErrIllegalString, r, *i+8,
|
||||
)
|
||||
}
|
||||
|
||||
r = ((r - 0xD800) << 10) + ex + 0x10000
|
||||
|
||||
le := it.assignASCIICodedRune(*sectEnd, r)
|
||||
*i += 12
|
||||
*sectEnd += le
|
||||
return nil
|
||||
}
|
||||
|
||||
func chrToHex(chr byte, errOut *error) byte {
|
||||
if chr >= '0' && chr <= '9' {
|
||||
return chr - '0'
|
||||
}
|
||||
if chr >= 'A' && chr <= 'F' {
|
||||
return chr - 'A' + 10
|
||||
}
|
||||
if chr >= 'a' && chr <= 'f' {
|
||||
return chr - 'a' + 10
|
||||
}
|
||||
*errOut = fmt.Errorf("invalid unicode value character: %c", rune(chr))
|
||||
return 0
|
||||
}
|
||||
|
||||
func (it iter) memcpy(dst, src, length int) {
|
||||
if dst == src {
|
||||
return
|
||||
}
|
||||
copy(it[dst:dst+length], it[src:src+length])
|
||||
// ptr := unsafe.Pointer(&it[0])
|
||||
// C.memcpy(
|
||||
// unsafe.Pointer(uintptr(ptr)+uintptr(dst)),
|
||||
// unsafe.Pointer(uintptr(ptr)+uintptr(src)),
|
||||
// C.size_t(length),
|
||||
// )
|
||||
}
|
||||
|
||||
func (it iter) assignASCIICodedRune(dst int, r rune) (offset int) {
|
||||
switch {
|
||||
// 0zzzzzzz ==>
|
||||
// 0zzzzzzz
|
||||
case r <= 0x7F:
|
||||
it[dst+0] = byte(r)
|
||||
return 1
|
||||
// 00000yyy yyzzzzzz ==>
|
||||
// 110yyyyy 10zzzzzz
|
||||
case r <= 0x7FF:
|
||||
it[dst+1] = byte((r&0x03F)>>0) + 0x80
|
||||
it[dst+0] = byte((r&0x7C0)>>6) + 0xC0
|
||||
return 2
|
||||
// xxxxyyyy yyzzzzzz ==>
|
||||
// 1110xxxx 10yyyyyy 10zzzzzz
|
||||
case r <= 0xFFFF:
|
||||
it[dst+2] = byte((r&0x003F)>>0) + 0x80
|
||||
it[dst+1] = byte((r&0x0FC0)>>6) + 0x80
|
||||
it[dst+0] = byte((r&0xF000)>>12) + 0xE0
|
||||
return 3
|
||||
// 000wwwxx xxxxyyyy yyzzzzzz ==>
|
||||
// 11110www 10xxxxxx 10yyyyyy 10zzzzzz
|
||||
default:
|
||||
it[dst+3] = byte((r&0x00003F)>>0) + 0x80
|
||||
it[dst+2] = byte((r&0x000FC0)>>6) + 0x80
|
||||
it[dst+1] = byte((r&0x03F000)>>12) + 0x80
|
||||
it[dst+0] = byte((r&0x1C0000)>>18) + 0xF0
|
||||
return 4
|
||||
}
|
||||
}
|
||||
|
||||
func runeIdentifyingBytes2(chr byte) bool {
|
||||
return (chr & 0xE0) == 0xC0
|
||||
}
|
||||
|
||||
func runeIdentifyingBytes3(chr byte) bool {
|
||||
return (chr & 0xF0) == 0xE0
|
||||
}
|
||||
|
||||
func runeIdentifyingBytes4(chr byte) bool {
|
||||
return (chr & 0xF8) == 0xF0
|
||||
}
|
||||
|
||||
func (it iter) parseTrue(offset int) (end int, err error) {
|
||||
if len(it)-offset < 4 {
|
||||
return -1, fmt.Errorf("%w, insufficient character from Position %d", ErrNotValidBoolValue, offset)
|
||||
}
|
||||
|
||||
if it[offset] == 't' &&
|
||||
it[offset+1] == 'r' &&
|
||||
it[offset+2] == 'u' &&
|
||||
it[offset+3] == 'e' {
|
||||
return offset + 4, nil
|
||||
}
|
||||
|
||||
return -1, fmt.Errorf("%w, not 'true' at Position %d", ErrNotValidBoolValue, offset)
|
||||
}
|
||||
|
||||
func (it iter) parseFalse(offset int) (end int, err error) {
|
||||
if len(it)-offset < 5 {
|
||||
return -1, fmt.Errorf("%w, insufficient character from Position %d", ErrNotValidBoolValue, offset)
|
||||
}
|
||||
|
||||
if it[offset] == 'f' &&
|
||||
it[offset+1] == 'a' &&
|
||||
it[offset+2] == 'l' &&
|
||||
it[offset+3] == 's' &&
|
||||
it[offset+4] == 'e' {
|
||||
return offset + 5, nil
|
||||
}
|
||||
|
||||
return -1, fmt.Errorf("%w, not 'false' at Position %d", ErrNotValidBoolValue, offset)
|
||||
}
|
||||
|
||||
func (it iter) parseNull(offset int) (end int, err error) {
|
||||
if len(it)-offset < 4 {
|
||||
return -1, fmt.Errorf("%w, insufficient character from Position %d", ErrNotValidNullValue, offset)
|
||||
}
|
||||
|
||||
if it[offset] == 'n' &&
|
||||
it[offset+1] == 'u' &&
|
||||
it[offset+2] == 'l' &&
|
||||
it[offset+3] == 'l' {
|
||||
return offset + 4, nil
|
||||
}
|
||||
|
||||
return -1, fmt.Errorf("%w, not 'null' at Position %d", ErrNotValidBoolValue, offset)
|
||||
}
|
||||
|
||||
// skipBlanks skip blank characters until end or reaching a non-blank character
|
||||
func (it iter) skipBlanks(offset int, endPos ...int) (newOffset int, reachEnd bool) {
|
||||
end := 0
|
||||
if len(endPos) > 0 {
|
||||
end = endPos[0]
|
||||
} else {
|
||||
end = len(it)
|
||||
}
|
||||
|
||||
for offset < end {
|
||||
chr := it[offset]
|
||||
switch chr {
|
||||
case ' ', '\r', '\n', '\t', '\b':
|
||||
offset++ // continue
|
||||
default:
|
||||
return offset, false
|
||||
}
|
||||
}
|
||||
|
||||
return end, true
|
||||
}
|
||||
|
||||
// ================ FLOAT UNMARSHALING ================
|
||||
|
||||
// For state machine chart, please refer to ./img/parse_float_state_chart.drawio
|
||||
|
||||
func (it iter) parseNumber(
|
||||
p pool, offset int,
|
||||
) (v *V, end int, reachEnd bool, err error) {
|
||||
|
||||
idx := offset
|
||||
negative := false
|
||||
floated := false
|
||||
exponentGot := false
|
||||
dotGot := false
|
||||
intAfterDotGot := false
|
||||
integer := uint64(0)
|
||||
edgeFound := false
|
||||
|
||||
// len(it)-idx means remain bytes
|
||||
|
||||
for ; len(it)-idx > 0 && !edgeFound; idx++ {
|
||||
b := it[idx]
|
||||
|
||||
switch b {
|
||||
default:
|
||||
edgeFound = true
|
||||
|
||||
case '0':
|
||||
if idx == offset {
|
||||
// OK
|
||||
} else if exponentGot {
|
||||
// OK
|
||||
} else if dotGot {
|
||||
intAfterDotGot = true
|
||||
} else if negative {
|
||||
if integer == 0 && idx != offset+1 {
|
||||
err = it.numErrorf(idx, "unexpected zero")
|
||||
return
|
||||
}
|
||||
} else if integer == 0 {
|
||||
err = it.numErrorf(idx, "unexpected zero")
|
||||
return
|
||||
}
|
||||
integer *= 10
|
||||
|
||||
case '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
||||
if !floated {
|
||||
integer = integer*10 + uint64(b) - '0'
|
||||
} else if !exponentGot {
|
||||
intAfterDotGot = true
|
||||
}
|
||||
|
||||
case 'e', 'E':
|
||||
if exponentGot {
|
||||
err = it.numErrorf(idx, "unexpected exponent symbol")
|
||||
return
|
||||
}
|
||||
exponentGot = true
|
||||
floated = true
|
||||
|
||||
case '+':
|
||||
if !exponentGot {
|
||||
err = it.numErrorf(idx, "unexpected +")
|
||||
return
|
||||
}
|
||||
// Codes below not needed because this error is caught in outer logic
|
||||
// if !floated {
|
||||
// err = it.numErrorf(idx, "unexpected positive symbol")
|
||||
// return
|
||||
// }
|
||||
|
||||
case '-':
|
||||
if !floated {
|
||||
if idx != offset {
|
||||
err = it.numErrorf(idx, "unexpected negative symbol")
|
||||
return
|
||||
}
|
||||
negative = true
|
||||
}
|
||||
|
||||
case '.':
|
||||
if idx == offset || floated || exponentGot || dotGot {
|
||||
err = it.numErrorf(idx, "unexpected dot symbol")
|
||||
return
|
||||
}
|
||||
dotGot = true
|
||||
floated = true
|
||||
}
|
||||
}
|
||||
|
||||
if edgeFound {
|
||||
idx--
|
||||
}
|
||||
|
||||
if floated {
|
||||
if dotGot && !intAfterDotGot {
|
||||
err = it.numErrorf(offset, "integer after dot missing")
|
||||
return
|
||||
}
|
||||
v, err = it.parseFloatResult(p, offset, idx)
|
||||
} else {
|
||||
if integer > 0 && it[offset] == '0' {
|
||||
err = it.numErrorf(offset, "non-zero integer should not start with zero")
|
||||
return
|
||||
}
|
||||
|
||||
firstB := it[offset]
|
||||
if idx-offset == 1 {
|
||||
if firstB >= '0' && firstB <= '9' {
|
||||
// OK
|
||||
} else {
|
||||
err = it.numErrorf(offset, "invalid number format")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if negative {
|
||||
v, err = it.parseNegativeIntResult(p, offset, idx, integer)
|
||||
} else {
|
||||
v, err = it.parsePositiveIntResult(p, offset, idx, integer)
|
||||
}
|
||||
}
|
||||
|
||||
return v, idx, len(it)-idx == 0, err
|
||||
}
|
||||
|
||||
func (it iter) numErrorf(offset int, f string, a ...any) error {
|
||||
a = append([]any{offset}, a...)
|
||||
return fmt.Errorf("parsing number at index %d: "+f, a...)
|
||||
|
||||
// debug ONLY below
|
||||
|
||||
// getCaller := func(skip int) string {
|
||||
// pc, _, _, ok := runtime.Caller(skip + 1)
|
||||
// if !ok {
|
||||
// return "<caller N/A>"
|
||||
// }
|
||||
// ca := runtime.CallersFrames([]uintptr{pc})
|
||||
// fr, _ := ca.Next()
|
||||
|
||||
// fu := filepath.Ext(fr.Function)
|
||||
// fu = strings.TrimLeft(fu, ".")
|
||||
// li := fr.Line
|
||||
|
||||
// return fmt.Sprintf("%s(), Line %d", fu, li)
|
||||
// }
|
||||
// ca := getCaller(1)
|
||||
|
||||
// a = append([]any{ca, string(it), offset}, a...)
|
||||
// return fmt.Errorf("%s - parsing number \"%s\" at index %d: "+f, a...)
|
||||
}
|
||||
|
||||
const (
|
||||
uintMaxStr = "18446744073709551615"
|
||||
uintMaxDigits = 10000000000000000000
|
||||
intMin = -9223372036854775808
|
||||
intMinStr = "-9223372036854775808"
|
||||
intMinAbs = 9223372036854775808
|
||||
)
|
||||
|
||||
func (it iter) parseFloatResult(p pool, start, end int) (*V, error) {
|
||||
f, err := strconv.ParseFloat(unsafe.BtoS(it[start:end]), 64)
|
||||
if err != nil {
|
||||
return nil, it.numErrorf(start, "%w", err)
|
||||
}
|
||||
|
||||
v := new(p, Number)
|
||||
v.srcByte = it[start:end]
|
||||
|
||||
v.num.negative = f < 0
|
||||
v.num.floated = true
|
||||
v.num.i64 = int64(f)
|
||||
v.num.u64 = uint64(f)
|
||||
v.num.f64 = f
|
||||
|
||||
return v, nil
|
||||
}
|
||||
|
||||
func (it iter) parsePositiveIntResult(p pool, start, end int, integer uint64) (*V, error) {
|
||||
le := end - start
|
||||
|
||||
if le > len(uintMaxStr) {
|
||||
return nil, it.numErrorf(start, "value too large")
|
||||
} else if le == len(uintMaxStr) {
|
||||
if integer < uintMaxDigits {
|
||||
return nil, it.numErrorf(start, "value too large")
|
||||
}
|
||||
}
|
||||
|
||||
v := new(p, Number)
|
||||
v.srcByte = it[start:end]
|
||||
|
||||
v.num.negative = false
|
||||
v.num.floated = false
|
||||
v.num.i64 = int64(integer)
|
||||
v.num.u64 = uint64(integer)
|
||||
v.num.f64 = float64(integer)
|
||||
|
||||
return v, nil
|
||||
}
|
||||
|
||||
func (it iter) parseNegativeIntResult(p pool, start, end int, integer uint64) (*V, error) {
|
||||
le := end - start
|
||||
|
||||
if le > len(intMinStr) {
|
||||
return nil, it.numErrorf(start, "absolute value too large")
|
||||
} else if le == len(intMinStr) {
|
||||
if integer > intMinAbs {
|
||||
return nil, it.numErrorf(start, "absolute value too large")
|
||||
}
|
||||
}
|
||||
|
||||
v := new(p, Number)
|
||||
v.srcByte = it[start:end]
|
||||
|
||||
v.num.negative = true
|
||||
v.num.floated = false
|
||||
|
||||
if integer == intMinAbs {
|
||||
v.num.i64 = intMin
|
||||
} else {
|
||||
v.num.i64 = -int64(integer)
|
||||
}
|
||||
|
||||
v.num.u64 = uint64(v.num.i64)
|
||||
v.num.f64 = -float64(integer)
|
||||
|
||||
return v, nil
|
||||
}
|
9
vendor/github.com/shopspring/decimal/.gitignore
generated
vendored
Normal file
9
vendor/github.com/shopspring/decimal/.gitignore
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
.git
|
||||
*.swp
|
||||
|
||||
# IntelliJ
|
||||
.idea/
|
||||
*.iml
|
||||
|
||||
# VS code
|
||||
*.code-workspace
|
76
vendor/github.com/shopspring/decimal/CHANGELOG.md
generated
vendored
Normal file
76
vendor/github.com/shopspring/decimal/CHANGELOG.md
generated
vendored
Normal file
@ -0,0 +1,76 @@
|
||||
## Decimal v1.4.0
|
||||
#### BREAKING
|
||||
- Drop support for Go version older than 1.10 [#361](https://github.com/shopspring/decimal/pull/361)
|
||||
|
||||
#### FEATURES
|
||||
- Add implementation of natural logarithm [#339](https://github.com/shopspring/decimal/pull/339) [#357](https://github.com/shopspring/decimal/pull/357)
|
||||
- Add improved implementation of power operation [#358](https://github.com/shopspring/decimal/pull/358)
|
||||
- Add Compare method which forwards calls to Cmp [#346](https://github.com/shopspring/decimal/pull/346)
|
||||
- Add NewFromBigRat constructor [#288](https://github.com/shopspring/decimal/pull/288)
|
||||
- Add NewFromUint64 constructor [#352](https://github.com/shopspring/decimal/pull/352)
|
||||
|
||||
#### ENHANCEMENTS
|
||||
- Migrate to Github Actions [#245](https://github.com/shopspring/decimal/pull/245) [#340](https://github.com/shopspring/decimal/pull/340)
|
||||
- Fix examples for RoundDown, RoundFloor, RoundUp, and RoundCeil [#285](https://github.com/shopspring/decimal/pull/285) [#328](https://github.com/shopspring/decimal/pull/328) [#341](https://github.com/shopspring/decimal/pull/341)
|
||||
- Use Godoc standard to mark deprecated Equals and StringScaled methods [#342](https://github.com/shopspring/decimal/pull/342)
|
||||
- Removed unnecessary min function for RescalePair method [#265](https://github.com/shopspring/decimal/pull/265)
|
||||
- Avoid reallocation of initial slice in MarshalBinary (GobEncode) [#355](https://github.com/shopspring/decimal/pull/355)
|
||||
- Optimize NumDigits method [#301](https://github.com/shopspring/decimal/pull/301) [#356](https://github.com/shopspring/decimal/pull/356)
|
||||
- Optimize BigInt method [#359](https://github.com/shopspring/decimal/pull/359)
|
||||
- Support scanning uint64 [#131](https://github.com/shopspring/decimal/pull/131) [#364](https://github.com/shopspring/decimal/pull/364)
|
||||
- Add docs section with alternative libraries [#363](https://github.com/shopspring/decimal/pull/363)
|
||||
|
||||
#### BUGFIXES
|
||||
- Fix incorrect calculation of decimal modulo [#258](https://github.com/shopspring/decimal/pull/258) [#317](https://github.com/shopspring/decimal/pull/317)
|
||||
- Allocate new(big.Int) in Copy method to deeply clone it [#278](https://github.com/shopspring/decimal/pull/278)
|
||||
- Fix overflow edge case in QuoRem method [#322](https://github.com/shopspring/decimal/pull/322)
|
||||
|
||||
## Decimal v1.3.1
|
||||
|
||||
#### ENHANCEMENTS
|
||||
- Reduce memory allocation in case of initialization from big.Int [#252](https://github.com/shopspring/decimal/pull/252)
|
||||
|
||||
#### BUGFIXES
|
||||
- Fix binary marshalling of decimal zero value [#253](https://github.com/shopspring/decimal/pull/253)
|
||||
|
||||
## Decimal v1.3.0
|
||||
|
||||
#### FEATURES
|
||||
- Add NewFromFormattedString initializer [#184](https://github.com/shopspring/decimal/pull/184)
|
||||
- Add NewNullDecimal initializer [#234](https://github.com/shopspring/decimal/pull/234)
|
||||
- Add implementation of natural exponent function (Taylor, Hull-Abraham) [#229](https://github.com/shopspring/decimal/pull/229)
|
||||
- Add RoundUp, RoundDown, RoundCeil, RoundFloor methods [#196](https://github.com/shopspring/decimal/pull/196) [#202](https://github.com/shopspring/decimal/pull/202) [#220](https://github.com/shopspring/decimal/pull/220)
|
||||
- Add XML support for NullDecimal [#192](https://github.com/shopspring/decimal/pull/192)
|
||||
- Add IsInteger method [#179](https://github.com/shopspring/decimal/pull/179)
|
||||
- Add Copy helper method [#123](https://github.com/shopspring/decimal/pull/123)
|
||||
- Add InexactFloat64 helper method [#205](https://github.com/shopspring/decimal/pull/205)
|
||||
- Add CoefficientInt64 helper method [#244](https://github.com/shopspring/decimal/pull/244)
|
||||
|
||||
#### ENHANCEMENTS
|
||||
- Performance optimization of NewFromString init method [#198](https://github.com/shopspring/decimal/pull/198)
|
||||
- Performance optimization of Abs and Round methods [#240](https://github.com/shopspring/decimal/pull/240)
|
||||
- Additional tests (CI) for ppc64le architecture [#188](https://github.com/shopspring/decimal/pull/188)
|
||||
|
||||
#### BUGFIXES
|
||||
- Fix rounding in FormatFloat fallback path (roundShortest method, fix taken from Go main repository) [#161](https://github.com/shopspring/decimal/pull/161)
|
||||
- Add slice range checks to UnmarshalBinary method [#232](https://github.com/shopspring/decimal/pull/232)
|
||||
|
||||
## Decimal v1.2.0
|
||||
|
||||
#### BREAKING
|
||||
- Drop support for Go version older than 1.7 [#172](https://github.com/shopspring/decimal/pull/172)
|
||||
|
||||
#### FEATURES
|
||||
- Add NewFromInt and NewFromInt32 initializers [#72](https://github.com/shopspring/decimal/pull/72)
|
||||
- Add support for Go modules [#157](https://github.com/shopspring/decimal/pull/157)
|
||||
- Add BigInt, BigFloat helper methods [#171](https://github.com/shopspring/decimal/pull/171)
|
||||
|
||||
#### ENHANCEMENTS
|
||||
- Memory usage optimization [#160](https://github.com/shopspring/decimal/pull/160)
|
||||
- Updated travis CI golang versions [#156](https://github.com/shopspring/decimal/pull/156)
|
||||
- Update documentation [#173](https://github.com/shopspring/decimal/pull/173)
|
||||
- Improve code quality [#174](https://github.com/shopspring/decimal/pull/174)
|
||||
|
||||
#### BUGFIXES
|
||||
- Revert remove insignificant digits [#159](https://github.com/shopspring/decimal/pull/159)
|
||||
- Remove 15 interval for RoundCash [#166](https://github.com/shopspring/decimal/pull/166)
|
45
vendor/github.com/shopspring/decimal/LICENSE
generated
vendored
Normal file
45
vendor/github.com/shopspring/decimal/LICENSE
generated
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Spring, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
- Based on https://github.com/oguzbilgic/fpd, which has the following license:
|
||||
"""
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013 Oguz Bilgic
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
"""
|
139
vendor/github.com/shopspring/decimal/README.md
generated
vendored
Normal file
139
vendor/github.com/shopspring/decimal/README.md
generated
vendored
Normal file
@ -0,0 +1,139 @@
|
||||
# decimal
|
||||
|
||||
[](https://github.com/shopspring/decimal/actions/workflows/ci.yml)
|
||||
[](https://godoc.org/github.com/shopspring/decimal)
|
||||
[](https://goreportcard.com/report/github.com/shopspring/decimal)
|
||||
|
||||
Arbitrary-precision fixed-point decimal numbers in go.
|
||||
|
||||
_Note:_ Decimal library can "only" represent numbers with a maximum of 2^31 digits after the decimal point.
|
||||
|
||||
## Features
|
||||
|
||||
* The zero-value is 0, and is safe to use without initialization
|
||||
* Addition, subtraction, multiplication with no loss of precision
|
||||
* Division with specified precision
|
||||
* Database/sql serialization/deserialization
|
||||
* JSON and XML serialization/deserialization
|
||||
|
||||
## Install
|
||||
|
||||
Run `go get github.com/shopspring/decimal`
|
||||
|
||||
## Requirements
|
||||
|
||||
Decimal library requires Go version `>=1.10`
|
||||
|
||||
## Documentation
|
||||
|
||||
http://godoc.org/github.com/shopspring/decimal
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/shopspring/decimal"
|
||||
)
|
||||
|
||||
func main() {
|
||||
price, err := decimal.NewFromString("136.02")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
quantity := decimal.NewFromInt(3)
|
||||
|
||||
fee, _ := decimal.NewFromString(".035")
|
||||
taxRate, _ := decimal.NewFromString(".08875")
|
||||
|
||||
subtotal := price.Mul(quantity)
|
||||
|
||||
preTax := subtotal.Mul(fee.Add(decimal.NewFromFloat(1)))
|
||||
|
||||
total := preTax.Mul(taxRate.Add(decimal.NewFromFloat(1)))
|
||||
|
||||
fmt.Println("Subtotal:", subtotal) // Subtotal: 408.06
|
||||
fmt.Println("Pre-tax:", preTax) // Pre-tax: 422.3421
|
||||
fmt.Println("Taxes:", total.Sub(preTax)) // Taxes: 37.482861375
|
||||
fmt.Println("Total:", total) // Total: 459.824961375
|
||||
fmt.Println("Tax rate:", total.Sub(preTax).Div(preTax)) // Tax rate: 0.08875
|
||||
}
|
||||
```
|
||||
|
||||
## Alternative libraries
|
||||
|
||||
When working with decimal numbers, you might face problems this library is not perfectly suited for.
|
||||
Fortunately, thanks to the wonderful community we have a dozen other libraries that you can choose from.
|
||||
Explore other alternatives to find the one that best fits your needs :)
|
||||
|
||||
* [cockroachdb/apd](https://github.com/cockroachdb/apd) - arbitrary precision, mutable and rich API similar to `big.Int`, more performant than this library
|
||||
* [alpacahq/alpacadecimal](https://github.com/alpacahq/alpacadecimal) - high performance, low precision (12 digits), fully compatible API with this library
|
||||
* [govalues/decimal](https://github.com/govalues/decimal) - high performance, zero-allocation, low precision (19 digits)
|
||||
* [greatcloak/decimal](https://github.com/greatcloak/decimal) - fork focusing on billing and e-commerce web application related use cases, includes out-of-the-box BSON marshaling support
|
||||
|
||||
## FAQ
|
||||
|
||||
#### Why don't you just use float64?
|
||||
|
||||
Because float64 (or any binary floating point type, actually) can't represent
|
||||
numbers such as `0.1` exactly.
|
||||
|
||||
Consider this code: http://play.golang.org/p/TQBd4yJe6B You might expect that
|
||||
it prints out `10`, but it actually prints `9.999999999999831`. Over time,
|
||||
these small errors can really add up!
|
||||
|
||||
#### Why don't you just use big.Rat?
|
||||
|
||||
big.Rat is fine for representing rational numbers, but Decimal is better for
|
||||
representing money. Why? Here's a (contrived) example:
|
||||
|
||||
Let's say you use big.Rat, and you have two numbers, x and y, both
|
||||
representing 1/3, and you have `z = 1 - x - y = 1/3`. If you print each one
|
||||
out, the string output has to stop somewhere (let's say it stops at 3 decimal
|
||||
digits, for simplicity), so you'll get 0.333, 0.333, and 0.333. But where did
|
||||
the other 0.001 go?
|
||||
|
||||
Here's the above example as code: http://play.golang.org/p/lCZZs0w9KE
|
||||
|
||||
With Decimal, the strings being printed out represent the number exactly. So,
|
||||
if you have `x = y = 1/3` (with precision 3), they will actually be equal to
|
||||
0.333, and when you do `z = 1 - x - y`, `z` will be equal to .334. No money is
|
||||
unaccounted for!
|
||||
|
||||
You still have to be careful. If you want to split a number `N` 3 ways, you
|
||||
can't just send `N/3` to three different people. You have to pick one to send
|
||||
`N - (2/3*N)` to. That person will receive the fraction of a penny remainder.
|
||||
|
||||
But, it is much easier to be careful with Decimal than with big.Rat.
|
||||
|
||||
#### Why isn't the API similar to big.Int's?
|
||||
|
||||
big.Int's API is built to reduce the number of memory allocations for maximal
|
||||
performance. This makes sense for its use-case, but the trade-off is that the
|
||||
API is awkward and easy to misuse.
|
||||
|
||||
For example, to add two big.Ints, you do: `z := new(big.Int).Add(x, y)`. A
|
||||
developer unfamiliar with this API might try to do `z := a.Add(a, b)`. This
|
||||
modifies `a` and sets `z` as an alias for `a`, which they might not expect. It
|
||||
also modifies any other aliases to `a`.
|
||||
|
||||
Here's an example of the subtle bugs you can introduce with big.Int's API:
|
||||
https://play.golang.org/p/x2R_78pa8r
|
||||
|
||||
In contrast, it's difficult to make such mistakes with decimal. Decimals
|
||||
behave like other go numbers types: even though `a = b` will not deep copy
|
||||
`b` into `a`, it is impossible to modify a Decimal, since all Decimal methods
|
||||
return new Decimals and do not modify the originals. The downside is that
|
||||
this causes extra allocations, so Decimal is less performant. My assumption
|
||||
is that if you're using Decimals, you probably care more about correctness
|
||||
than performance.
|
||||
|
||||
## License
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
This is a heavily modified fork of [fpd.Decimal](https://github.com/oguzbilgic/fpd), which was also released under the MIT License.
|
63
vendor/github.com/shopspring/decimal/const.go
generated
vendored
Normal file
63
vendor/github.com/shopspring/decimal/const.go
generated
vendored
Normal file
@ -0,0 +1,63 @@
|
||||
package decimal
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
strLn10 = "2.302585092994045684017991454684364207601101488628772976033327900967572609677352480235997205089598298341967784042286248633409525465082806756666287369098781689482907208325554680843799894826233198528393505308965377732628846163366222287698219886746543667474404243274365155048934314939391479619404400222105101714174800368808401264708068556774321622835522011480466371565912137345074785694768346361679210180644507064800027750268491674655058685693567342067058113642922455440575892572420824131469568901675894025677631135691929203337658714166023010570308963457207544037084746994016826928280848118428931484852494864487192780967627127577539702766860595249671667418348570442250719796500471495105049221477656763693866297697952211071826454973477266242570942932258279850258550978526538320760672631716430950599508780752371033310119785754733154142180842754386359177811705430982748238504564801909561029929182431823752535770975053956518769751037497088869218020518933950723853920514463419726528728696511086257149219884997874887377134568620916705849807828059751193854445009978131146915934666241071846692310107598438319191292230792503747298650929009880391941702654416816335727555703151596113564846546190897042819763365836983716328982174407366009162177850541779276367731145041782137660111010731042397832521894898817597921798666394319523936855916447118246753245630912528778330963604262982153040874560927760726641354787576616262926568298704957954913954918049209069438580790032763017941503117866862092408537949861264933479354871737451675809537088281067452440105892444976479686075120275724181874989395971643105518848195288330746699317814634930000321200327765654130472621883970596794457943468343218395304414844803701305753674262153675579814770458031413637793236291560128185336498466942261465206459942072917119370602444929358037007718981097362533224548366988505528285966192805098447175198503666680874970496982273220244823343097169111136813588418696549323714996941979687803008850408979618598756579894836445212043698216415292987811742973332588607915912510967187510929248475023930572665446276200923068791518135803477701295593646298412366497023355174586195564772461857717369368404676577047874319780573853271810933883496338813069945569399346101090745616033312247949360455361849123333063704751724871276379140924398331810164737823379692265637682071706935846394531616949411701841938119405416449466111274712819705817783293841742231409930022911502362192186723337268385688273533371925103412930705632544426611429765388301822384091026198582888433587455960453004548370789052578473166283701953392231047527564998119228742789713715713228319641003422124210082180679525276689858180956119208391760721080919923461516952599099473782780648128058792731993893453415320185969711021407542282796298237068941764740642225757212455392526179373652434440560595336591539160312524480149313234572453879524389036839236450507881731359711238145323701508413491122324390927681724749607955799151363982881058285740538000653371655553014196332241918087621018204919492651483892"
|
||||
)
|
||||
|
||||
var (
|
||||
ln10 = newConstApproximation(strLn10)
|
||||
)
|
||||
|
||||
type constApproximation struct {
|
||||
exact Decimal
|
||||
approximations []Decimal
|
||||
}
|
||||
|
||||
func newConstApproximation(value string) constApproximation {
|
||||
parts := strings.Split(value, ".")
|
||||
coeff, fractional := parts[0], parts[1]
|
||||
|
||||
coeffLen := len(coeff)
|
||||
maxPrecision := len(fractional)
|
||||
|
||||
var approximations []Decimal
|
||||
for p := 1; p < maxPrecision; p *= 2 {
|
||||
r := RequireFromString(value[:coeffLen+p])
|
||||
approximations = append(approximations, r)
|
||||
}
|
||||
|
||||
return constApproximation{
|
||||
RequireFromString(value),
|
||||
approximations,
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the smallest approximation available that's at least as precise
|
||||
// as the passed precision (places after decimal point), i.e. Floor[ log2(precision) ] + 1
|
||||
func (c constApproximation) withPrecision(precision int32) Decimal {
|
||||
i := 0
|
||||
|
||||
if precision >= 1 {
|
||||
i++
|
||||
}
|
||||
|
||||
for precision >= 16 {
|
||||
precision /= 16
|
||||
i += 4
|
||||
}
|
||||
|
||||
for precision >= 2 {
|
||||
precision /= 2
|
||||
i++
|
||||
}
|
||||
|
||||
if i >= len(c.approximations) {
|
||||
return c.exact
|
||||
}
|
||||
|
||||
return c.approximations[i]
|
||||
}
|
415
vendor/github.com/shopspring/decimal/decimal-go.go
generated
vendored
Normal file
415
vendor/github.com/shopspring/decimal/decimal-go.go
generated
vendored
Normal file
@ -0,0 +1,415 @@
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Multiprecision decimal numbers.
|
||||
// For floating-point formatting only; not general purpose.
|
||||
// Only operations are assign and (binary) left/right shift.
|
||||
// Can do binary floating point in multiprecision decimal precisely
|
||||
// because 2 divides 10; cannot do decimal floating point
|
||||
// in multiprecision binary precisely.
|
||||
|
||||
package decimal
|
||||
|
||||
type decimal struct {
|
||||
d [800]byte // digits, big-endian representation
|
||||
nd int // number of digits used
|
||||
dp int // decimal point
|
||||
neg bool // negative flag
|
||||
trunc bool // discarded nonzero digits beyond d[:nd]
|
||||
}
|
||||
|
||||
func (a *decimal) String() string {
|
||||
n := 10 + a.nd
|
||||
if a.dp > 0 {
|
||||
n += a.dp
|
||||
}
|
||||
if a.dp < 0 {
|
||||
n += -a.dp
|
||||
}
|
||||
|
||||
buf := make([]byte, n)
|
||||
w := 0
|
||||
switch {
|
||||
case a.nd == 0:
|
||||
return "0"
|
||||
|
||||
case a.dp <= 0:
|
||||
// zeros fill space between decimal point and digits
|
||||
buf[w] = '0'
|
||||
w++
|
||||
buf[w] = '.'
|
||||
w++
|
||||
w += digitZero(buf[w : w+-a.dp])
|
||||
w += copy(buf[w:], a.d[0:a.nd])
|
||||
|
||||
case a.dp < a.nd:
|
||||
// decimal point in middle of digits
|
||||
w += copy(buf[w:], a.d[0:a.dp])
|
||||
buf[w] = '.'
|
||||
w++
|
||||
w += copy(buf[w:], a.d[a.dp:a.nd])
|
||||
|
||||
default:
|
||||
// zeros fill space between digits and decimal point
|
||||
w += copy(buf[w:], a.d[0:a.nd])
|
||||
w += digitZero(buf[w : w+a.dp-a.nd])
|
||||
}
|
||||
return string(buf[0:w])
|
||||
}
|
||||
|
||||
func digitZero(dst []byte) int {
|
||||
for i := range dst {
|
||||
dst[i] = '0'
|
||||
}
|
||||
return len(dst)
|
||||
}
|
||||
|
||||
// trim trailing zeros from number.
|
||||
// (They are meaningless; the decimal point is tracked
|
||||
// independent of the number of digits.)
|
||||
func trim(a *decimal) {
|
||||
for a.nd > 0 && a.d[a.nd-1] == '0' {
|
||||
a.nd--
|
||||
}
|
||||
if a.nd == 0 {
|
||||
a.dp = 0
|
||||
}
|
||||
}
|
||||
|
||||
// Assign v to a.
|
||||
func (a *decimal) Assign(v uint64) {
|
||||
var buf [24]byte
|
||||
|
||||
// Write reversed decimal in buf.
|
||||
n := 0
|
||||
for v > 0 {
|
||||
v1 := v / 10
|
||||
v -= 10 * v1
|
||||
buf[n] = byte(v + '0')
|
||||
n++
|
||||
v = v1
|
||||
}
|
||||
|
||||
// Reverse again to produce forward decimal in a.d.
|
||||
a.nd = 0
|
||||
for n--; n >= 0; n-- {
|
||||
a.d[a.nd] = buf[n]
|
||||
a.nd++
|
||||
}
|
||||
a.dp = a.nd
|
||||
trim(a)
|
||||
}
|
||||
|
||||
// Maximum shift that we can do in one pass without overflow.
|
||||
// A uint has 32 or 64 bits, and we have to be able to accommodate 9<<k.
|
||||
const uintSize = 32 << (^uint(0) >> 63)
|
||||
const maxShift = uintSize - 4
|
||||
|
||||
// Binary shift right (/ 2) by k bits. k <= maxShift to avoid overflow.
|
||||
func rightShift(a *decimal, k uint) {
|
||||
r := 0 // read pointer
|
||||
w := 0 // write pointer
|
||||
|
||||
// Pick up enough leading digits to cover first shift.
|
||||
var n uint
|
||||
for ; n>>k == 0; r++ {
|
||||
if r >= a.nd {
|
||||
if n == 0 {
|
||||
// a == 0; shouldn't get here, but handle anyway.
|
||||
a.nd = 0
|
||||
return
|
||||
}
|
||||
for n>>k == 0 {
|
||||
n = n * 10
|
||||
r++
|
||||
}
|
||||
break
|
||||
}
|
||||
c := uint(a.d[r])
|
||||
n = n*10 + c - '0'
|
||||
}
|
||||
a.dp -= r - 1
|
||||
|
||||
var mask uint = (1 << k) - 1
|
||||
|
||||
// Pick up a digit, put down a digit.
|
||||
for ; r < a.nd; r++ {
|
||||
c := uint(a.d[r])
|
||||
dig := n >> k
|
||||
n &= mask
|
||||
a.d[w] = byte(dig + '0')
|
||||
w++
|
||||
n = n*10 + c - '0'
|
||||
}
|
||||
|
||||
// Put down extra digits.
|
||||
for n > 0 {
|
||||
dig := n >> k
|
||||
n &= mask
|
||||
if w < len(a.d) {
|
||||
a.d[w] = byte(dig + '0')
|
||||
w++
|
||||
} else if dig > 0 {
|
||||
a.trunc = true
|
||||
}
|
||||
n = n * 10
|
||||
}
|
||||
|
||||
a.nd = w
|
||||
trim(a)
|
||||
}
|
||||
|
||||
// Cheat sheet for left shift: table indexed by shift count giving
|
||||
// number of new digits that will be introduced by that shift.
|
||||
//
|
||||
// For example, leftcheats[4] = {2, "625"}. That means that
|
||||
// if we are shifting by 4 (multiplying by 16), it will add 2 digits
|
||||
// when the string prefix is "625" through "999", and one fewer digit
|
||||
// if the string prefix is "000" through "624".
|
||||
//
|
||||
// Credit for this trick goes to Ken.
|
||||
|
||||
type leftCheat struct {
|
||||
delta int // number of new digits
|
||||
cutoff string // minus one digit if original < a.
|
||||
}
|
||||
|
||||
var leftcheats = []leftCheat{
|
||||
// Leading digits of 1/2^i = 5^i.
|
||||
// 5^23 is not an exact 64-bit floating point number,
|
||||
// so have to use bc for the math.
|
||||
// Go up to 60 to be large enough for 32bit and 64bit platforms.
|
||||
/*
|
||||
seq 60 | sed 's/^/5^/' | bc |
|
||||
awk 'BEGIN{ print "\t{ 0, \"\" }," }
|
||||
{
|
||||
log2 = log(2)/log(10)
|
||||
printf("\t{ %d, \"%s\" },\t// * %d\n",
|
||||
int(log2*NR+1), $0, 2**NR)
|
||||
}'
|
||||
*/
|
||||
{0, ""},
|
||||
{1, "5"}, // * 2
|
||||
{1, "25"}, // * 4
|
||||
{1, "125"}, // * 8
|
||||
{2, "625"}, // * 16
|
||||
{2, "3125"}, // * 32
|
||||
{2, "15625"}, // * 64
|
||||
{3, "78125"}, // * 128
|
||||
{3, "390625"}, // * 256
|
||||
{3, "1953125"}, // * 512
|
||||
{4, "9765625"}, // * 1024
|
||||
{4, "48828125"}, // * 2048
|
||||
{4, "244140625"}, // * 4096
|
||||
{4, "1220703125"}, // * 8192
|
||||
{5, "6103515625"}, // * 16384
|
||||
{5, "30517578125"}, // * 32768
|
||||
{5, "152587890625"}, // * 65536
|
||||
{6, "762939453125"}, // * 131072
|
||||
{6, "3814697265625"}, // * 262144
|
||||
{6, "19073486328125"}, // * 524288
|
||||
{7, "95367431640625"}, // * 1048576
|
||||
{7, "476837158203125"}, // * 2097152
|
||||
{7, "2384185791015625"}, // * 4194304
|
||||
{7, "11920928955078125"}, // * 8388608
|
||||
{8, "59604644775390625"}, // * 16777216
|
||||
{8, "298023223876953125"}, // * 33554432
|
||||
{8, "1490116119384765625"}, // * 67108864
|
||||
{9, "7450580596923828125"}, // * 134217728
|
||||
{9, "37252902984619140625"}, // * 268435456
|
||||
{9, "186264514923095703125"}, // * 536870912
|
||||
{10, "931322574615478515625"}, // * 1073741824
|
||||
{10, "4656612873077392578125"}, // * 2147483648
|
||||
{10, "23283064365386962890625"}, // * 4294967296
|
||||
{10, "116415321826934814453125"}, // * 8589934592
|
||||
{11, "582076609134674072265625"}, // * 17179869184
|
||||
{11, "2910383045673370361328125"}, // * 34359738368
|
||||
{11, "14551915228366851806640625"}, // * 68719476736
|
||||
{12, "72759576141834259033203125"}, // * 137438953472
|
||||
{12, "363797880709171295166015625"}, // * 274877906944
|
||||
{12, "1818989403545856475830078125"}, // * 549755813888
|
||||
{13, "9094947017729282379150390625"}, // * 1099511627776
|
||||
{13, "45474735088646411895751953125"}, // * 2199023255552
|
||||
{13, "227373675443232059478759765625"}, // * 4398046511104
|
||||
{13, "1136868377216160297393798828125"}, // * 8796093022208
|
||||
{14, "5684341886080801486968994140625"}, // * 17592186044416
|
||||
{14, "28421709430404007434844970703125"}, // * 35184372088832
|
||||
{14, "142108547152020037174224853515625"}, // * 70368744177664
|
||||
{15, "710542735760100185871124267578125"}, // * 140737488355328
|
||||
{15, "3552713678800500929355621337890625"}, // * 281474976710656
|
||||
{15, "17763568394002504646778106689453125"}, // * 562949953421312
|
||||
{16, "88817841970012523233890533447265625"}, // * 1125899906842624
|
||||
{16, "444089209850062616169452667236328125"}, // * 2251799813685248
|
||||
{16, "2220446049250313080847263336181640625"}, // * 4503599627370496
|
||||
{16, "11102230246251565404236316680908203125"}, // * 9007199254740992
|
||||
{17, "55511151231257827021181583404541015625"}, // * 18014398509481984
|
||||
{17, "277555756156289135105907917022705078125"}, // * 36028797018963968
|
||||
{17, "1387778780781445675529539585113525390625"}, // * 72057594037927936
|
||||
{18, "6938893903907228377647697925567626953125"}, // * 144115188075855872
|
||||
{18, "34694469519536141888238489627838134765625"}, // * 288230376151711744
|
||||
{18, "173472347597680709441192448139190673828125"}, // * 576460752303423488
|
||||
{19, "867361737988403547205962240695953369140625"}, // * 1152921504606846976
|
||||
}
|
||||
|
||||
// Is the leading prefix of b lexicographically less than s?
|
||||
func prefixIsLessThan(b []byte, s string) bool {
|
||||
for i := 0; i < len(s); i++ {
|
||||
if i >= len(b) {
|
||||
return true
|
||||
}
|
||||
if b[i] != s[i] {
|
||||
return b[i] < s[i]
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Binary shift left (* 2) by k bits. k <= maxShift to avoid overflow.
|
||||
func leftShift(a *decimal, k uint) {
|
||||
delta := leftcheats[k].delta
|
||||
if prefixIsLessThan(a.d[0:a.nd], leftcheats[k].cutoff) {
|
||||
delta--
|
||||
}
|
||||
|
||||
r := a.nd // read index
|
||||
w := a.nd + delta // write index
|
||||
|
||||
// Pick up a digit, put down a digit.
|
||||
var n uint
|
||||
for r--; r >= 0; r-- {
|
||||
n += (uint(a.d[r]) - '0') << k
|
||||
quo := n / 10
|
||||
rem := n - 10*quo
|
||||
w--
|
||||
if w < len(a.d) {
|
||||
a.d[w] = byte(rem + '0')
|
||||
} else if rem != 0 {
|
||||
a.trunc = true
|
||||
}
|
||||
n = quo
|
||||
}
|
||||
|
||||
// Put down extra digits.
|
||||
for n > 0 {
|
||||
quo := n / 10
|
||||
rem := n - 10*quo
|
||||
w--
|
||||
if w < len(a.d) {
|
||||
a.d[w] = byte(rem + '0')
|
||||
} else if rem != 0 {
|
||||
a.trunc = true
|
||||
}
|
||||
n = quo
|
||||
}
|
||||
|
||||
a.nd += delta
|
||||
if a.nd >= len(a.d) {
|
||||
a.nd = len(a.d)
|
||||
}
|
||||
a.dp += delta
|
||||
trim(a)
|
||||
}
|
||||
|
||||
// Binary shift left (k > 0) or right (k < 0).
|
||||
func (a *decimal) Shift(k int) {
|
||||
switch {
|
||||
case a.nd == 0:
|
||||
// nothing to do: a == 0
|
||||
case k > 0:
|
||||
for k > maxShift {
|
||||
leftShift(a, maxShift)
|
||||
k -= maxShift
|
||||
}
|
||||
leftShift(a, uint(k))
|
||||
case k < 0:
|
||||
for k < -maxShift {
|
||||
rightShift(a, maxShift)
|
||||
k += maxShift
|
||||
}
|
||||
rightShift(a, uint(-k))
|
||||
}
|
||||
}
|
||||
|
||||
// If we chop a at nd digits, should we round up?
|
||||
func shouldRoundUp(a *decimal, nd int) bool {
|
||||
if nd < 0 || nd >= a.nd {
|
||||
return false
|
||||
}
|
||||
if a.d[nd] == '5' && nd+1 == a.nd { // exactly halfway - round to even
|
||||
// if we truncated, a little higher than what's recorded - always round up
|
||||
if a.trunc {
|
||||
return true
|
||||
}
|
||||
return nd > 0 && (a.d[nd-1]-'0')%2 != 0
|
||||
}
|
||||
// not halfway - digit tells all
|
||||
return a.d[nd] >= '5'
|
||||
}
|
||||
|
||||
// Round a to nd digits (or fewer).
|
||||
// If nd is zero, it means we're rounding
|
||||
// just to the left of the digits, as in
|
||||
// 0.09 -> 0.1.
|
||||
func (a *decimal) Round(nd int) {
|
||||
if nd < 0 || nd >= a.nd {
|
||||
return
|
||||
}
|
||||
if shouldRoundUp(a, nd) {
|
||||
a.RoundUp(nd)
|
||||
} else {
|
||||
a.RoundDown(nd)
|
||||
}
|
||||
}
|
||||
|
||||
// Round a down to nd digits (or fewer).
|
||||
func (a *decimal) RoundDown(nd int) {
|
||||
if nd < 0 || nd >= a.nd {
|
||||
return
|
||||
}
|
||||
a.nd = nd
|
||||
trim(a)
|
||||
}
|
||||
|
||||
// Round a up to nd digits (or fewer).
|
||||
func (a *decimal) RoundUp(nd int) {
|
||||
if nd < 0 || nd >= a.nd {
|
||||
return
|
||||
}
|
||||
|
||||
// round up
|
||||
for i := nd - 1; i >= 0; i-- {
|
||||
c := a.d[i]
|
||||
if c < '9' { // can stop after this digit
|
||||
a.d[i]++
|
||||
a.nd = i + 1
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Number is all 9s.
|
||||
// Change to single 1 with adjusted decimal point.
|
||||
a.d[0] = '1'
|
||||
a.nd = 1
|
||||
a.dp++
|
||||
}
|
||||
|
||||
// Extract integer part, rounded appropriately.
|
||||
// No guarantees about overflow.
|
||||
func (a *decimal) RoundedInteger() uint64 {
|
||||
if a.dp > 20 {
|
||||
return 0xFFFFFFFFFFFFFFFF
|
||||
}
|
||||
var i int
|
||||
n := uint64(0)
|
||||
for i = 0; i < a.dp && i < a.nd; i++ {
|
||||
n = n*10 + uint64(a.d[i]-'0')
|
||||
}
|
||||
for ; i < a.dp; i++ {
|
||||
n *= 10
|
||||
}
|
||||
if shouldRoundUp(a, a.dp) {
|
||||
n++
|
||||
}
|
||||
return n
|
||||
}
|
2339
vendor/github.com/shopspring/decimal/decimal.go
generated
vendored
Normal file
2339
vendor/github.com/shopspring/decimal/decimal.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
160
vendor/github.com/shopspring/decimal/rounding.go
generated
vendored
Normal file
160
vendor/github.com/shopspring/decimal/rounding.go
generated
vendored
Normal file
@ -0,0 +1,160 @@
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Multiprecision decimal numbers.
|
||||
// For floating-point formatting only; not general purpose.
|
||||
// Only operations are assign and (binary) left/right shift.
|
||||
// Can do binary floating point in multiprecision decimal precisely
|
||||
// because 2 divides 10; cannot do decimal floating point
|
||||
// in multiprecision binary precisely.
|
||||
|
||||
package decimal
|
||||
|
||||
type floatInfo struct {
|
||||
mantbits uint
|
||||
expbits uint
|
||||
bias int
|
||||
}
|
||||
|
||||
var float32info = floatInfo{23, 8, -127}
|
||||
var float64info = floatInfo{52, 11, -1023}
|
||||
|
||||
// roundShortest rounds d (= mant * 2^exp) to the shortest number of digits
|
||||
// that will let the original floating point value be precisely reconstructed.
|
||||
func roundShortest(d *decimal, mant uint64, exp int, flt *floatInfo) {
|
||||
// If mantissa is zero, the number is zero; stop now.
|
||||
if mant == 0 {
|
||||
d.nd = 0
|
||||
return
|
||||
}
|
||||
|
||||
// Compute upper and lower such that any decimal number
|
||||
// between upper and lower (possibly inclusive)
|
||||
// will round to the original floating point number.
|
||||
|
||||
// We may see at once that the number is already shortest.
|
||||
//
|
||||
// Suppose d is not denormal, so that 2^exp <= d < 10^dp.
|
||||
// The closest shorter number is at least 10^(dp-nd) away.
|
||||
// The lower/upper bounds computed below are at distance
|
||||
// at most 2^(exp-mantbits).
|
||||
//
|
||||
// So the number is already shortest if 10^(dp-nd) > 2^(exp-mantbits),
|
||||
// or equivalently log2(10)*(dp-nd) > exp-mantbits.
|
||||
// It is true if 332/100*(dp-nd) >= exp-mantbits (log2(10) > 3.32).
|
||||
minexp := flt.bias + 1 // minimum possible exponent
|
||||
if exp > minexp && 332*(d.dp-d.nd) >= 100*(exp-int(flt.mantbits)) {
|
||||
// The number is already shortest.
|
||||
return
|
||||
}
|
||||
|
||||
// d = mant << (exp - mantbits)
|
||||
// Next highest floating point number is mant+1 << exp-mantbits.
|
||||
// Our upper bound is halfway between, mant*2+1 << exp-mantbits-1.
|
||||
upper := new(decimal)
|
||||
upper.Assign(mant*2 + 1)
|
||||
upper.Shift(exp - int(flt.mantbits) - 1)
|
||||
|
||||
// d = mant << (exp - mantbits)
|
||||
// Next lowest floating point number is mant-1 << exp-mantbits,
|
||||
// unless mant-1 drops the significant bit and exp is not the minimum exp,
|
||||
// in which case the next lowest is mant*2-1 << exp-mantbits-1.
|
||||
// Either way, call it mantlo << explo-mantbits.
|
||||
// Our lower bound is halfway between, mantlo*2+1 << explo-mantbits-1.
|
||||
var mantlo uint64
|
||||
var explo int
|
||||
if mant > 1<<flt.mantbits || exp == minexp {
|
||||
mantlo = mant - 1
|
||||
explo = exp
|
||||
} else {
|
||||
mantlo = mant*2 - 1
|
||||
explo = exp - 1
|
||||
}
|
||||
lower := new(decimal)
|
||||
lower.Assign(mantlo*2 + 1)
|
||||
lower.Shift(explo - int(flt.mantbits) - 1)
|
||||
|
||||
// The upper and lower bounds are possible outputs only if
|
||||
// the original mantissa is even, so that IEEE round-to-even
|
||||
// would round to the original mantissa and not the neighbors.
|
||||
inclusive := mant%2 == 0
|
||||
|
||||
// As we walk the digits we want to know whether rounding up would fall
|
||||
// within the upper bound. This is tracked by upperdelta:
|
||||
//
|
||||
// If upperdelta == 0, the digits of d and upper are the same so far.
|
||||
//
|
||||
// If upperdelta == 1, we saw a difference of 1 between d and upper on a
|
||||
// previous digit and subsequently only 9s for d and 0s for upper.
|
||||
// (Thus rounding up may fall outside the bound, if it is exclusive.)
|
||||
//
|
||||
// If upperdelta == 2, then the difference is greater than 1
|
||||
// and we know that rounding up falls within the bound.
|
||||
var upperdelta uint8
|
||||
|
||||
// Now we can figure out the minimum number of digits required.
|
||||
// Walk along until d has distinguished itself from upper and lower.
|
||||
for ui := 0; ; ui++ {
|
||||
// lower, d, and upper may have the decimal points at different
|
||||
// places. In this case upper is the longest, so we iterate from
|
||||
// ui==0 and start li and mi at (possibly) -1.
|
||||
mi := ui - upper.dp + d.dp
|
||||
if mi >= d.nd {
|
||||
break
|
||||
}
|
||||
li := ui - upper.dp + lower.dp
|
||||
l := byte('0') // lower digit
|
||||
if li >= 0 && li < lower.nd {
|
||||
l = lower.d[li]
|
||||
}
|
||||
m := byte('0') // middle digit
|
||||
if mi >= 0 {
|
||||
m = d.d[mi]
|
||||
}
|
||||
u := byte('0') // upper digit
|
||||
if ui < upper.nd {
|
||||
u = upper.d[ui]
|
||||
}
|
||||
|
||||
// Okay to round down (truncate) if lower has a different digit
|
||||
// or if lower is inclusive and is exactly the result of rounding
|
||||
// down (i.e., and we have reached the final digit of lower).
|
||||
okdown := l != m || inclusive && li+1 == lower.nd
|
||||
|
||||
switch {
|
||||
case upperdelta == 0 && m+1 < u:
|
||||
// Example:
|
||||
// m = 12345xxx
|
||||
// u = 12347xxx
|
||||
upperdelta = 2
|
||||
case upperdelta == 0 && m != u:
|
||||
// Example:
|
||||
// m = 12345xxx
|
||||
// u = 12346xxx
|
||||
upperdelta = 1
|
||||
case upperdelta == 1 && (m != '9' || u != '0'):
|
||||
// Example:
|
||||
// m = 1234598x
|
||||
// u = 1234600x
|
||||
upperdelta = 2
|
||||
}
|
||||
// Okay to round up if upper has a different digit and either upper
|
||||
// is inclusive or upper is bigger than the result of rounding up.
|
||||
okup := upperdelta > 0 && (inclusive || upperdelta > 1 || ui+1 < upper.nd)
|
||||
|
||||
// If it's okay to do either, then round to the nearest one.
|
||||
// If it's okay to do only one, do it.
|
||||
switch {
|
||||
case okdown && okup:
|
||||
d.Round(mi + 1)
|
||||
return
|
||||
case okdown:
|
||||
d.RoundDown(mi + 1)
|
||||
return
|
||||
case okup:
|
||||
d.RoundUp(mi + 1)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
8
vendor/modules.txt
vendored
8
vendor/modules.txt
vendored
@ -2,6 +2,11 @@
|
||||
## explicit; go 1.20
|
||||
filippo.io/edwards25519
|
||||
filippo.io/edwards25519/field
|
||||
# github.com/Andrew-M-C/go.jsonvalue v1.4.1
|
||||
## explicit; go 1.13
|
||||
github.com/Andrew-M-C/go.jsonvalue
|
||||
github.com/Andrew-M-C/go.jsonvalue/internal/buffer
|
||||
github.com/Andrew-M-C/go.jsonvalue/internal/unsafe
|
||||
# github.com/Esword618/unioffice v1.4.1
|
||||
## explicit; go 1.12
|
||||
github.com/Esword618/unioffice
|
||||
@ -76,6 +81,9 @@ github.com/lxn/win
|
||||
## explicit; go 1.22
|
||||
github.com/playwright-community/playwright-go
|
||||
github.com/playwright-community/playwright-go/internal/safe
|
||||
# github.com/shopspring/decimal v1.4.0
|
||||
## explicit; go 1.10
|
||||
github.com/shopspring/decimal
|
||||
# github.com/stretchr/testify v1.9.0
|
||||
## explicit; go 1.17
|
||||
# github.com/super-l/machine-code v0.0.0-20241121142923-4cb40646deba
|
||||
|
Loading…
Reference in New Issue
Block a user