json更新

This commit is contained in:
李超 2025-02-27 10:48:32 +08:00
parent f5e2b3b76f
commit 3a82defb40
41 changed files with 10209 additions and 19 deletions

View File

@ -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"`
}

View File

@ -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
View File

@ -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
View File

@ -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
View 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

View 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
View 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
View File

@ -0,0 +1,87 @@
# Jsonvalue - A Fast and Convenient Alternation of Go map[string]interface{}
[![Workflow](https://github.com/Andrew-M-C/go.jsonvalue/actions/workflows/go_test_general.yml/badge.svg)](https://github.com/Andrew-M-C/go.jsonvalue/actions/workflows/go_test_general.yml)
[![codecov](https://codecov.io/gh/Andrew-M-C/go.jsonvalue/branch/dev/github_workflow/graph/badge.svg?token=REDI4YDLPR&date=221104)](https://codecov.io/gh/Andrew-M-C/go.jsonvalue)
[![Go report](https://goreportcard.com/badge/github.com/Andrew-M-C/go.jsonvalue?date=221104)](https://goreportcard.com/report/github.com/Andrew-M-C/go.jsonvalue)
[![CodeBeat](https://codebeat.co/badges/ecf87760-2987-48a7-a6dd-4d9fcad57256)](https://codebeat.co/projects/github-com-andrew-m-c-go-jsonvalue-master)
[![GoDoc](https://godoc.org/github.com/Andrew-M-C/go.jsonvalue?status.svg&date=221104)](https://pkg.go.dev/github.com/Andrew-M-C/go.jsonvalue@v1.4.0)
[![Latest](https://img.shields.io/badge/latest-v1.4.0-blue.svg?date=221104)](https://github.com/Andrew-M-C/go.jsonvalue/tree/v1.4.0)
[![License](https://img.shields.io/badge/license-MIT-blue.svg?date=221104)](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).

View File

@ -0,0 +1,3 @@
package jsonvalue
type any = interface{}

View 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
View 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
View 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
View 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
View 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
}
}

View 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
}

View 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]
}

View 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...)
}

View 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),
}
}

View 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
}

View File

@ -0,0 +1 @@
package buffer

View 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
View 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
View 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(']')
}

View 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
View 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(']')
}

View 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
View 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
View 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
View 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
View 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
View 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
View 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, &sectEnd)
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
View 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
View 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
View 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
View File

@ -0,0 +1,139 @@
# decimal
[![ci](https://github.com/shopspring/decimal/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/shopspring/decimal/actions/workflows/ci.yml)
[![GoDoc](https://godoc.org/github.com/shopspring/decimal?status.svg)](https://godoc.org/github.com/shopspring/decimal)
[![Go Report Card](https://goreportcard.com/badge/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
View 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
View 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

File diff suppressed because it is too large Load Diff

160
vendor/github.com/shopspring/decimal/rounding.go generated vendored Normal file
View 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
View File

@ -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