diff --git a/.example/database/gdb/mysql/config.toml b/.example/database/gdb/mysql/config.toml index beea9dcb5..0ea384859 100644 --- a/.example/database/gdb/mysql/config.toml +++ b/.example/database/gdb/mysql/config.toml @@ -4,7 +4,7 @@ [database.logger] Level = "all" Stdout = true - CtxKeys = ["Trace-Id"] + CtxKeys = ["RequestId"] [database.default] link = "mysql:root:12345678@tcp(127.0.0.1:3306)/test" debug = true diff --git a/.example/database/gdb/mysql/config/gdb.go b/.example/database/gdb/mysql/config/gdb.go index 6fb30486b..75e92e9d1 100644 --- a/.example/database/gdb/mysql/config/gdb.go +++ b/.example/database/gdb/mysql/config/gdb.go @@ -2,6 +2,7 @@ package main import ( "github.com/gogf/gf/database/gdb" + "github.com/gogf/gf/os/gctx" "sync" "time" ) @@ -24,13 +25,16 @@ func init() { } func main() { - wg := sync.WaitGroup{} + var ( + wg = sync.WaitGroup{} + ctx = gctx.New() + ) for i := 0; i < 100000; i++ { wg.Add(1) go func() { defer wg.Done() time.Sleep(10 * time.Second) - db.Table("user").Where("id=1").All() + db.Ctx(ctx).Model("user").Where("id=1").All() }() } wg.Wait() diff --git a/.example/database/gdb/mysql/gdb_all.go b/.example/database/gdb/mysql/gdb_all.go index 74830ee48..355424f03 100644 --- a/.example/database/gdb/mysql/gdb_all.go +++ b/.example/database/gdb/mysql/gdb_all.go @@ -3,26 +3,22 @@ package main import ( "fmt" "github.com/gogf/gf/frame/g" + "github.com/gogf/gf/os/gctx" ) func main() { - db := g.DB() + var ( + db = g.DB() + ctx = gctx.New() + ) // 开启调试模式,以便于记录所有执行的SQL db.SetDebug(true) - r, e := db.GetAll("SELECT * from `user` where id in(?)", g.Slice{}) + r, e := db.Ctx(ctx).GetAll("SELECT * from `user` where id in(?)", g.Slice{}) if e != nil { fmt.Println(e) } if r != nil { fmt.Println(r) } - return - //r, e := db.Table("user").Where("id in(?)", g.Slice{}).All() - //if e != nil { - // fmt.Println(e) - //} - //if r != nil { - // fmt.Println(r.List()) - //} } diff --git a/.example/database/gdb/mysql/gdb_args_slice.go b/.example/database/gdb/mysql/gdb_args_slice.go index ceebe23d1..68c346dc9 100644 --- a/.example/database/gdb/mysql/gdb_args_slice.go +++ b/.example/database/gdb/mysql/gdb_args_slice.go @@ -2,12 +2,18 @@ package main import ( "github.com/gogf/gf/frame/g" + "github.com/gogf/gf/os/gctx" ) func main() { - db := g.DB() + var ( + db = g.DB() + ctx = gctx.New() + ) - db.Table("user").Where("nickname like ? and passport like ?", g.Slice{"T3", "t3"}).OrderBy("id asc").All() + db.Ctx(ctx).Model("user"). + Where("nickname like ? and passport like ?", g.Slice{"T3", "t3"}). + OrderAsc("id").All() conditions := g.Map{ "nickname like ?": "%T%", @@ -16,8 +22,8 @@ func main() { "create_time > ?": 0, "id in(?)": g.Slice{1, 2, 3}, } - db.Table("user").Where(conditions).OrderBy("id asc").All() + db.Ctx(ctx).Model("user").Where(conditions).OrderAsc("id").All() var params []interface{} - db.Table("user").Where("1=1", params).OrderBy("id asc").All() + db.Ctx(ctx).Model("user").Where("1=1", params).OrderAsc("id").All() } diff --git a/.example/database/gdb/mysql/gdb_batch_insert.go b/.example/database/gdb/mysql/gdb_batch_insert.go index 171bb9fb4..62c8a2e38 100644 --- a/.example/database/gdb/mysql/gdb_batch_insert.go +++ b/.example/database/gdb/mysql/gdb_batch_insert.go @@ -3,10 +3,14 @@ package main import ( "fmt" "github.com/gogf/gf/frame/g" + "github.com/gogf/gf/os/gctx" ) func main() { - db := g.DB() + var ( + db = g.DB() + ctx = gctx.New() + ) db.SetDebug(true) list := make(g.List, 0) for i := 0; i < 100; i++ { @@ -14,7 +18,7 @@ func main() { "name": fmt.Sprintf(`name_%d`, i), }) } - r, e := db.Table("user").Data(list).Batch(2).Insert() + r, e := db.Ctx(ctx).Model("user").Data(list).Batch(2).Insert() if e != nil { panic(e) } diff --git a/.example/database/gdb/mysql/gdb_binary.go b/.example/database/gdb/mysql/gdb_binary.go index f3d234736..eeba8987e 100644 --- a/.example/database/gdb/mysql/gdb_binary.go +++ b/.example/database/gdb/mysql/gdb_binary.go @@ -2,6 +2,7 @@ package main import ( "fmt" + "github.com/gogf/gf/os/gctx" "github.com/gogf/gf/crypto/gaes" "github.com/gogf/gf/database/gdb" @@ -19,6 +20,9 @@ func main() { Role: "master", Charset: "utf8", }) + var ( + ctx = gctx.New() + ) db, err := gdb.New() if err != nil { panic(err) @@ -33,7 +37,7 @@ func main() { } // 写入 - r, err := db.Table("user").Data(g.Map{ + r, err := db.Ctx(ctx).Model("user").Data(g.Map{ "uid": 1, "name": encryptedName, }).Save() @@ -43,9 +47,9 @@ func main() { fmt.Println(r.RowsAffected()) // 查询 - one, err := db.Table("user").Where("name=?", encryptedName).One() + one, err := db.Ctx(ctx).Model("user").Where("name=?", encryptedName).One() if err != nil { fmt.Println(err) } - fmt.Println(one.ToMap()) + fmt.Println(one.Map()) } diff --git a/.example/database/gdb/mysql/gdb_bit.go b/.example/database/gdb/mysql/gdb_bit.go index b7da01292..ce2c729e0 100644 --- a/.example/database/gdb/mysql/gdb_bit.go +++ b/.example/database/gdb/mysql/gdb_bit.go @@ -2,19 +2,23 @@ package main import ( "fmt" + "github.com/gogf/gf/os/gctx" "github.com/gogf/gf/frame/g" ) func main() { - db := g.DB() + var ( + db = g.DB() + ctx = gctx.New() + ) db.SetDebug(true) - r, e := db.Table("test").All() + r, e := db.Ctx(ctx).Model("test").All() if e != nil { panic(e) } if r != nil { - fmt.Println(r.ToList()) + fmt.Println(r.List()) } } diff --git a/.example/database/gdb/mysql/gdb_cache.go b/.example/database/gdb/mysql/gdb_cache.go index cefc858da..90f812ff2 100644 --- a/.example/database/gdb/mysql/gdb_cache.go +++ b/.example/database/gdb/mysql/gdb_cache.go @@ -2,6 +2,7 @@ package main import ( "github.com/gogf/gf/database/gdb" + "github.com/gogf/gf/os/gctx" "github.com/gogf/gf/util/gutil" "time" ) @@ -17,6 +18,9 @@ func main() { Role: "master", Charset: "utf8", }) + var ( + ctx = gctx.New() + ) db, err := gdb.New() if err != nil { panic(err) @@ -27,7 +31,7 @@ func main() { // 执行2次查询并将查询结果缓存3秒,并可执行缓存名称(可选) for i := 0; i < 3; i++ { - r, _ := db.Table("user").Cache(3000*time.Second).Where("id=?", 1).One() + r, _ := db.Ctx(ctx).Model("user").Cache(3000*time.Second).Where("id=?", 1).One() gutil.Dump(r.Map()) } diff --git a/.example/database/gdb/mysql/gdb_complecated.go b/.example/database/gdb/mysql/gdb_complecated.go index 0f8a9906f..eeaddebe3 100644 --- a/.example/database/gdb/mysql/gdb_complecated.go +++ b/.example/database/gdb/mysql/gdb_complecated.go @@ -6,7 +6,7 @@ import ( func main() { // error! - r, err := g.DB().Table("user").Where(g.Map{ + r, err := g.DB().Model("user").Where(g.Map{ "or": g.Map{ "nickname": "jim", "create_time > ": "2019-10-01", diff --git a/.example/database/gdb/mysql/gdb_config.go b/.example/database/gdb/mysql/gdb_config.go index cb88e2d89..4f6a809a3 100644 --- a/.example/database/gdb/mysql/gdb_config.go +++ b/.example/database/gdb/mysql/gdb_config.go @@ -7,7 +7,7 @@ import ( ) func main() { - if r, err := g.DB().Table("user").Where("uid=?", 1).One(); err == nil { + if r, err := g.DB().Model("user").Where("uid=?", 1).One(); err == nil { fmt.Println(r["uid"].Int()) fmt.Println(r["name"].String()) } else { diff --git a/.example/database/gdb/mysql/gdb_config2.go b/.example/database/gdb/mysql/gdb_config2.go index dfe80bc19..ca6fb4ebd 100644 --- a/.example/database/gdb/mysql/gdb_config2.go +++ b/.example/database/gdb/mysql/gdb_config2.go @@ -8,7 +8,7 @@ import ( func main() { g.Config().SetFileName("config2.toml") - if r, err := g.DB().Table("user").Where("uid=?", 1).One(); err == nil { + if r, err := g.DB().Model("user").Where("uid=?", 1).One(); err == nil { fmt.Println(r["uid"].Int()) fmt.Println(r["name"].String()) } else { diff --git a/.example/database/gdb/mysql/gdb_config3.go b/.example/database/gdb/mysql/gdb_config3.go index 11a531d55..576e622fd 100644 --- a/.example/database/gdb/mysql/gdb_config3.go +++ b/.example/database/gdb/mysql/gdb_config3.go @@ -8,14 +8,14 @@ import ( func main() { g.Config().SetFileName("config3.toml") - if r, err := g.DB().Table("user").Where("uid=?", 1).One(); err == nil { + if r, err := g.DB().Model("user").Where("uid=?", 1).One(); err == nil { fmt.Println(r["uid"].Int()) fmt.Println(r["name"].String()) } else { fmt.Println(err) } - if r, err := g.DB("user").Table("user").Where("uid=?", 1).One(); err == nil { + if r, err := g.DB("user").Model("user").Where("uid=?", 1).One(); err == nil { fmt.Println(r["uid"].Int()) fmt.Println(r["name"].String()) } else { diff --git a/.example/database/gdb/mysql/gdb_ctx.go b/.example/database/gdb/mysql/gdb_ctx.go index c296b59ba..0572f08c2 100644 --- a/.example/database/gdb/mysql/gdb_ctx.go +++ b/.example/database/gdb/mysql/gdb_ctx.go @@ -6,7 +6,7 @@ import ( ) func main() { - ctx := context.WithValue(context.Background(), "Trace-Id", "123456789") + ctx := context.WithValue(context.Background(), "RequestId", "123456789") _, err := g.DB().Ctx(ctx).Query("SELECT 1") if err != nil { panic(err) diff --git a/.example/database/gdb/mysql/gdb_ctx_model.go b/.example/database/gdb/mysql/gdb_ctx_model.go index ba7b83c02..fec1663f0 100644 --- a/.example/database/gdb/mysql/gdb_ctx_model.go +++ b/.example/database/gdb/mysql/gdb_ctx_model.go @@ -6,7 +6,7 @@ import ( ) func main() { - ctx := context.WithValue(context.Background(), "Trace-Id", "123456789") + ctx := context.WithValue(context.Background(), "RequestId", "123456789") _, err := g.DB().Model("user").Ctx(ctx).All() if err != nil { panic(err) diff --git a/.example/database/gdb/mysql/gdb_datetime.go b/.example/database/gdb/mysql/gdb_datetime.go index 440e70f1f..1a4677bb9 100644 --- a/.example/database/gdb/mysql/gdb_datetime.go +++ b/.example/database/gdb/mysql/gdb_datetime.go @@ -2,23 +2,20 @@ package main import ( "fmt" + "github.com/gogf/gf/os/gctx" "github.com/gogf/gf/frame/g" "github.com/gogf/gf/os/gtime" ) func main() { - db := g.Database() + var ( + db = g.DB() + ctx = gctx.New() + ) db.SetDebug(true) - //r, err := db.Table("user").Data("create_time", gtime.Now().String()).Insert() - //if err == nil { - // fmt.Println(r.LastInsertId()) - //} else { - // panic(err) - //} - - r, err := db.Table("user").Data(g.Map{ + r, err := db.Ctx(ctx).Model("user").Data(g.Map{ "name": "john", "create_time": gtime.Now().String(), }).Insert() diff --git a/.example/database/gdb/mysql/gdb_debug1.go b/.example/database/gdb/mysql/gdb_debug1.go index 9a3bc10e3..ecbceffe3 100644 --- a/.example/database/gdb/mysql/gdb_debug1.go +++ b/.example/database/gdb/mysql/gdb_debug1.go @@ -3,6 +3,7 @@ package main import ( "github.com/gogf/gf/database/gdb" "github.com/gogf/gf/frame/g" + "github.com/gogf/gf/os/gctx" "github.com/gogf/gf/os/glog" ) @@ -17,6 +18,9 @@ func main() { Role: "master", Charset: "utf8", }) + var ( + ctx = gctx.New() + ) db, err := gdb.New() if err != nil { panic(err) @@ -27,11 +31,11 @@ func main() { // 执行3条SQL查询 for i := 1; i <= 3; i++ { - db.Table("user").Where("uid=?", i).One() + db.Ctx(ctx).Model("user").Where("uid=?", i).One() } // 构造一条错误查询 - db.Table("user").Where("no_such_field=?", "just_test").One() + db.Model("user").Where("no_such_field=?", "just_test").One() - db.Table("user").Data(g.Map{"name": "smith"}).Where("uid=?", 1).Save() + db.Ctx(ctx).Model("user").Data(g.Map{"name": "smith"}).Where("uid=?", 1).Save() } diff --git a/.example/database/gdb/mysql/gdb_debug2.go b/.example/database/gdb/mysql/gdb_debug2.go index 0ed29c2a7..2480dc420 100644 --- a/.example/database/gdb/mysql/gdb_debug2.go +++ b/.example/database/gdb/mysql/gdb_debug2.go @@ -2,17 +2,21 @@ package main import ( "github.com/gogf/gf/frame/g" + "github.com/gogf/gf/os/gctx" ) func main() { - db := g.DB() + var ( + db = g.DB() + ctx = gctx.New() + ) // 执行3条SQL查询 for i := 1; i <= 3; i++ { - db.Table("user").Where("id=?", i).One() + db.Ctx(ctx).Model("user").Where("id=?", i).One() } // 构造一条错误查询 - db.Table("user").Where("no_such_field=?", "just_test").One() + db.Ctx(ctx).Model("user").Where("no_such_field=?", "just_test").One() - db.Table("user").Data(g.Map{"name": "smith"}).Where("uid=?", 1).Save() + db.Ctx(ctx).Model("user").Data(g.Map{"name": "smith"}).Where("uid=?", 1).Save() } diff --git a/.example/database/gdb/mysql/gdb_insert.go b/.example/database/gdb/mysql/gdb_insert.go index a6afa8491..61a0bd35b 100644 --- a/.example/database/gdb/mysql/gdb_insert.go +++ b/.example/database/gdb/mysql/gdb_insert.go @@ -18,7 +18,7 @@ func main() { db.SetDebug(true) - r, e := db.Table("user").Data(g.Map{ + r, e := db.Model("user").Data(g.Map{ "create_at": "now()", }).Unscoped().Insert() if e != nil { diff --git a/.example/database/gdb/mysql/gdb_issue_278.go b/.example/database/gdb/mysql/gdb_issue_278.go index 2f18da921..160b9f317 100644 --- a/.example/database/gdb/mysql/gdb_issue_278.go +++ b/.example/database/gdb/mysql/gdb_issue_278.go @@ -8,7 +8,7 @@ import ( var ( tableName = "orders" - dao = g.DB().Table(tableName).Safe() + dao = g.DB().Model(tableName).Safe() ) type OrderServiceEntity struct { diff --git a/.example/database/gdb/mysql/gdb_json_xml.go b/.example/database/gdb/mysql/gdb_json_xml.go index 7a273b884..8be1b9163 100644 --- a/.example/database/gdb/mysql/gdb_json_xml.go +++ b/.example/database/gdb/mysql/gdb_json_xml.go @@ -2,6 +2,7 @@ package main import ( "fmt" + "github.com/gogf/gf/os/gctx" "github.com/gogf/gf/database/gdb" "github.com/gogf/gf/encoding/gparser" @@ -19,19 +20,22 @@ func main() { Role: "master", Charset: "utf8", }) - db := g.DB() - one, err := db.Table("user").Where("id=?", 1).One() + var ( + db = g.DB() + ctx = gctx.New() + ) + one, err := db.Ctx(ctx).Model("user").Where("id=?", 1).One() if err != nil { panic(err) } // 使用内置方法转换为json/xml - fmt.Println(one.ToJson()) - fmt.Println(one.ToXml()) + fmt.Println(one.Json()) + fmt.Println(one.Xml()) // 自定义方法方法转换为json/xml - jsonContent, _ := gparser.VarToJson(one.ToMap()) + jsonContent, _ := gparser.VarToJson(one.Map()) fmt.Println(string(jsonContent)) - xmlContent, _ := gparser.VarToXml(one.ToMap()) + xmlContent, _ := gparser.VarToXml(one.Map()) fmt.Println(string(xmlContent)) } diff --git a/.example/database/gdb/mysql/gdb_pool.go b/.example/database/gdb/mysql/gdb_pool.go index 0a435d618..dcfdd063a 100644 --- a/.example/database/gdb/mysql/gdb_pool.go +++ b/.example/database/gdb/mysql/gdb_pool.go @@ -1,20 +1,24 @@ package main import ( + "github.com/gogf/gf/os/gctx" "time" "github.com/gogf/gf/frame/g" ) func main() { - db := g.DB() + var ( + db = g.DB() + ctx = gctx.New() + ) // 开启调试模式,以便于记录所有执行的SQL db.SetDebug(true) for { for i := 0; i < 10; i++ { - go db.Table("user").All() + go db.Ctx(ctx).Model("user").All() } time.Sleep(time.Millisecond * 100) } diff --git a/.example/database/gdb/mysql/gdb_reconnect.go b/.example/database/gdb/mysql/gdb_reconnect.go index 18d53ef14..fbbb594d9 100644 --- a/.example/database/gdb/mysql/gdb_reconnect.go +++ b/.example/database/gdb/mysql/gdb_reconnect.go @@ -3,14 +3,18 @@ package main import ( "fmt" "github.com/gogf/gf/frame/g" + "github.com/gogf/gf/os/gctx" "time" ) func main() { - db := g.DB() + var ( + db = g.DB() + ctx = gctx.New() + ) db.SetDebug(true) for { - r, err := db.Table("user").All() + r, err := db.Ctx(ctx).Model("user").All() fmt.Println(err) fmt.Println(r) time.Sleep(time.Second * 10) diff --git a/.example/database/gdb/mysql/gdb_struct.go b/.example/database/gdb/mysql/gdb_struct.go index 6aa5b8830..dfe401475 100644 --- a/.example/database/gdb/mysql/gdb_struct.go +++ b/.example/database/gdb/mysql/gdb_struct.go @@ -17,7 +17,7 @@ func main() { } user := (*User)(nil) fmt.Println(user) - err := db.Table("test").Where("id=1").Struct(&user) + err := db.Model("test").Where("id=1").Scan(&user) fmt.Println(err) fmt.Println(user) } diff --git a/.example/database/gdb/mysql/gdb_tables.go b/.example/database/gdb/mysql/gdb_tables.go index 8dbf2d222..6c84b9e1a 100644 --- a/.example/database/gdb/mysql/gdb_tables.go +++ b/.example/database/gdb/mysql/gdb_tables.go @@ -2,13 +2,17 @@ package main import ( "github.com/gogf/gf/frame/g" + "github.com/gogf/gf/os/gctx" ) func main() { - db := g.DB() + var ( + db = g.DB() + ctx = gctx.New() + ) db.SetDebug(true) - tables, err := db.Tables() + tables, err := db.Tables(ctx) if err != nil { panic(err) } diff --git a/.example/database/gdb/mysql/gdb_tables_fields.go b/.example/database/gdb/mysql/gdb_tables_fields.go index 3f5409b95..fe6e412b5 100644 --- a/.example/database/gdb/mysql/gdb_tables_fields.go +++ b/.example/database/gdb/mysql/gdb_tables_fields.go @@ -2,20 +2,24 @@ package main import ( "github.com/gogf/gf/frame/g" + "github.com/gogf/gf/os/gctx" ) func main() { - db := g.DB() + var ( + db = g.DB() + ctx = gctx.New() + ) db.SetDebug(true) - tables, e := db.Tables() + tables, e := db.Tables(ctx) if e != nil { panic(e) } if tables != nil { g.Dump(tables) for _, table := range tables { - fields, err := db.TableFields(table) + fields, err := db.TableFields(ctx, table) if err != nil { panic(err) } diff --git a/.example/database/gdb/mysql/gdb_transaction_closure.go b/.example/database/gdb/mysql/gdb_transaction_closure.go index aa05d48d4..9d38aef51 100644 --- a/.example/database/gdb/mysql/gdb_transaction_closure.go +++ b/.example/database/gdb/mysql/gdb_transaction_closure.go @@ -1,26 +1,29 @@ package main import ( + "context" "github.com/gogf/gf/database/gdb" "github.com/gogf/gf/frame/g" + "github.com/gogf/gf/os/gctx" ) func main() { var ( err error db = g.DB() + ctx = gctx.New() table = "user" ) - if err = db.Transaction(func(tx *gdb.TX) error { + if err = db.Transaction(ctx, func(ctx context.Context, tx *gdb.TX) error { // Nested transaction 1. - if err = tx.Transaction(func(tx *gdb.TX) error { + if err = tx.Transaction(ctx, func(ctx context.Context, tx *gdb.TX) error { _, err = tx.Model(table).Data(g.Map{"id": 1, "name": "john"}).Insert() return err }); err != nil { return err } // Nested transaction 2, panic. - if err = tx.Transaction(func(tx *gdb.TX) error { + if err = tx.Transaction(ctx, func(ctx context.Context, tx *gdb.TX) error { _, err = tx.Model(table).Data(g.Map{"id": 2, "name": "smith"}).Insert() // Create a panic that can make this transaction rollback automatically. panic("error") diff --git a/.example/database/gdb/mysql/gdb_update_field.go b/.example/database/gdb/mysql/gdb_update_field.go index c824f4176..9b420db20 100644 --- a/.example/database/gdb/mysql/gdb_update_field.go +++ b/.example/database/gdb/mysql/gdb_update_field.go @@ -12,7 +12,7 @@ import ( func main() { db := g.DB() table := "medicine_clinics_upload_yinchuan" - list, err := db.Table(table).All() + list, err := db.Model(table).All() if err != nil && err != sql.ErrNoRows { panic(err) } diff --git a/.example/database/gdb/mysql/gdb_update_union.go b/.example/database/gdb/mysql/gdb_update_union.go index a0e14b7c0..cf51e548a 100644 --- a/.example/database/gdb/mysql/gdb_update_union.go +++ b/.example/database/gdb/mysql/gdb_update_union.go @@ -9,7 +9,7 @@ import ( func main() { db := g.DB() db.SetDebug(true) - result, err := db.Table("pw_passageway m,pw_template t").Data("t.status", 99).Where("m.templateId=t.id AND m.status = 0").Update() + result, err := db.Model("pw_passageway m,pw_template t").Data("t.status", 99).Where("m.templateId=t.id AND m.status = 0").Update() if err != nil { panic(err) } diff --git a/.example/database/gdb/mysql/gdb_value.go b/.example/database/gdb/mysql/gdb_value.go index 3ba996e67..3909df5d5 100644 --- a/.example/database/gdb/mysql/gdb_value.go +++ b/.example/database/gdb/mysql/gdb_value.go @@ -6,7 +6,7 @@ import ( ) func main() { - one, err := g.DB().Table("carlist c"). + one, err := g.Model("carlist c"). LeftJoin("cardetail d", "c.postid=d.carid"). Where("c.postid", "142039140032006"). Fields("c.*,d.*").One() diff --git a/.example/database/gdb/mysql/gdb_with_insert.go b/.example/database/gdb/mysql/gdb_with_insert.go index 669ab3ce6..b7ef3a15b 100644 --- a/.example/database/gdb/mysql/gdb_with_insert.go +++ b/.example/database/gdb/mysql/gdb_with_insert.go @@ -1,9 +1,11 @@ package main import ( + "context" "fmt" "github.com/gogf/gf/database/gdb" "github.com/gogf/gf/frame/g" + "github.com/gogf/gf/os/gctx" "github.com/gogf/gf/util/gmeta" ) @@ -30,13 +32,13 @@ func main() { } db := g.DB() - db.Transaction(func(tx *gdb.TX) error { + err := db.Transaction(gctx.New(), func(ctx context.Context, tx *gdb.TX) error { for i := 1; i <= 5; i++ { // User. user := User{ Name: fmt.Sprintf(`name_%d`, i), } - lastInsertId, err := db.Model(user).Data(user).OmitEmpty().InsertAndGetId() + lastInsertId, err := db.Ctx(ctx).Model(user).Data(user).OmitEmpty().InsertAndGetId() if err != nil { return err } @@ -45,7 +47,7 @@ func main() { Uid: int(lastInsertId), Address: fmt.Sprintf(`address_%d`, lastInsertId), } - _, err = db.Model(userDetail).Data(userDetail).OmitEmpty().Insert() + _, err = db.Ctx(ctx).Model(userDetail).Data(userDetail).OmitEmpty().Insert() if err != nil { return err } @@ -55,7 +57,7 @@ func main() { Uid: int(lastInsertId), Score: j, } - _, err = db.Model(userScore).Data(userScore).OmitEmpty().Insert() + _, err = db.Ctx(ctx).Model(userScore).Data(userScore).OmitEmpty().Insert() if err != nil { return err } @@ -63,4 +65,5 @@ func main() { } return nil }) + fmt.Println(err) } diff --git a/.example/database/gdb/mysql/issue364.go b/.example/database/gdb/mysql/issue364.go index cae5f6ace..164a8a9bd 100644 --- a/.example/database/gdb/mysql/issue364.go +++ b/.example/database/gdb/mysql/issue364.go @@ -9,7 +9,7 @@ func test1() { db := g.DB() db.SetDebug(true) time.Sleep(1 * time.Minute) - r, e := db.Table("test").Where("id", 10000).Count() + r, e := db.Model("test").Where("id", 10000).Count() if e != nil { panic(e) } @@ -19,7 +19,7 @@ func test1() { func test2() { db := g.DB() db.SetDebug(true) - dao := db.Table("test").Safe() + dao := db.Model("test").Safe() time.Sleep(1 * time.Minute) r, e := dao.Where("id", 10000).Count() if e != nil { diff --git a/container/garray/garray_func.go b/container/garray/garray_func.go index d3e7b7795..364654084 100644 --- a/container/garray/garray_func.go +++ b/container/garray/garray_func.go @@ -8,8 +8,8 @@ package garray import "strings" -// apiInterfaces is used for type assert api for Interfaces. -type apiInterfaces interface { +// iInterfaces is used for type assert api for Interfaces. +type iInterfaces interface { Interfaces() []interface{} } diff --git a/container/garray/garray_z_unit_normal_any_array_test.go b/container/garray/garray_z_unit_normal_any_array_test.go index 004e9bfd3..39b57be19 100644 --- a/container/garray/garray_z_unit_normal_any_array_test.go +++ b/container/garray/garray_z_unit_normal_any_array_test.go @@ -709,7 +709,7 @@ func TestArray_UnmarshalValue(t *testing.T) { "name": "john", "array": []byte(`[1,2,3]`), }, &v) - t.Assert(err, nil) + t.AssertNil(err) t.Assert(v.Name, "john") t.Assert(v.Array.Slice(), g.Slice{1, 2, 3}) }) diff --git a/container/glist/glist.go b/container/glist/glist.go index 94319e50e..1df70e4a9 100644 --- a/container/glist/glist.go +++ b/container/glist/glist.go @@ -36,8 +36,8 @@ func New(safe ...bool) *List { } } -// NewFrom creates and returns a list from a copy of given slice . -// The parameter is used to specify whether using list in concurrent-safety, +// NewFrom creates and returns a list from a copy of given slice `array`. +// The parameter `safe` is used to specify whether using list in concurrent-safety, // which is false in default. func NewFrom(array []interface{}, safe ...bool) *List { l := list.New() @@ -50,7 +50,7 @@ func NewFrom(array []interface{}, safe ...bool) *List { } } -// PushFront inserts a new element with value at the front of list and returns . +// PushFront inserts a new element with value at the front of list and returns `e`. func (l *List) PushFront(v interface{}) (e *Element) { l.mu.Lock() if l.list == nil { @@ -61,7 +61,7 @@ func (l *List) PushFront(v interface{}) (e *Element) { return } -// PushBack inserts a new element with value at the back of list and returns . +// PushBack inserts a new element with value at the back of list and returns `e`. func (l *List) PushBack(v interface{}) (e *Element) { l.mu.Lock() if l.list == nil { @@ -72,7 +72,7 @@ func (l *List) PushBack(v interface{}) (e *Element) { return } -// PushFronts inserts multiple new elements with values at the front of list . +// PushFronts inserts multiple new elements with values at the front of list `l`. func (l *List) PushFronts(values []interface{}) { l.mu.Lock() if l.list == nil { @@ -84,7 +84,7 @@ func (l *List) PushFronts(values []interface{}) { l.mu.Unlock() } -// PushBacks inserts multiple new elements with values at the back of list . +// PushBacks inserts multiple new elements with values at the back of list `l`. func (l *List) PushBacks(values []interface{}) { l.mu.Lock() if l.list == nil { @@ -96,7 +96,7 @@ func (l *List) PushBacks(values []interface{}) { l.mu.Unlock() } -// PopBack removes the element from back of and returns the value of the element. +// PopBack removes the element from back of `l` and returns the value of the element. func (l *List) PopBack() (value interface{}) { l.mu.Lock() defer l.mu.Unlock() @@ -110,7 +110,7 @@ func (l *List) PopBack() (value interface{}) { return } -// PopFront removes the element from front of and returns the value of the element. +// PopFront removes the element from front of `l` and returns the value of the element. func (l *List) PopFront() (value interface{}) { l.mu.Lock() defer l.mu.Unlock() @@ -124,7 +124,7 @@ func (l *List) PopFront() (value interface{}) { return } -// PopBacks removes elements from back of +// PopBacks removes elements from back of `l` // and returns values of the removed elements as slice. func (l *List) PopBacks(max int) (values []interface{}) { l.mu.Lock() @@ -146,7 +146,7 @@ func (l *List) PopBacks(max int) (values []interface{}) { return } -// PopFronts removes elements from front of +// PopFronts removes elements from front of `l` // and returns values of the removed elements as slice. func (l *List) PopFronts(max int) (values []interface{}) { l.mu.Lock() @@ -168,19 +168,19 @@ func (l *List) PopFronts(max int) (values []interface{}) { return } -// PopBackAll removes all elements from back of +// PopBackAll removes all elements from back of `l` // and returns values of the removed elements as slice. func (l *List) PopBackAll() []interface{} { return l.PopBacks(-1) } -// PopFrontAll removes all elements from front of +// PopFrontAll removes all elements from front of `l` // and returns values of the removed elements as slice. func (l *List) PopFrontAll() []interface{} { return l.PopFronts(-1) } -// FrontAll copies and returns values of all elements from front of as slice. +// FrontAll copies and returns values of all elements from front of `l` as slice. func (l *List) FrontAll() (values []interface{}) { l.mu.RLock() defer l.mu.RUnlock() @@ -197,7 +197,7 @@ func (l *List) FrontAll() (values []interface{}) { return } -// BackAll copies and returns values of all elements from back of as slice. +// BackAll copies and returns values of all elements from back of `l` as slice. func (l *List) BackAll() (values []interface{}) { l.mu.RLock() defer l.mu.RUnlock() @@ -214,7 +214,7 @@ func (l *List) BackAll() (values []interface{}) { return } -// FrontValue returns value of the first element of or nil if the list is empty. +// FrontValue returns value of the first element of `l` or nil if the list is empty. func (l *List) FrontValue() (value interface{}) { l.mu.RLock() defer l.mu.RUnlock() @@ -227,7 +227,7 @@ func (l *List) FrontValue() (value interface{}) { return } -// BackValue returns value of the last element of or nil if the list is empty. +// BackValue returns value of the last element of `l` or nil if the list is empty. func (l *List) BackValue() (value interface{}) { l.mu.RLock() defer l.mu.RUnlock() @@ -240,7 +240,7 @@ func (l *List) BackValue() (value interface{}) { return } -// Front returns the first element of list or nil if the list is empty. +// Front returns the first element of list `l` or nil if the list is empty. func (l *List) Front() (e *Element) { l.mu.RLock() defer l.mu.RUnlock() @@ -251,7 +251,7 @@ func (l *List) Front() (e *Element) { return } -// Back returns the last element of list or nil if the list is empty. +// Back returns the last element of list `l` or nil if the list is empty. func (l *List) Back() (e *Element) { l.mu.RLock() defer l.mu.RUnlock() @@ -262,7 +262,7 @@ func (l *List) Back() (e *Element) { return } -// Len returns the number of elements of list . +// Len returns the number of elements of list `l`. // The complexity is O(1). func (l *List) Len() (length int) { l.mu.RLock() @@ -279,9 +279,9 @@ func (l *List) Size() int { return l.Len() } -// MoveBefore moves element to its new position before

. -// If or

is not an element of , or ==

, the list is not modified. -// The element and

must not be nil. +// MoveBefore moves element to its new position before `p`. +// If or

is not an element of , or == `p`, the list is not modified. +// The element and `p` must not be nil. func (l *List) MoveBefore(e, p *Element) { l.mu.Lock() defer l.mu.Unlock() @@ -291,9 +291,9 @@ func (l *List) MoveBefore(e, p *Element) { l.list.MoveBefore(e, p) } -// MoveAfter moves element to its new position after

. -// If or

is not an element of , or ==

, the list is not modified. -// The element and

must not be nil. +// MoveAfter moves element to its new position after `p`. +// If or

is not an element of , or == `p`, the list is not modified. +// The element and `p` must not be nil. func (l *List) MoveAfter(e, p *Element) { l.mu.Lock() defer l.mu.Unlock() @@ -303,8 +303,8 @@ func (l *List) MoveAfter(e, p *Element) { l.list.MoveAfter(e, p) } -// MoveToFront moves element to the front of list . -// If is not an element of , the list is not modified. +// MoveToFront moves element to the front of list `l`. +// If is not an element of `l`, the list is not modified. // The element must not be nil. func (l *List) MoveToFront(e *Element) { l.mu.Lock() @@ -315,8 +315,8 @@ func (l *List) MoveToFront(e *Element) { l.list.MoveToFront(e) } -// MoveToBack moves element to the back of list . -// If is not an element of , the list is not modified. +// MoveToBack moves element to the back of list `l`. +// If is not an element of `l`, the list is not modified. // The element must not be nil. func (l *List) MoveToBack(e *Element) { l.mu.Lock() @@ -327,8 +327,8 @@ func (l *List) MoveToBack(e *Element) { l.list.MoveToBack(e) } -// PushBackList inserts a copy of an other list at the back of list . -// The lists and may be the same, but they must not be nil. +// PushBackList inserts a copy of an other list at the back of list `l`. +// The lists and `other` may be the same, but they must not be nil. func (l *List) PushBackList(other *List) { if l != other { other.mu.RLock() @@ -342,8 +342,8 @@ func (l *List) PushBackList(other *List) { l.list.PushBackList(other.list) } -// PushFrontList inserts a copy of an other list at the front of list . -// The lists and may be the same, but they must not be nil. +// PushFrontList inserts a copy of an other list at the front of list `l`. +// The lists and `other` may be the same, but they must not be nil. func (l *List) PushFrontList(other *List) { if l != other { other.mu.RLock() @@ -357,9 +357,9 @@ func (l *List) PushFrontList(other *List) { l.list.PushFrontList(other.list) } -// InsertAfter inserts a new element with value immediately after

and returns . -// If

is not an element of , the list is not modified. -// The

must not be nil. +// InsertAfter inserts a new element with value immediately after

and returns `e`. +// If

is not an element of `l`, the list is not modified. +// The `p` must not be nil. func (l *List) InsertAfter(p *Element, v interface{}) (e *Element) { l.mu.Lock() defer l.mu.Unlock() @@ -370,9 +370,9 @@ func (l *List) InsertAfter(p *Element, v interface{}) (e *Element) { return } -// InsertBefore inserts a new element with value immediately before

and returns . -// If

is not an element of , the list is not modified. -// The

must not be nil. +// InsertBefore inserts a new element with value immediately before

and returns `e`. +// If

is not an element of `l`, the list is not modified. +// The `p` must not be nil. func (l *List) InsertBefore(p *Element, v interface{}) (e *Element) { l.mu.Lock() defer l.mu.Unlock() @@ -383,7 +383,7 @@ func (l *List) InsertBefore(p *Element, v interface{}) (e *Element) { return } -// Remove removes from if is an element of list . +// Remove removes from if is an element of list `l`. // It returns the element value e.Value. // The element must not be nil. func (l *List) Remove(e *Element) (value interface{}) { @@ -396,7 +396,7 @@ func (l *List) Remove(e *Element) (value interface{}) { return } -// Removes removes multiple elements from if are elements of list . +// Removes removes multiple elements from if are elements of list `l`. func (l *List) Removes(es []*Element) { l.mu.Lock() defer l.mu.Unlock() @@ -409,7 +409,7 @@ func (l *List) Removes(es []*Element) { return } -// RemoveAll removes all elements from list . +// RemoveAll removes all elements from list `l`. func (l *List) RemoveAll() { l.mu.Lock() l.list = list.New() @@ -421,7 +421,7 @@ func (l *List) Clear() { l.RemoveAll() } -// RLockFunc locks reading with given callback function within RWMutex.RLock. +// RLockFunc locks reading with given callback function `f` within RWMutex.RLock. func (l *List) RLockFunc(f func(list *list.List)) { l.mu.RLock() defer l.mu.RUnlock() @@ -430,7 +430,7 @@ func (l *List) RLockFunc(f func(list *list.List)) { } } -// LockFunc locks writing with given callback function within RWMutex.Lock. +// LockFunc locks writing with given callback function `f` within RWMutex.Lock. func (l *List) LockFunc(f func(list *list.List)) { l.mu.Lock() defer l.mu.Unlock() @@ -445,8 +445,8 @@ func (l *List) Iterator(f func(e *Element) bool) { l.IteratorAsc(f) } -// IteratorAsc iterates the list readonly in ascending order with given callback function . -// If returns true, then it continues iterating; or false to stop. +// IteratorAsc iterates the list readonly in ascending order with given callback function `f`. +// If `f` returns true, then it continues iterating; or false to stop. func (l *List) IteratorAsc(f func(e *Element) bool) { l.mu.RLock() defer l.mu.RUnlock() @@ -463,8 +463,8 @@ func (l *List) IteratorAsc(f func(e *Element) bool) { } } -// IteratorDesc iterates the list readonly in descending order with given callback function . -// If returns true, then it continues iterating; or false to stop. +// IteratorDesc iterates the list readonly in descending order with given callback function `f`. +// If `f` returns true, then it continues iterating; or false to stop. func (l *List) IteratorDesc(f func(e *Element) bool) { l.mu.RLock() defer l.mu.RUnlock() @@ -481,7 +481,7 @@ func (l *List) IteratorDesc(f func(e *Element) bool) { } } -// Join joins list elements with a string . +// Join joins list elements with a string `glue`. func (l *List) Join(glue string) string { l.mu.RLock() defer l.mu.RUnlock() diff --git a/container/gmap/gmap.go b/container/gmap/gmap.go index b5e887e62..4cff99d3a 100644 --- a/container/gmap/gmap.go +++ b/container/gmap/gmap.go @@ -13,32 +13,32 @@ type ( ) // New creates and returns an empty hash map. -// The parameter is used to specify whether using map in concurrent-safety, +// The parameter `safe` is used to specify whether using map in concurrent-safety, // which is false in default. func New(safe ...bool) *Map { return NewAnyAnyMap(safe...) } -// NewFrom creates and returns a hash map from given map . -// Note that, the param map will be set as the underlying data map(no deep copy), +// NewFrom creates and returns a hash map from given map `data`. +// Note that, the param `data` map will be set as the underlying data map(no deep copy), // there might be some concurrent-safe issues when changing the map outside. -// The parameter is used to specify whether using tree in concurrent-safety, +// The parameter `safe` is used to specify whether using tree in concurrent-safety, // which is false in default. func NewFrom(data map[interface{}]interface{}, safe ...bool) *Map { return NewAnyAnyMapFrom(data, safe...) } // NewHashMap creates and returns an empty hash map. -// The parameter is used to specify whether using map in concurrent-safety, +// The parameter `safe` is used to specify whether using map in concurrent-safety, // which is false in default. func NewHashMap(safe ...bool) *Map { return NewAnyAnyMap(safe...) } -// NewHashMapFrom creates and returns a hash map from given map . -// Note that, the param map will be set as the underlying data map(no deep copy), +// NewHashMapFrom creates and returns a hash map from given map `data`. +// Note that, the param `data` map will be set as the underlying data map(no deep copy), // there might be some concurrent-safe issues when changing the map outside. -// The parameter is used to specify whether using tree in concurrent-safety, +// The parameter `safe` is used to specify whether using tree in concurrent-safety, // which is false in default. func NewHashMapFrom(data map[interface{}]interface{}, safe ...bool) *Map { return NewAnyAnyMapFrom(data, safe...) diff --git a/container/gmap/gmap_hash_any_any_map.go b/container/gmap/gmap_hash_any_any_map.go index a42cf26ea..ea56aed8c 100644 --- a/container/gmap/gmap_hash_any_any_map.go +++ b/container/gmap/gmap_hash_any_any_map.go @@ -23,7 +23,7 @@ type AnyAnyMap struct { } // NewAnyAnyMap creates and returns an empty hash map. -// The parameter is used to specify whether using map in concurrent-safety, +// The parameter `safe` is used to specify whether using map in concurrent-safety, // which is false in default. func NewAnyAnyMap(safe ...bool) *AnyAnyMap { return &AnyAnyMap{ @@ -32,8 +32,8 @@ func NewAnyAnyMap(safe ...bool) *AnyAnyMap { } } -// NewAnyAnyMapFrom creates and returns a hash map from given map . -// Note that, the param map will be set as the underlying data map(no deep copy), +// NewAnyAnyMapFrom creates and returns a hash map from given map `data`. +// Note that, the param `data` map will be set as the underlying data map(no deep copy), // there might be some concurrent-safe issues when changing the map outside. func NewAnyAnyMapFrom(data map[interface{}]interface{}, safe ...bool) *AnyAnyMap { return &AnyAnyMap{ @@ -42,8 +42,8 @@ func NewAnyAnyMapFrom(data map[interface{}]interface{}, safe ...bool) *AnyAnyMap } } -// Iterator iterates the hash map readonly with custom callback function . -// If returns true, then it continues iterating; or false to stop. +// Iterator iterates the hash map readonly with custom callback function `f`. +// If `f` returns true, then it continues iterating; or false to stop. func (m *AnyAnyMap) Iterator(f func(k interface{}, v interface{}) bool) { m.mu.RLock() defer m.mu.RUnlock() @@ -143,8 +143,8 @@ func (m *AnyAnyMap) Sets(data map[interface{}]interface{}) { m.mu.Unlock() } -// Search searches the map with given . -// Second return parameter is true if key was found, otherwise false. +// Search searches the map with given `key`. +// Second return parameter `found` is true if key was found, otherwise false. func (m *AnyAnyMap) Search(key interface{}) (value interface{}, found bool) { m.mu.RLock() if m.data != nil { @@ -154,7 +154,7 @@ func (m *AnyAnyMap) Search(key interface{}) (value interface{}, found bool) { return } -// Get returns the value by given . +// Get returns the value by given `key`. func (m *AnyAnyMap) Get(key interface{}) (value interface{}) { m.mu.RLock() if m.data != nil { @@ -175,7 +175,7 @@ func (m *AnyAnyMap) Pop() (key, value interface{}) { return } -// Pops retrieves and deletes items from the map. +// Pops retrieves and deletes `size` items from the map. // It returns all items if size == -1. func (m *AnyAnyMap) Pops(size int) map[interface{}]interface{} { m.mu.Lock() @@ -202,14 +202,14 @@ func (m *AnyAnyMap) Pops(size int) map[interface{}]interface{} { } // doSetWithLockCheck checks whether value of the key exists with mutex.Lock, -// if not exists, set value to the map with given , +// if not exists, set value to the map with given `key`, // or else just return the existing value. // -// When setting value, if is type of , +// When setting value, if `value` is type of , // it will be executed with mutex.Lock of the hash map, -// and its return value will be set to the map with . +// and its return value will be set to the map with `key`. // -// It returns value with given . +// It returns value with given `key`. func (m *AnyAnyMap) doSetWithLockCheck(key interface{}, value interface{}) interface{} { m.mu.Lock() defer m.mu.Unlock() @@ -229,7 +229,7 @@ func (m *AnyAnyMap) doSetWithLockCheck(key interface{}, value interface{}) inter } // GetOrSet returns the value by key, -// or sets value with given if it does not exist and then returns this value. +// or sets value with given `value` if it does not exist and then returns this value. func (m *AnyAnyMap) GetOrSet(key interface{}, value interface{}) interface{} { if v, ok := m.Search(key); !ok { return m.doSetWithLockCheck(key, value) @@ -239,7 +239,7 @@ func (m *AnyAnyMap) GetOrSet(key interface{}, value interface{}) interface{} { } // GetOrSetFunc returns the value by key, -// or sets value with returned value of callback function if it does not exist +// or sets value with returned value of callback function `f` if it does not exist // and then returns this value. func (m *AnyAnyMap) GetOrSetFunc(key interface{}, f func() interface{}) interface{} { if v, ok := m.Search(key); !ok { @@ -250,10 +250,10 @@ func (m *AnyAnyMap) GetOrSetFunc(key interface{}, f func() interface{}) interfac } // GetOrSetFuncLock returns the value by key, -// or sets value with returned value of callback function if it does not exist +// or sets value with returned value of callback function `f` if it does not exist // and then returns this value. // -// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function +// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function `f` // with mutex.Lock of the hash map. func (m *AnyAnyMap) GetOrSetFuncLock(key interface{}, f func() interface{}) interface{} { if v, ok := m.Search(key); !ok { @@ -263,7 +263,7 @@ func (m *AnyAnyMap) GetOrSetFuncLock(key interface{}, f func() interface{}) inte } } -// GetVar returns a Var with the value by given . +// GetVar returns a Var with the value by given `key`. // The returned Var is un-concurrent safe. func (m *AnyAnyMap) GetVar(key interface{}) *gvar.Var { return gvar.New(m.Get(key)) @@ -287,8 +287,8 @@ func (m *AnyAnyMap) GetVarOrSetFuncLock(key interface{}, f func() interface{}) * return gvar.New(m.GetOrSetFuncLock(key, f)) } -// SetIfNotExist sets to the map if the does not exist, and then returns true. -// It returns false if exists, and would be ignored. +// SetIfNotExist sets to the map if the `key` does not exist, and then returns true. +// It returns false if exists, and `value` would be ignored. func (m *AnyAnyMap) SetIfNotExist(key interface{}, value interface{}) bool { if !m.Contains(key) { m.doSetWithLockCheck(key, value) @@ -297,8 +297,8 @@ func (m *AnyAnyMap) SetIfNotExist(key interface{}, value interface{}) bool { return false } -// SetIfNotExistFunc sets value with return value of callback function , and then returns true. -// It returns false if exists, and would be ignored. +// SetIfNotExistFunc sets value with return value of callback function `f`, and then returns true. +// It returns false if exists, and `value` would be ignored. func (m *AnyAnyMap) SetIfNotExistFunc(key interface{}, f func() interface{}) bool { if !m.Contains(key) { m.doSetWithLockCheck(key, f()) @@ -307,11 +307,11 @@ func (m *AnyAnyMap) SetIfNotExistFunc(key interface{}, f func() interface{}) boo return false } -// SetIfNotExistFuncLock sets value with return value of callback function , and then returns true. -// It returns false if exists, and would be ignored. +// SetIfNotExistFuncLock sets value with return value of callback function `f`, and then returns true. +// It returns false if exists, and `value` would be ignored. // // SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that -// it executes function with mutex.Lock of the hash map. +// it executes function `f` with mutex.Lock of the hash map. func (m *AnyAnyMap) SetIfNotExistFuncLock(key interface{}, f func() interface{}) bool { if !m.Contains(key) { m.doSetWithLockCheck(key, f) @@ -320,7 +320,7 @@ func (m *AnyAnyMap) SetIfNotExistFuncLock(key interface{}, f func() interface{}) return false } -// Remove deletes value from map by given , and return this deleted value. +// Remove deletes value from map by given `key`, and return this deleted value. func (m *AnyAnyMap) Remove(key interface{}) (value interface{}) { m.mu.Lock() if m.data != nil { @@ -375,7 +375,7 @@ func (m *AnyAnyMap) Values() []interface{} { } // Contains checks whether a key exists. -// It returns true if the exists, or else false. +// It returns true if the `key` exists, or else false. func (m *AnyAnyMap) Contains(key interface{}) bool { var ok bool m.mu.RLock() @@ -407,21 +407,21 @@ func (m *AnyAnyMap) Clear() { m.mu.Unlock() } -// Replace the data of the map with given . +// Replace the data of the map with given `data`. func (m *AnyAnyMap) Replace(data map[interface{}]interface{}) { m.mu.Lock() m.data = data m.mu.Unlock() } -// LockFunc locks writing with given callback function within RWMutex.Lock. +// LockFunc locks writing with given callback function `f` within RWMutex.Lock. func (m *AnyAnyMap) LockFunc(f func(m map[interface{}]interface{})) { m.mu.Lock() defer m.mu.Unlock() f(m.data) } -// RLockFunc locks reading with given callback function within RWMutex.RLock. +// RLockFunc locks reading with given callback function `f` within RWMutex.RLock. func (m *AnyAnyMap) RLockFunc(f func(m map[interface{}]interface{})) { m.mu.RLock() defer m.mu.RUnlock() @@ -440,7 +440,7 @@ func (m *AnyAnyMap) Flip() { } // Merge merges two hash maps. -// The map will be merged into the map . +// The map will be merged into the map `m`. func (m *AnyAnyMap) Merge(other *AnyAnyMap) { m.mu.Lock() defer m.mu.Unlock() @@ -460,7 +460,7 @@ func (m *AnyAnyMap) Merge(other *AnyAnyMap) { // String returns the map as a string. func (m *AnyAnyMap) String() string { b, _ := m.MarshalJSON() - return gconv.UnsafeBytesToStr(b) + return string(b) } // MarshalJSON implements the interface MarshalJSON for json.Marshal. diff --git a/container/gmap/gmap_hash_int_any_map.go b/container/gmap/gmap_hash_int_any_map.go index f99fd77d4..1a53a8b63 100644 --- a/container/gmap/gmap_hash_int_any_map.go +++ b/container/gmap/gmap_hash_int_any_map.go @@ -23,7 +23,7 @@ type IntAnyMap struct { } // NewIntAnyMap returns an empty IntAnyMap object. -// The parameter is used to specify whether using map in concurrent-safety, +// The parameter `safe` is used to specify whether using map in concurrent-safety, // which is false in default. func NewIntAnyMap(safe ...bool) *IntAnyMap { return &IntAnyMap{ @@ -32,8 +32,8 @@ func NewIntAnyMap(safe ...bool) *IntAnyMap { } } -// NewIntAnyMapFrom creates and returns a hash map from given map . -// Note that, the param map will be set as the underlying data map(no deep copy), +// NewIntAnyMapFrom creates and returns a hash map from given map `data`. +// Note that, the param `data` map will be set as the underlying data map(no deep copy), // there might be some concurrent-safe issues when changing the map outside. func NewIntAnyMapFrom(data map[int]interface{}, safe ...bool) *IntAnyMap { return &IntAnyMap{ @@ -42,8 +42,8 @@ func NewIntAnyMapFrom(data map[int]interface{}, safe ...bool) *IntAnyMap { } } -// Iterator iterates the hash map readonly with custom callback function . -// If returns true, then it continues iterating; or false to stop. +// Iterator iterates the hash map readonly with custom callback function `f`. +// If `f` returns true, then it continues iterating; or false to stop. func (m *IntAnyMap) Iterator(f func(k int, v interface{}) bool) { m.mu.RLock() defer m.mu.RUnlock() @@ -143,8 +143,8 @@ func (m *IntAnyMap) Sets(data map[int]interface{}) { m.mu.Unlock() } -// Search searches the map with given . -// Second return parameter is true if key was found, otherwise false. +// Search searches the map with given `key`. +// Second return parameter `found` is true if key was found, otherwise false. func (m *IntAnyMap) Search(key int) (value interface{}, found bool) { m.mu.RLock() if m.data != nil { @@ -154,7 +154,7 @@ func (m *IntAnyMap) Search(key int) (value interface{}, found bool) { return } -// Get returns the value by given . +// Get returns the value by given `key`. func (m *IntAnyMap) Get(key int) (value interface{}) { m.mu.RLock() if m.data != nil { @@ -175,7 +175,7 @@ func (m *IntAnyMap) Pop() (key int, value interface{}) { return } -// Pops retrieves and deletes items from the map. +// Pops retrieves and deletes `size` items from the map. // It returns all items if size == -1. func (m *IntAnyMap) Pops(size int) map[int]interface{} { m.mu.Lock() @@ -202,14 +202,14 @@ func (m *IntAnyMap) Pops(size int) map[int]interface{} { } // doSetWithLockCheck checks whether value of the key exists with mutex.Lock, -// if not exists, set value to the map with given , +// if not exists, set value to the map with given `key`, // or else just return the existing value. // -// When setting value, if is type of , +// When setting value, if `value` is type of , // it will be executed with mutex.Lock of the hash map, -// and its return value will be set to the map with . +// and its return value will be set to the map with `key`. // -// It returns value with given . +// It returns value with given `key`. func (m *IntAnyMap) doSetWithLockCheck(key int, value interface{}) interface{} { m.mu.Lock() defer m.mu.Unlock() @@ -229,7 +229,7 @@ func (m *IntAnyMap) doSetWithLockCheck(key int, value interface{}) interface{} { } // GetOrSet returns the value by key, -// or sets value with given if it does not exist and then returns this value. +// or sets value with given `value` if it does not exist and then returns this value. func (m *IntAnyMap) GetOrSet(key int, value interface{}) interface{} { if v, ok := m.Search(key); !ok { return m.doSetWithLockCheck(key, value) @@ -239,7 +239,7 @@ func (m *IntAnyMap) GetOrSet(key int, value interface{}) interface{} { } // GetOrSetFunc returns the value by key, -// or sets value with returned value of callback function if it does not exist and returns this value. +// or sets value with returned value of callback function `f` if it does not exist and returns this value. func (m *IntAnyMap) GetOrSetFunc(key int, f func() interface{}) interface{} { if v, ok := m.Search(key); !ok { return m.doSetWithLockCheck(key, f()) @@ -249,9 +249,9 @@ func (m *IntAnyMap) GetOrSetFunc(key int, f func() interface{}) interface{} { } // GetOrSetFuncLock returns the value by key, -// or sets value with returned value of callback function if it does not exist and returns this value. +// or sets value with returned value of callback function `f` if it does not exist and returns this value. // -// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function +// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function `f` // with mutex.Lock of the hash map. func (m *IntAnyMap) GetOrSetFuncLock(key int, f func() interface{}) interface{} { if v, ok := m.Search(key); !ok { @@ -261,7 +261,7 @@ func (m *IntAnyMap) GetOrSetFuncLock(key int, f func() interface{}) interface{} } } -// GetVar returns a Var with the value by given . +// GetVar returns a Var with the value by given `key`. // The returned Var is un-concurrent safe. func (m *IntAnyMap) GetVar(key int) *gvar.Var { return gvar.New(m.Get(key)) @@ -285,8 +285,8 @@ func (m *IntAnyMap) GetVarOrSetFuncLock(key int, f func() interface{}) *gvar.Var return gvar.New(m.GetOrSetFuncLock(key, f)) } -// SetIfNotExist sets to the map if the does not exist, and then returns true. -// It returns false if exists, and would be ignored. +// SetIfNotExist sets to the map if the `key` does not exist, and then returns true. +// It returns false if exists, and `value` would be ignored. func (m *IntAnyMap) SetIfNotExist(key int, value interface{}) bool { if !m.Contains(key) { m.doSetWithLockCheck(key, value) @@ -295,8 +295,8 @@ func (m *IntAnyMap) SetIfNotExist(key int, value interface{}) bool { return false } -// SetIfNotExistFunc sets value with return value of callback function , and then returns true. -// It returns false if exists, and would be ignored. +// SetIfNotExistFunc sets value with return value of callback function `f`, and then returns true. +// It returns false if exists, and `value` would be ignored. func (m *IntAnyMap) SetIfNotExistFunc(key int, f func() interface{}) bool { if !m.Contains(key) { m.doSetWithLockCheck(key, f()) @@ -305,11 +305,11 @@ func (m *IntAnyMap) SetIfNotExistFunc(key int, f func() interface{}) bool { return false } -// SetIfNotExistFuncLock sets value with return value of callback function , and then returns true. -// It returns false if exists, and would be ignored. +// SetIfNotExistFuncLock sets value with return value of callback function `f`, and then returns true. +// It returns false if exists, and `value` would be ignored. // // SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that -// it executes function with mutex.Lock of the hash map. +// it executes function `f` with mutex.Lock of the hash map. func (m *IntAnyMap) SetIfNotExistFuncLock(key int, f func() interface{}) bool { if !m.Contains(key) { m.doSetWithLockCheck(key, f) @@ -329,7 +329,7 @@ func (m *IntAnyMap) Removes(keys []int) { m.mu.Unlock() } -// Remove deletes value from map by given , and return this deleted value. +// Remove deletes value from map by given `key`, and return this deleted value. func (m *IntAnyMap) Remove(key int) (value interface{}) { m.mu.Lock() if m.data != nil { @@ -373,7 +373,7 @@ func (m *IntAnyMap) Values() []interface{} { } // Contains checks whether a key exists. -// It returns true if the exists, or else false. +// It returns true if the `key` exists, or else false. func (m *IntAnyMap) Contains(key int) bool { var ok bool m.mu.RLock() @@ -405,21 +405,21 @@ func (m *IntAnyMap) Clear() { m.mu.Unlock() } -// Replace the data of the map with given . +// Replace the data of the map with given `data`. func (m *IntAnyMap) Replace(data map[int]interface{}) { m.mu.Lock() m.data = data m.mu.Unlock() } -// LockFunc locks writing with given callback function within RWMutex.Lock. +// LockFunc locks writing with given callback function `f` within RWMutex.Lock. func (m *IntAnyMap) LockFunc(f func(m map[int]interface{})) { m.mu.Lock() defer m.mu.Unlock() f(m.data) } -// RLockFunc locks reading with given callback function within RWMutex.RLock. +// RLockFunc locks reading with given callback function `f` within RWMutex.RLock. func (m *IntAnyMap) RLockFunc(f func(m map[int]interface{})) { m.mu.RLock() defer m.mu.RUnlock() @@ -438,7 +438,7 @@ func (m *IntAnyMap) Flip() { } // Merge merges two hash maps. -// The map will be merged into the map . +// The map will be merged into the map `m`. func (m *IntAnyMap) Merge(other *IntAnyMap) { m.mu.Lock() defer m.mu.Unlock() @@ -458,7 +458,7 @@ func (m *IntAnyMap) Merge(other *IntAnyMap) { // String returns the map as a string. func (m *IntAnyMap) String() string { b, _ := m.MarshalJSON() - return gconv.UnsafeBytesToStr(b) + return string(b) } // MarshalJSON implements the interface MarshalJSON for json.Marshal. diff --git a/container/gmap/gmap_hash_int_int_map.go b/container/gmap/gmap_hash_int_int_map.go index 3f8b8d411..404ad6f70 100644 --- a/container/gmap/gmap_hash_int_int_map.go +++ b/container/gmap/gmap_hash_int_int_map.go @@ -21,7 +21,7 @@ type IntIntMap struct { } // NewIntIntMap returns an empty IntIntMap object. -// The parameter is used to specify whether using map in concurrent-safety, +// The parameter `safe` is used to specify whether using map in concurrent-safety, // which is false in default. func NewIntIntMap(safe ...bool) *IntIntMap { return &IntIntMap{ @@ -30,8 +30,8 @@ func NewIntIntMap(safe ...bool) *IntIntMap { } } -// NewIntIntMapFrom creates and returns a hash map from given map . -// Note that, the param map will be set as the underlying data map(no deep copy), +// NewIntIntMapFrom creates and returns a hash map from given map `data`. +// Note that, the param `data` map will be set as the underlying data map(no deep copy), // there might be some concurrent-safe issues when changing the map outside. func NewIntIntMapFrom(data map[int]int, safe ...bool) *IntIntMap { return &IntIntMap{ @@ -40,8 +40,8 @@ func NewIntIntMapFrom(data map[int]int, safe ...bool) *IntIntMap { } } -// Iterator iterates the hash map readonly with custom callback function . -// If returns true, then it continues iterating; or false to stop. +// Iterator iterates the hash map readonly with custom callback function `f`. +// If `f` returns true, then it continues iterating; or false to stop. func (m *IntIntMap) Iterator(f func(k int, v int) bool) { m.mu.RLock() defer m.mu.RUnlock() @@ -130,8 +130,8 @@ func (m *IntIntMap) Sets(data map[int]int) { m.mu.Unlock() } -// Search searches the map with given . -// Second return parameter is true if key was found, otherwise false. +// Search searches the map with given `key`. +// Second return parameter `found` is true if key was found, otherwise false. func (m *IntIntMap) Search(key int) (value int, found bool) { m.mu.RLock() if m.data != nil { @@ -141,7 +141,7 @@ func (m *IntIntMap) Search(key int) (value int, found bool) { return } -// Get returns the value by given . +// Get returns the value by given `key`. func (m *IntIntMap) Get(key int) (value int) { m.mu.RLock() if m.data != nil { @@ -162,7 +162,7 @@ func (m *IntIntMap) Pop() (key, value int) { return } -// Pops retrieves and deletes items from the map. +// Pops retrieves and deletes `size` items from the map. // It returns all items if size == -1. func (m *IntIntMap) Pops(size int) map[int]int { m.mu.Lock() @@ -189,10 +189,10 @@ func (m *IntIntMap) Pops(size int) map[int]int { } // doSetWithLockCheck checks whether value of the key exists with mutex.Lock, -// if not exists, set value to the map with given , +// if not exists, set value to the map with given `key`, // or else just return the existing value. // -// It returns value with given . +// It returns value with given `key`. func (m *IntIntMap) doSetWithLockCheck(key int, value int) int { m.mu.Lock() defer m.mu.Unlock() @@ -207,7 +207,7 @@ func (m *IntIntMap) doSetWithLockCheck(key int, value int) int { } // GetOrSet returns the value by key, -// or sets value with given if it does not exist and then returns this value. +// or sets value with given `value` if it does not exist and then returns this value. func (m *IntIntMap) GetOrSet(key int, value int) int { if v, ok := m.Search(key); !ok { return m.doSetWithLockCheck(key, value) @@ -217,7 +217,7 @@ func (m *IntIntMap) GetOrSet(key int, value int) int { } // GetOrSetFunc returns the value by key, -// or sets value with returned value of callback function if it does not exist and returns this value. +// or sets value with returned value of callback function `f` if it does not exist and returns this value. func (m *IntIntMap) GetOrSetFunc(key int, f func() int) int { if v, ok := m.Search(key); !ok { return m.doSetWithLockCheck(key, f()) @@ -227,9 +227,9 @@ func (m *IntIntMap) GetOrSetFunc(key int, f func() int) int { } // GetOrSetFuncLock returns the value by key, -// or sets value with returned value of callback function if it does not exist and returns this value. +// or sets value with returned value of callback function `f` if it does not exist and returns this value. // -// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function +// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function `f` // with mutex.Lock of the hash map. func (m *IntIntMap) GetOrSetFuncLock(key int, f func() int) int { if v, ok := m.Search(key); !ok { @@ -249,8 +249,8 @@ func (m *IntIntMap) GetOrSetFuncLock(key int, f func() int) int { } } -// SetIfNotExist sets to the map if the does not exist, and then returns true. -// It returns false if exists, and would be ignored. +// SetIfNotExist sets to the map if the `key` does not exist, and then returns true. +// It returns false if exists, and `value` would be ignored. func (m *IntIntMap) SetIfNotExist(key int, value int) bool { if !m.Contains(key) { m.doSetWithLockCheck(key, value) @@ -259,8 +259,8 @@ func (m *IntIntMap) SetIfNotExist(key int, value int) bool { return false } -// SetIfNotExistFunc sets value with return value of callback function , and then returns true. -// It returns false if exists, and would be ignored. +// SetIfNotExistFunc sets value with return value of callback function `f`, and then returns true. +// It returns false if exists, and `value` would be ignored. func (m *IntIntMap) SetIfNotExistFunc(key int, f func() int) bool { if !m.Contains(key) { m.doSetWithLockCheck(key, f()) @@ -269,11 +269,11 @@ func (m *IntIntMap) SetIfNotExistFunc(key int, f func() int) bool { return false } -// SetIfNotExistFuncLock sets value with return value of callback function , and then returns true. -// It returns false if exists, and would be ignored. +// SetIfNotExistFuncLock sets value with return value of callback function `f`, and then returns true. +// It returns false if exists, and `value` would be ignored. // // SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that -// it executes function with mutex.Lock of the hash map. +// it executes function `f` with mutex.Lock of the hash map. func (m *IntIntMap) SetIfNotExistFuncLock(key int, f func() int) bool { if !m.Contains(key) { m.mu.Lock() @@ -300,7 +300,7 @@ func (m *IntIntMap) Removes(keys []int) { m.mu.Unlock() } -// Remove deletes value from map by given , and return this deleted value. +// Remove deletes value from map by given `key`, and return this deleted value. func (m *IntIntMap) Remove(key int) (value int) { m.mu.Lock() if m.data != nil { @@ -344,7 +344,7 @@ func (m *IntIntMap) Values() []int { } // Contains checks whether a key exists. -// It returns true if the exists, or else false. +// It returns true if the `key` exists, or else false. func (m *IntIntMap) Contains(key int) bool { var ok bool m.mu.RLock() @@ -376,21 +376,21 @@ func (m *IntIntMap) Clear() { m.mu.Unlock() } -// Replace the data of the map with given . +// Replace the data of the map with given `data`. func (m *IntIntMap) Replace(data map[int]int) { m.mu.Lock() m.data = data m.mu.Unlock() } -// LockFunc locks writing with given callback function within RWMutex.Lock. +// LockFunc locks writing with given callback function `f` within RWMutex.Lock. func (m *IntIntMap) LockFunc(f func(m map[int]int)) { m.mu.Lock() defer m.mu.Unlock() f(m.data) } -// RLockFunc locks reading with given callback function within RWMutex.RLock. +// RLockFunc locks reading with given callback function `f` within RWMutex.RLock. func (m *IntIntMap) RLockFunc(f func(m map[int]int)) { m.mu.RLock() defer m.mu.RUnlock() @@ -409,7 +409,7 @@ func (m *IntIntMap) Flip() { } // Merge merges two hash maps. -// The map will be merged into the map . +// The map will be merged into the map `m`. func (m *IntIntMap) Merge(other *IntIntMap) { m.mu.Lock() defer m.mu.Unlock() @@ -429,7 +429,7 @@ func (m *IntIntMap) Merge(other *IntIntMap) { // String returns the map as a string. func (m *IntIntMap) String() string { b, _ := m.MarshalJSON() - return gconv.UnsafeBytesToStr(b) + return string(b) } // MarshalJSON implements the interface MarshalJSON for json.Marshal. diff --git a/container/gmap/gmap_hash_int_str_map.go b/container/gmap/gmap_hash_int_str_map.go index c5f5ac323..9e6dc6c34 100644 --- a/container/gmap/gmap_hash_int_str_map.go +++ b/container/gmap/gmap_hash_int_str_map.go @@ -21,7 +21,7 @@ type IntStrMap struct { } // NewIntStrMap returns an empty IntStrMap object. -// The parameter is used to specify whether using map in concurrent-safety, +// The parameter `safe` is used to specify whether using map in concurrent-safety, // which is false in default. func NewIntStrMap(safe ...bool) *IntStrMap { return &IntStrMap{ @@ -30,8 +30,8 @@ func NewIntStrMap(safe ...bool) *IntStrMap { } } -// NewIntStrMapFrom creates and returns a hash map from given map . -// Note that, the param map will be set as the underlying data map(no deep copy), +// NewIntStrMapFrom creates and returns a hash map from given map `data`. +// Note that, the param `data` map will be set as the underlying data map(no deep copy), // there might be some concurrent-safe issues when changing the map outside. func NewIntStrMapFrom(data map[int]string, safe ...bool) *IntStrMap { return &IntStrMap{ @@ -40,8 +40,8 @@ func NewIntStrMapFrom(data map[int]string, safe ...bool) *IntStrMap { } } -// Iterator iterates the hash map readonly with custom callback function . -// If returns true, then it continues iterating; or false to stop. +// Iterator iterates the hash map readonly with custom callback function `f`. +// If `f` returns true, then it continues iterating; or false to stop. func (m *IntStrMap) Iterator(f func(k int, v string) bool) { m.mu.RLock() defer m.mu.RUnlock() @@ -130,8 +130,8 @@ func (m *IntStrMap) Sets(data map[int]string) { m.mu.Unlock() } -// Search searches the map with given . -// Second return parameter is true if key was found, otherwise false. +// Search searches the map with given `key`. +// Second return parameter `found` is true if key was found, otherwise false. func (m *IntStrMap) Search(key int) (value string, found bool) { m.mu.RLock() if m.data != nil { @@ -141,7 +141,7 @@ func (m *IntStrMap) Search(key int) (value string, found bool) { return } -// Get returns the value by given . +// Get returns the value by given `key`. func (m *IntStrMap) Get(key int) (value string) { m.mu.RLock() if m.data != nil { @@ -162,7 +162,7 @@ func (m *IntStrMap) Pop() (key int, value string) { return } -// Pops retrieves and deletes items from the map. +// Pops retrieves and deletes `size` items from the map. // It returns all items if size == -1. func (m *IntStrMap) Pops(size int) map[int]string { m.mu.Lock() @@ -189,10 +189,10 @@ func (m *IntStrMap) Pops(size int) map[int]string { } // doSetWithLockCheck checks whether value of the key exists with mutex.Lock, -// if not exists, set value to the map with given , +// if not exists, set value to the map with given `key`, // or else just return the existing value. // -// It returns value with given . +// It returns value with given `key`. func (m *IntStrMap) doSetWithLockCheck(key int, value string) string { m.mu.Lock() defer m.mu.Unlock() @@ -207,7 +207,7 @@ func (m *IntStrMap) doSetWithLockCheck(key int, value string) string { } // GetOrSet returns the value by key, -// or sets value with given if it does not exist and then returns this value. +// or sets value with given `value` if it does not exist and then returns this value. func (m *IntStrMap) GetOrSet(key int, value string) string { if v, ok := m.Search(key); !ok { return m.doSetWithLockCheck(key, value) @@ -217,7 +217,7 @@ func (m *IntStrMap) GetOrSet(key int, value string) string { } // GetOrSetFunc returns the value by key, -// or sets value with returned value of callback function if it does not exist and returns this value. +// or sets value with returned value of callback function `f` if it does not exist and returns this value. func (m *IntStrMap) GetOrSetFunc(key int, f func() string) string { if v, ok := m.Search(key); !ok { return m.doSetWithLockCheck(key, f()) @@ -227,9 +227,9 @@ func (m *IntStrMap) GetOrSetFunc(key int, f func() string) string { } // GetOrSetFuncLock returns the value by key, -// or sets value with returned value of callback function if it does not exist and returns this value. +// or sets value with returned value of callback function `f` if it does not exist and returns this value. // -// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function +// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function `f` // with mutex.Lock of the hash map. func (m *IntStrMap) GetOrSetFuncLock(key int, f func() string) string { if v, ok := m.Search(key); !ok { @@ -249,8 +249,8 @@ func (m *IntStrMap) GetOrSetFuncLock(key int, f func() string) string { } } -// SetIfNotExist sets to the map if the does not exist, and then returns true. -// It returns false if exists, and would be ignored. +// SetIfNotExist sets to the map if the `key` does not exist, and then returns true. +// It returns false if exists, and `value` would be ignored. func (m *IntStrMap) SetIfNotExist(key int, value string) bool { if !m.Contains(key) { m.doSetWithLockCheck(key, value) @@ -259,8 +259,8 @@ func (m *IntStrMap) SetIfNotExist(key int, value string) bool { return false } -// SetIfNotExistFunc sets value with return value of callback function , and then returns true. -// It returns false if exists, and would be ignored. +// SetIfNotExistFunc sets value with return value of callback function `f`, and then returns true. +// It returns false if exists, and `value` would be ignored. func (m *IntStrMap) SetIfNotExistFunc(key int, f func() string) bool { if !m.Contains(key) { m.doSetWithLockCheck(key, f()) @@ -269,11 +269,11 @@ func (m *IntStrMap) SetIfNotExistFunc(key int, f func() string) bool { return false } -// SetIfNotExistFuncLock sets value with return value of callback function , and then returns true. -// It returns false if exists, and would be ignored. +// SetIfNotExistFuncLock sets value with return value of callback function `f`, and then returns true. +// It returns false if exists, and `value` would be ignored. // // SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that -// it executes function with mutex.Lock of the hash map. +// it executes function `f` with mutex.Lock of the hash map. func (m *IntStrMap) SetIfNotExistFuncLock(key int, f func() string) bool { if !m.Contains(key) { m.mu.Lock() @@ -300,7 +300,7 @@ func (m *IntStrMap) Removes(keys []int) { m.mu.Unlock() } -// Remove deletes value from map by given , and return this deleted value. +// Remove deletes value from map by given `key`, and return this deleted value. func (m *IntStrMap) Remove(key int) (value string) { m.mu.Lock() if m.data != nil { @@ -344,7 +344,7 @@ func (m *IntStrMap) Values() []string { } // Contains checks whether a key exists. -// It returns true if the exists, or else false. +// It returns true if the `key` exists, or else false. func (m *IntStrMap) Contains(key int) bool { var ok bool m.mu.RLock() @@ -376,21 +376,21 @@ func (m *IntStrMap) Clear() { m.mu.Unlock() } -// Replace the data of the map with given . +// Replace the data of the map with given `data`. func (m *IntStrMap) Replace(data map[int]string) { m.mu.Lock() m.data = data m.mu.Unlock() } -// LockFunc locks writing with given callback function within RWMutex.Lock. +// LockFunc locks writing with given callback function `f` within RWMutex.Lock. func (m *IntStrMap) LockFunc(f func(m map[int]string)) { m.mu.Lock() defer m.mu.Unlock() f(m.data) } -// RLockFunc locks reading with given callback function within RWMutex.RLock. +// RLockFunc locks reading with given callback function `f` within RWMutex.RLock. func (m *IntStrMap) RLockFunc(f func(m map[int]string)) { m.mu.RLock() defer m.mu.RUnlock() @@ -409,7 +409,7 @@ func (m *IntStrMap) Flip() { } // Merge merges two hash maps. -// The map will be merged into the map . +// The map will be merged into the map `m`. func (m *IntStrMap) Merge(other *IntStrMap) { m.mu.Lock() defer m.mu.Unlock() @@ -429,7 +429,7 @@ func (m *IntStrMap) Merge(other *IntStrMap) { // String returns the map as a string. func (m *IntStrMap) String() string { b, _ := m.MarshalJSON() - return gconv.UnsafeBytesToStr(b) + return string(b) } // MarshalJSON implements the interface MarshalJSON for json.Marshal. diff --git a/container/gmap/gmap_hash_str_any_map.go b/container/gmap/gmap_hash_str_any_map.go index 04d70f664..609ebc026 100644 --- a/container/gmap/gmap_hash_str_any_map.go +++ b/container/gmap/gmap_hash_str_any_map.go @@ -23,7 +23,7 @@ type StrAnyMap struct { } // NewStrAnyMap returns an empty StrAnyMap object. -// The parameter is used to specify whether using map in concurrent-safety, +// The parameter `safe` is used to specify whether using map in concurrent-safety, // which is false in default. func NewStrAnyMap(safe ...bool) *StrAnyMap { return &StrAnyMap{ @@ -32,8 +32,8 @@ func NewStrAnyMap(safe ...bool) *StrAnyMap { } } -// NewStrAnyMapFrom creates and returns a hash map from given map . -// Note that, the param map will be set as the underlying data map(no deep copy), +// NewStrAnyMapFrom creates and returns a hash map from given map `data`. +// Note that, the param `data` map will be set as the underlying data map(no deep copy), // there might be some concurrent-safe issues when changing the map outside. func NewStrAnyMapFrom(data map[string]interface{}, safe ...bool) *StrAnyMap { return &StrAnyMap{ @@ -42,8 +42,8 @@ func NewStrAnyMapFrom(data map[string]interface{}, safe ...bool) *StrAnyMap { } } -// Iterator iterates the hash map readonly with custom callback function . -// If returns true, then it continues iterating; or false to stop. +// Iterator iterates the hash map readonly with custom callback function `f`. +// If `f` returns true, then it continues iterating; or false to stop. func (m *StrAnyMap) Iterator(f func(k string, v interface{}) bool) { m.mu.RLock() defer m.mu.RUnlock() @@ -137,8 +137,8 @@ func (m *StrAnyMap) Sets(data map[string]interface{}) { m.mu.Unlock() } -// Search searches the map with given . -// Second return parameter is true if key was found, otherwise false. +// Search searches the map with given `key`. +// Second return parameter `found` is true if key was found, otherwise false. func (m *StrAnyMap) Search(key string) (value interface{}, found bool) { m.mu.RLock() if m.data != nil { @@ -148,7 +148,7 @@ func (m *StrAnyMap) Search(key string) (value interface{}, found bool) { return } -// Get returns the value by given . +// Get returns the value by given `key`. func (m *StrAnyMap) Get(key string) (value interface{}) { m.mu.RLock() if m.data != nil { @@ -169,7 +169,7 @@ func (m *StrAnyMap) Pop() (key string, value interface{}) { return } -// Pops retrieves and deletes items from the map. +// Pops retrieves and deletes `size` items from the map. // It returns all items if size == -1. func (m *StrAnyMap) Pops(size int) map[string]interface{} { m.mu.Lock() @@ -196,14 +196,14 @@ func (m *StrAnyMap) Pops(size int) map[string]interface{} { } // doSetWithLockCheck checks whether value of the key exists with mutex.Lock, -// if not exists, set value to the map with given , +// if not exists, set value to the map with given `key`, // or else just return the existing value. // -// When setting value, if is type of , +// When setting value, if `value` is type of , // it will be executed with mutex.Lock of the hash map, -// and its return value will be set to the map with . +// and its return value will be set to the map with `key`. // -// It returns value with given . +// It returns value with given `key`. func (m *StrAnyMap) doSetWithLockCheck(key string, value interface{}) interface{} { m.mu.Lock() defer m.mu.Unlock() @@ -223,7 +223,7 @@ func (m *StrAnyMap) doSetWithLockCheck(key string, value interface{}) interface{ } // GetOrSet returns the value by key, -// or sets value with given if it does not exist and then returns this value. +// or sets value with given `value` if it does not exist and then returns this value. func (m *StrAnyMap) GetOrSet(key string, value interface{}) interface{} { if v, ok := m.Search(key); !ok { return m.doSetWithLockCheck(key, value) @@ -233,7 +233,7 @@ func (m *StrAnyMap) GetOrSet(key string, value interface{}) interface{} { } // GetOrSetFunc returns the value by key, -// or sets value with returned value of callback function if it does not exist +// or sets value with returned value of callback function `f` if it does not exist // and then returns this value. func (m *StrAnyMap) GetOrSetFunc(key string, f func() interface{}) interface{} { if v, ok := m.Search(key); !ok { @@ -244,10 +244,10 @@ func (m *StrAnyMap) GetOrSetFunc(key string, f func() interface{}) interface{} { } // GetOrSetFuncLock returns the value by key, -// or sets value with returned value of callback function if it does not exist +// or sets value with returned value of callback function `f` if it does not exist // and then returns this value. // -// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function +// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function `f` // with mutex.Lock of the hash map. func (m *StrAnyMap) GetOrSetFuncLock(key string, f func() interface{}) interface{} { if v, ok := m.Search(key); !ok { @@ -257,7 +257,7 @@ func (m *StrAnyMap) GetOrSetFuncLock(key string, f func() interface{}) interface } } -// GetVar returns a Var with the value by given . +// GetVar returns a Var with the value by given `key`. // The returned Var is un-concurrent safe. func (m *StrAnyMap) GetVar(key string) *gvar.Var { return gvar.New(m.Get(key)) @@ -281,8 +281,8 @@ func (m *StrAnyMap) GetVarOrSetFuncLock(key string, f func() interface{}) *gvar. return gvar.New(m.GetOrSetFuncLock(key, f)) } -// SetIfNotExist sets to the map if the does not exist, and then returns true. -// It returns false if exists, and would be ignored. +// SetIfNotExist sets to the map if the `key` does not exist, and then returns true. +// It returns false if exists, and `value` would be ignored. func (m *StrAnyMap) SetIfNotExist(key string, value interface{}) bool { if !m.Contains(key) { m.doSetWithLockCheck(key, value) @@ -291,8 +291,8 @@ func (m *StrAnyMap) SetIfNotExist(key string, value interface{}) bool { return false } -// SetIfNotExistFunc sets value with return value of callback function , and then returns true. -// It returns false if exists, and would be ignored. +// SetIfNotExistFunc sets value with return value of callback function `f`, and then returns true. +// It returns false if exists, and `value` would be ignored. func (m *StrAnyMap) SetIfNotExistFunc(key string, f func() interface{}) bool { if !m.Contains(key) { m.doSetWithLockCheck(key, f()) @@ -301,11 +301,11 @@ func (m *StrAnyMap) SetIfNotExistFunc(key string, f func() interface{}) bool { return false } -// SetIfNotExistFuncLock sets value with return value of callback function , and then returns true. -// It returns false if exists, and would be ignored. +// SetIfNotExistFuncLock sets value with return value of callback function `f`, and then returns true. +// It returns false if exists, and `value` would be ignored. // // SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that -// it executes function with mutex.Lock of the hash map. +// it executes function `f` with mutex.Lock of the hash map. func (m *StrAnyMap) SetIfNotExistFuncLock(key string, f func() interface{}) bool { if !m.Contains(key) { m.doSetWithLockCheck(key, f) @@ -325,7 +325,7 @@ func (m *StrAnyMap) Removes(keys []string) { m.mu.Unlock() } -// Remove deletes value from map by given , and return this deleted value. +// Remove deletes value from map by given `key`, and return this deleted value. func (m *StrAnyMap) Remove(key string) (value interface{}) { m.mu.Lock() if m.data != nil { @@ -369,7 +369,7 @@ func (m *StrAnyMap) Values() []interface{} { } // Contains checks whether a key exists. -// It returns true if the exists, or else false. +// It returns true if the `key` exists, or else false. func (m *StrAnyMap) Contains(key string) bool { var ok bool m.mu.RLock() @@ -401,21 +401,21 @@ func (m *StrAnyMap) Clear() { m.mu.Unlock() } -// Replace the data of the map with given . +// Replace the data of the map with given `data`. func (m *StrAnyMap) Replace(data map[string]interface{}) { m.mu.Lock() m.data = data m.mu.Unlock() } -// LockFunc locks writing with given callback function within RWMutex.Lock. +// LockFunc locks writing with given callback function `f` within RWMutex.Lock. func (m *StrAnyMap) LockFunc(f func(m map[string]interface{})) { m.mu.Lock() defer m.mu.Unlock() f(m.data) } -// RLockFunc locks reading with given callback function within RWMutex.RLock. +// RLockFunc locks reading with given callback function `f` within RWMutex.RLock. func (m *StrAnyMap) RLockFunc(f func(m map[string]interface{})) { m.mu.RLock() defer m.mu.RUnlock() @@ -434,7 +434,7 @@ func (m *StrAnyMap) Flip() { } // Merge merges two hash maps. -// The map will be merged into the map . +// The map will be merged into the map `m`. func (m *StrAnyMap) Merge(other *StrAnyMap) { m.mu.Lock() defer m.mu.Unlock() @@ -454,7 +454,7 @@ func (m *StrAnyMap) Merge(other *StrAnyMap) { // String returns the map as a string. func (m *StrAnyMap) String() string { b, _ := m.MarshalJSON() - return gconv.UnsafeBytesToStr(b) + return string(b) } // MarshalJSON implements the interface MarshalJSON for json.Marshal. diff --git a/container/gmap/gmap_hash_str_int_map.go b/container/gmap/gmap_hash_str_int_map.go index 7bc03cd34..129694f86 100644 --- a/container/gmap/gmap_hash_str_int_map.go +++ b/container/gmap/gmap_hash_str_int_map.go @@ -21,7 +21,7 @@ type StrIntMap struct { } // NewStrIntMap returns an empty StrIntMap object. -// The parameter is used to specify whether using map in concurrent-safety, +// The parameter `safe` is used to specify whether using map in concurrent-safety, // which is false in default. func NewStrIntMap(safe ...bool) *StrIntMap { return &StrIntMap{ @@ -30,8 +30,8 @@ func NewStrIntMap(safe ...bool) *StrIntMap { } } -// NewStrIntMapFrom creates and returns a hash map from given map . -// Note that, the param map will be set as the underlying data map(no deep copy), +// NewStrIntMapFrom creates and returns a hash map from given map `data`. +// Note that, the param `data` map will be set as the underlying data map(no deep copy), // there might be some concurrent-safe issues when changing the map outside. func NewStrIntMapFrom(data map[string]int, safe ...bool) *StrIntMap { return &StrIntMap{ @@ -40,8 +40,8 @@ func NewStrIntMapFrom(data map[string]int, safe ...bool) *StrIntMap { } } -// Iterator iterates the hash map readonly with custom callback function . -// If returns true, then it continues iterating; or false to stop. +// Iterator iterates the hash map readonly with custom callback function `f`. +// If `f` returns true, then it continues iterating; or false to stop. func (m *StrIntMap) Iterator(f func(k string, v int) bool) { m.mu.RLock() defer m.mu.RUnlock() @@ -130,8 +130,8 @@ func (m *StrIntMap) Sets(data map[string]int) { m.mu.Unlock() } -// Search searches the map with given . -// Second return parameter is true if key was found, otherwise false. +// Search searches the map with given `key`. +// Second return parameter `found` is true if key was found, otherwise false. func (m *StrIntMap) Search(key string) (value int, found bool) { m.mu.RLock() if m.data != nil { @@ -141,7 +141,7 @@ func (m *StrIntMap) Search(key string) (value int, found bool) { return } -// Get returns the value by given . +// Get returns the value by given `key`. func (m *StrIntMap) Get(key string) (value int) { m.mu.RLock() if m.data != nil { @@ -162,7 +162,7 @@ func (m *StrIntMap) Pop() (key string, value int) { return } -// Pops retrieves and deletes items from the map. +// Pops retrieves and deletes `size` items from the map. // It returns all items if size == -1. func (m *StrIntMap) Pops(size int) map[string]int { m.mu.Lock() @@ -189,10 +189,10 @@ func (m *StrIntMap) Pops(size int) map[string]int { } // doSetWithLockCheck checks whether value of the key exists with mutex.Lock, -// if not exists, set value to the map with given , +// if not exists, set value to the map with given `key`, // or else just return the existing value. // -// It returns value with given . +// It returns value with given `key`. func (m *StrIntMap) doSetWithLockCheck(key string, value int) int { m.mu.Lock() if m.data == nil { @@ -208,7 +208,7 @@ func (m *StrIntMap) doSetWithLockCheck(key string, value int) int { } // GetOrSet returns the value by key, -// or sets value with given if it does not exist and then returns this value. +// or sets value with given `value` if it does not exist and then returns this value. func (m *StrIntMap) GetOrSet(key string, value int) int { if v, ok := m.Search(key); !ok { return m.doSetWithLockCheck(key, value) @@ -218,7 +218,7 @@ func (m *StrIntMap) GetOrSet(key string, value int) int { } // GetOrSetFunc returns the value by key, -// or sets value with returned value of callback function if it does not exist +// or sets value with returned value of callback function `f` if it does not exist // and then returns this value. func (m *StrIntMap) GetOrSetFunc(key string, f func() int) int { if v, ok := m.Search(key); !ok { @@ -229,10 +229,10 @@ func (m *StrIntMap) GetOrSetFunc(key string, f func() int) int { } // GetOrSetFuncLock returns the value by key, -// or sets value with returned value of callback function if it does not exist +// or sets value with returned value of callback function `f` if it does not exist // and then returns this value. // -// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function +// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function `f` // with mutex.Lock of the hash map. func (m *StrIntMap) GetOrSetFuncLock(key string, f func() int) int { if v, ok := m.Search(key); !ok { @@ -252,8 +252,8 @@ func (m *StrIntMap) GetOrSetFuncLock(key string, f func() int) int { } } -// SetIfNotExist sets to the map if the does not exist, and then returns true. -// It returns false if exists, and would be ignored. +// SetIfNotExist sets to the map if the `key` does not exist, and then returns true. +// It returns false if exists, and `value` would be ignored. func (m *StrIntMap) SetIfNotExist(key string, value int) bool { if !m.Contains(key) { m.doSetWithLockCheck(key, value) @@ -262,8 +262,8 @@ func (m *StrIntMap) SetIfNotExist(key string, value int) bool { return false } -// SetIfNotExistFunc sets value with return value of callback function , and then returns true. -// It returns false if exists, and would be ignored. +// SetIfNotExistFunc sets value with return value of callback function `f`, and then returns true. +// It returns false if exists, and `value` would be ignored. func (m *StrIntMap) SetIfNotExistFunc(key string, f func() int) bool { if !m.Contains(key) { m.doSetWithLockCheck(key, f()) @@ -272,11 +272,11 @@ func (m *StrIntMap) SetIfNotExistFunc(key string, f func() int) bool { return false } -// SetIfNotExistFuncLock sets value with return value of callback function , and then returns true. -// It returns false if exists, and would be ignored. +// SetIfNotExistFuncLock sets value with return value of callback function `f`, and then returns true. +// It returns false if exists, and `value` would be ignored. // // SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that -// it executes function with mutex.Lock of the hash map. +// it executes function `f` with mutex.Lock of the hash map. func (m *StrIntMap) SetIfNotExistFuncLock(key string, f func() int) bool { if !m.Contains(key) { m.mu.Lock() @@ -303,7 +303,7 @@ func (m *StrIntMap) Removes(keys []string) { m.mu.Unlock() } -// Remove deletes value from map by given , and return this deleted value. +// Remove deletes value from map by given `key`, and return this deleted value. func (m *StrIntMap) Remove(key string) (value int) { m.mu.Lock() if m.data != nil { @@ -347,7 +347,7 @@ func (m *StrIntMap) Values() []int { } // Contains checks whether a key exists. -// It returns true if the exists, or else false. +// It returns true if the `key` exists, or else false. func (m *StrIntMap) Contains(key string) bool { var ok bool m.mu.RLock() @@ -379,21 +379,21 @@ func (m *StrIntMap) Clear() { m.mu.Unlock() } -// Replace the data of the map with given . +// Replace the data of the map with given `data`. func (m *StrIntMap) Replace(data map[string]int) { m.mu.Lock() m.data = data m.mu.Unlock() } -// LockFunc locks writing with given callback function within RWMutex.Lock. +// LockFunc locks writing with given callback function `f` within RWMutex.Lock. func (m *StrIntMap) LockFunc(f func(m map[string]int)) { m.mu.Lock() defer m.mu.Unlock() f(m.data) } -// RLockFunc locks reading with given callback function within RWMutex.RLock. +// RLockFunc locks reading with given callback function `f` within RWMutex.RLock. func (m *StrIntMap) RLockFunc(f func(m map[string]int)) { m.mu.RLock() defer m.mu.RUnlock() @@ -412,7 +412,7 @@ func (m *StrIntMap) Flip() { } // Merge merges two hash maps. -// The map will be merged into the map . +// The map will be merged into the map `m`. func (m *StrIntMap) Merge(other *StrIntMap) { m.mu.Lock() defer m.mu.Unlock() @@ -432,7 +432,7 @@ func (m *StrIntMap) Merge(other *StrIntMap) { // String returns the map as a string. func (m *StrIntMap) String() string { b, _ := m.MarshalJSON() - return gconv.UnsafeBytesToStr(b) + return string(b) } // MarshalJSON implements the interface MarshalJSON for json.Marshal. diff --git a/container/gmap/gmap_hash_str_str_map.go b/container/gmap/gmap_hash_str_str_map.go index ae68640c8..ce90c7820 100644 --- a/container/gmap/gmap_hash_str_str_map.go +++ b/container/gmap/gmap_hash_str_str_map.go @@ -22,7 +22,7 @@ type StrStrMap struct { } // NewStrStrMap returns an empty StrStrMap object. -// The parameter is used to specify whether using map in concurrent-safety, +// The parameter `safe` is used to specify whether using map in concurrent-safety, // which is false in default. func NewStrStrMap(safe ...bool) *StrStrMap { return &StrStrMap{ @@ -31,8 +31,8 @@ func NewStrStrMap(safe ...bool) *StrStrMap { } } -// NewStrStrMapFrom creates and returns a hash map from given map . -// Note that, the param map will be set as the underlying data map(no deep copy), +// NewStrStrMapFrom creates and returns a hash map from given map `data`. +// Note that, the param `data` map will be set as the underlying data map(no deep copy), // there might be some concurrent-safe issues when changing the map outside. func NewStrStrMapFrom(data map[string]string, safe ...bool) *StrStrMap { return &StrStrMap{ @@ -41,8 +41,8 @@ func NewStrStrMapFrom(data map[string]string, safe ...bool) *StrStrMap { } } -// Iterator iterates the hash map readonly with custom callback function . -// If returns true, then it continues iterating; or false to stop. +// Iterator iterates the hash map readonly with custom callback function `f`. +// If `f` returns true, then it continues iterating; or false to stop. func (m *StrStrMap) Iterator(f func(k string, v string) bool) { m.mu.RLock() defer m.mu.RUnlock() @@ -131,8 +131,8 @@ func (m *StrStrMap) Sets(data map[string]string) { m.mu.Unlock() } -// Search searches the map with given . -// Second return parameter is true if key was found, otherwise false. +// Search searches the map with given `key`. +// Second return parameter `found` is true if key was found, otherwise false. func (m *StrStrMap) Search(key string) (value string, found bool) { m.mu.RLock() if m.data != nil { @@ -142,7 +142,7 @@ func (m *StrStrMap) Search(key string) (value string, found bool) { return } -// Get returns the value by given . +// Get returns the value by given `key`. func (m *StrStrMap) Get(key string) (value string) { m.mu.RLock() if m.data != nil { @@ -163,7 +163,7 @@ func (m *StrStrMap) Pop() (key, value string) { return } -// Pops retrieves and deletes items from the map. +// Pops retrieves and deletes `size` items from the map. // It returns all items if size == -1. func (m *StrStrMap) Pops(size int) map[string]string { m.mu.Lock() @@ -190,10 +190,10 @@ func (m *StrStrMap) Pops(size int) map[string]string { } // doSetWithLockCheck checks whether value of the key exists with mutex.Lock, -// if not exists, set value to the map with given , +// if not exists, set value to the map with given `key`, // or else just return the existing value. // -// It returns value with given . +// It returns value with given `key`. func (m *StrStrMap) doSetWithLockCheck(key string, value string) string { m.mu.Lock() defer m.mu.Unlock() @@ -208,7 +208,7 @@ func (m *StrStrMap) doSetWithLockCheck(key string, value string) string { } // GetOrSet returns the value by key, -// or sets value with given if it does not exist and then returns this value. +// or sets value with given `value` if it does not exist and then returns this value. func (m *StrStrMap) GetOrSet(key string, value string) string { if v, ok := m.Search(key); !ok { return m.doSetWithLockCheck(key, value) @@ -218,7 +218,7 @@ func (m *StrStrMap) GetOrSet(key string, value string) string { } // GetOrSetFunc returns the value by key, -// or sets value with returned value of callback function if it does not exist +// or sets value with returned value of callback function `f` if it does not exist // and then returns this value. func (m *StrStrMap) GetOrSetFunc(key string, f func() string) string { if v, ok := m.Search(key); !ok { @@ -229,10 +229,10 @@ func (m *StrStrMap) GetOrSetFunc(key string, f func() string) string { } // GetOrSetFuncLock returns the value by key, -// or sets value with returned value of callback function if it does not exist +// or sets value with returned value of callback function `f` if it does not exist // and then returns this value. // -// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function +// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function `f` // with mutex.Lock of the hash map. func (m *StrStrMap) GetOrSetFuncLock(key string, f func() string) string { if v, ok := m.Search(key); !ok { @@ -252,8 +252,8 @@ func (m *StrStrMap) GetOrSetFuncLock(key string, f func() string) string { } } -// SetIfNotExist sets to the map if the does not exist, and then returns true. -// It returns false if exists, and would be ignored. +// SetIfNotExist sets to the map if the `key` does not exist, and then returns true. +// It returns false if exists, and `value` would be ignored. func (m *StrStrMap) SetIfNotExist(key string, value string) bool { if !m.Contains(key) { m.doSetWithLockCheck(key, value) @@ -262,8 +262,8 @@ func (m *StrStrMap) SetIfNotExist(key string, value string) bool { return false } -// SetIfNotExistFunc sets value with return value of callback function , and then returns true. -// It returns false if exists, and would be ignored. +// SetIfNotExistFunc sets value with return value of callback function `f`, and then returns true. +// It returns false if exists, and `value` would be ignored. func (m *StrStrMap) SetIfNotExistFunc(key string, f func() string) bool { if !m.Contains(key) { m.doSetWithLockCheck(key, f()) @@ -272,11 +272,11 @@ func (m *StrStrMap) SetIfNotExistFunc(key string, f func() string) bool { return false } -// SetIfNotExistFuncLock sets value with return value of callback function , and then returns true. -// It returns false if exists, and would be ignored. +// SetIfNotExistFuncLock sets value with return value of callback function `f`, and then returns true. +// It returns false if exists, and `value` would be ignored. // // SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that -// it executes function with mutex.Lock of the hash map. +// it executes function `f` with mutex.Lock of the hash map. func (m *StrStrMap) SetIfNotExistFuncLock(key string, f func() string) bool { if !m.Contains(key) { m.mu.Lock() @@ -303,7 +303,7 @@ func (m *StrStrMap) Removes(keys []string) { m.mu.Unlock() } -// Remove deletes value from map by given , and return this deleted value. +// Remove deletes value from map by given `key`, and return this deleted value. func (m *StrStrMap) Remove(key string) (value string) { m.mu.Lock() if m.data != nil { @@ -347,7 +347,7 @@ func (m *StrStrMap) Values() []string { } // Contains checks whether a key exists. -// It returns true if the exists, or else false. +// It returns true if the `key` exists, or else false. func (m *StrStrMap) Contains(key string) bool { var ok bool m.mu.RLock() @@ -379,21 +379,21 @@ func (m *StrStrMap) Clear() { m.mu.Unlock() } -// Replace the data of the map with given . +// Replace the data of the map with given `data`. func (m *StrStrMap) Replace(data map[string]string) { m.mu.Lock() m.data = data m.mu.Unlock() } -// LockFunc locks writing with given callback function within RWMutex.Lock. +// LockFunc locks writing with given callback function `f` within RWMutex.Lock. func (m *StrStrMap) LockFunc(f func(m map[string]string)) { m.mu.Lock() defer m.mu.Unlock() f(m.data) } -// RLockFunc locks reading with given callback function within RWMutex.RLock. +// RLockFunc locks reading with given callback function `f` within RWMutex.RLock. func (m *StrStrMap) RLockFunc(f func(m map[string]string)) { m.mu.RLock() defer m.mu.RUnlock() @@ -412,7 +412,7 @@ func (m *StrStrMap) Flip() { } // Merge merges two hash maps. -// The map will be merged into the map . +// The map will be merged into the map `m`. func (m *StrStrMap) Merge(other *StrStrMap) { m.mu.Lock() defer m.mu.Unlock() @@ -432,7 +432,7 @@ func (m *StrStrMap) Merge(other *StrStrMap) { // String returns the map as a string. func (m *StrStrMap) String() string { b, _ := m.MarshalJSON() - return gconv.UnsafeBytesToStr(b) + return string(b) } // MarshalJSON implements the interface MarshalJSON for json.Marshal. diff --git a/container/gmap/gmap_list_map.go b/container/gmap/gmap_list_map.go index 790998da7..5ca38d3f8 100644 --- a/container/gmap/gmap_list_map.go +++ b/container/gmap/gmap_list_map.go @@ -31,7 +31,7 @@ type gListMapNode struct { // NewListMap returns an empty link map. // ListMap is backed by a hash table to store values and doubly-linked list to store ordering. -// The parameter is used to specify whether using map in concurrent-safety, +// The parameter `safe` is used to specify whether using map in concurrent-safety, // which is false in default. func NewListMap(safe ...bool) *ListMap { return &ListMap{ @@ -41,8 +41,8 @@ func NewListMap(safe ...bool) *ListMap { } } -// NewListMapFrom returns a link map from given map . -// Note that, the param map will be set as the underlying data map(no deep copy), +// NewListMapFrom returns a link map from given map `data`. +// Note that, the param `data` map will be set as the underlying data map(no deep copy), // there might be some concurrent-safe issues when changing the map outside. func NewListMapFrom(data map[interface{}]interface{}, safe ...bool) *ListMap { m := NewListMap(safe...) @@ -55,8 +55,8 @@ func (m *ListMap) Iterator(f func(key, value interface{}) bool) { m.IteratorAsc(f) } -// IteratorAsc iterates the map readonly in ascending order with given callback function . -// If returns true, then it continues iterating; or false to stop. +// IteratorAsc iterates the map readonly in ascending order with given callback function `f`. +// If `f` returns true, then it continues iterating; or false to stop. func (m *ListMap) IteratorAsc(f func(key interface{}, value interface{}) bool) { m.mu.RLock() defer m.mu.RUnlock() @@ -69,8 +69,8 @@ func (m *ListMap) IteratorAsc(f func(key interface{}, value interface{}) bool) { } } -// IteratorDesc iterates the map readonly in descending order with given callback function . -// If returns true, then it continues iterating; or false to stop. +// IteratorDesc iterates the map readonly in descending order with given callback function `f`. +// If `f` returns true, then it continues iterating; or false to stop. func (m *ListMap) IteratorDesc(f func(key interface{}, value interface{}) bool) { m.mu.RLock() defer m.mu.RUnlock() @@ -96,7 +96,7 @@ func (m *ListMap) Clear() { m.mu.Unlock() } -// Replace the data of the map with given . +// Replace the data of the map with given `data`. func (m *ListMap) Replace(data map[interface{}]interface{}) { m.mu.Lock() m.data = make(map[interface{}]*glist.Element) @@ -202,8 +202,8 @@ func (m *ListMap) Sets(data map[interface{}]interface{}) { m.mu.Unlock() } -// Search searches the map with given . -// Second return parameter is true if key was found, otherwise false. +// Search searches the map with given `key`. +// Second return parameter `found` is true if key was found, otherwise false. func (m *ListMap) Search(key interface{}) (value interface{}, found bool) { m.mu.RLock() if m.data != nil { @@ -216,7 +216,7 @@ func (m *ListMap) Search(key interface{}) (value interface{}, found bool) { return } -// Get returns the value by given . +// Get returns the value by given `key`. func (m *ListMap) Get(key interface{}) (value interface{}) { m.mu.RLock() if m.data != nil { @@ -241,7 +241,7 @@ func (m *ListMap) Pop() (key, value interface{}) { return } -// Pops retrieves and deletes items from the map. +// Pops retrieves and deletes `size` items from the map. // It returns all items if size == -1. func (m *ListMap) Pops(size int) map[interface{}]interface{} { m.mu.Lock() @@ -268,14 +268,14 @@ func (m *ListMap) Pops(size int) map[interface{}]interface{} { } // doSetWithLockCheck checks whether value of the key exists with mutex.Lock, -// if not exists, set value to the map with given , +// if not exists, set value to the map with given `key`, // or else just return the existing value. // -// When setting value, if is type of , +// When setting value, if `value` is type of , // it will be executed with mutex.Lock of the map, -// and its return value will be set to the map with . +// and its return value will be set to the map with `key`. // -// It returns value with given . +// It returns value with given `key`. func (m *ListMap) doSetWithLockCheck(key interface{}, value interface{}) interface{} { m.mu.Lock() defer m.mu.Unlock() @@ -296,7 +296,7 @@ func (m *ListMap) doSetWithLockCheck(key interface{}, value interface{}) interfa } // GetOrSet returns the value by key, -// or sets value with given if it does not exist and then returns this value. +// or sets value with given `value` if it does not exist and then returns this value. func (m *ListMap) GetOrSet(key interface{}, value interface{}) interface{} { if v, ok := m.Search(key); !ok { return m.doSetWithLockCheck(key, value) @@ -306,7 +306,7 @@ func (m *ListMap) GetOrSet(key interface{}, value interface{}) interface{} { } // GetOrSetFunc returns the value by key, -// or sets value with returned value of callback function if it does not exist +// or sets value with returned value of callback function `f` if it does not exist // and then returns this value. func (m *ListMap) GetOrSetFunc(key interface{}, f func() interface{}) interface{} { if v, ok := m.Search(key); !ok { @@ -317,10 +317,10 @@ func (m *ListMap) GetOrSetFunc(key interface{}, f func() interface{}) interface{ } // GetOrSetFuncLock returns the value by key, -// or sets value with returned value of callback function if it does not exist +// or sets value with returned value of callback function `f` if it does not exist // and then returns this value. // -// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function +// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function `f` // with mutex.Lock of the map. func (m *ListMap) GetOrSetFuncLock(key interface{}, f func() interface{}) interface{} { if v, ok := m.Search(key); !ok { @@ -330,7 +330,7 @@ func (m *ListMap) GetOrSetFuncLock(key interface{}, f func() interface{}) interf } } -// GetVar returns a Var with the value by given . +// GetVar returns a Var with the value by given `key`. // The returned Var is un-concurrent safe. func (m *ListMap) GetVar(key interface{}) *gvar.Var { return gvar.New(m.Get(key)) @@ -354,8 +354,8 @@ func (m *ListMap) GetVarOrSetFuncLock(key interface{}, f func() interface{}) *gv return gvar.New(m.GetOrSetFuncLock(key, f)) } -// SetIfNotExist sets to the map if the does not exist, and then returns true. -// It returns false if exists, and would be ignored. +// SetIfNotExist sets to the map if the `key` does not exist, and then returns true. +// It returns false if exists, and `value` would be ignored. func (m *ListMap) SetIfNotExist(key interface{}, value interface{}) bool { if !m.Contains(key) { m.doSetWithLockCheck(key, value) @@ -364,8 +364,8 @@ func (m *ListMap) SetIfNotExist(key interface{}, value interface{}) bool { return false } -// SetIfNotExistFunc sets value with return value of callback function , and then returns true. -// It returns false if exists, and would be ignored. +// SetIfNotExistFunc sets value with return value of callback function `f`, and then returns true. +// It returns false if exists, and `value` would be ignored. func (m *ListMap) SetIfNotExistFunc(key interface{}, f func() interface{}) bool { if !m.Contains(key) { m.doSetWithLockCheck(key, f()) @@ -374,11 +374,11 @@ func (m *ListMap) SetIfNotExistFunc(key interface{}, f func() interface{}) bool return false } -// SetIfNotExistFuncLock sets value with return value of callback function , and then returns true. -// It returns false if exists, and would be ignored. +// SetIfNotExistFuncLock sets value with return value of callback function `f`, and then returns true. +// It returns false if exists, and `value` would be ignored. // // SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that -// it executes function with mutex.Lock of the map. +// it executes function `f` with mutex.Lock of the map. func (m *ListMap) SetIfNotExistFuncLock(key interface{}, f func() interface{}) bool { if !m.Contains(key) { m.doSetWithLockCheck(key, f) @@ -387,7 +387,7 @@ func (m *ListMap) SetIfNotExistFuncLock(key interface{}, f func() interface{}) b return false } -// Remove deletes value from map by given , and return this deleted value. +// Remove deletes value from map by given `key`, and return this deleted value. func (m *ListMap) Remove(key interface{}) (value interface{}) { m.mu.Lock() if m.data != nil { @@ -452,7 +452,7 @@ func (m *ListMap) Values() []interface{} { } // Contains checks whether a key exists. -// It returns true if the exists, or else false. +// It returns true if the `key` exists, or else false. func (m *ListMap) Contains(key interface{}) (ok bool) { m.mu.RLock() if m.data != nil { @@ -486,7 +486,7 @@ func (m *ListMap) Flip() { } // Merge merges two link maps. -// The map will be merged into the map . +// The map will be merged into the map `m`. func (m *ListMap) Merge(other *ListMap) { m.mu.Lock() defer m.mu.Unlock() @@ -513,7 +513,7 @@ func (m *ListMap) Merge(other *ListMap) { // String returns the map as a string. func (m *ListMap) String() string { b, _ := m.MarshalJSON() - return gconv.UnsafeBytesToStr(b) + return string(b) } // MarshalJSON implements the interface MarshalJSON for json.Marshal. diff --git a/container/gmap/gmap_tree_map.go b/container/gmap/gmap_tree_map.go index 1b9f02783..694fc10d7 100644 --- a/container/gmap/gmap_tree_map.go +++ b/container/gmap/gmap_tree_map.go @@ -14,16 +14,16 @@ import ( type TreeMap = gtree.RedBlackTree // NewTreeMap instantiates a tree map with the custom comparator. -// The parameter is used to specify whether using tree in concurrent-safety, +// The parameter `safe` is used to specify whether using tree in concurrent-safety, // which is false in default. func NewTreeMap(comparator func(v1, v2 interface{}) int, safe ...bool) *TreeMap { return gtree.NewRedBlackTree(comparator, safe...) } -// NewTreeMapFrom instantiates a tree map with the custom comparator and map. -// Note that, the param map will be set as the underlying data map(no deep copy), +// NewTreeMapFrom instantiates a tree map with the custom comparator and `data` map. +// Note that, the param `data` map will be set as the underlying data map(no deep copy), // there might be some concurrent-safe issues when changing the map outside. -// The parameter is used to specify whether using tree in concurrent-safety, +// The parameter `safe` is used to specify whether using tree in concurrent-safety, // which is false in default. func NewTreeMapFrom(comparator func(v1, v2 interface{}) int, data map[interface{}]interface{}, safe ...bool) *TreeMap { return gtree.NewRedBlackTreeFrom(comparator, data, safe...) diff --git a/container/gpool/gpool.go b/container/gpool/gpool.go index 4b7e5e583..0c32deb15 100644 --- a/container/gpool/gpool.go +++ b/container/gpool/gpool.go @@ -126,7 +126,7 @@ func (p *Pool) Size() int { return p.list.Len() } -// Close closes the pool. If

has ExpireFunc, +// Close closes the pool. If `p` has ExpireFunc, // then it automatically closes all items using this function before it's closed. // Commonly you do not need call this function manually. func (p *Pool) Close() { diff --git a/container/gqueue/gqueue.go b/container/gqueue/gqueue.go index b8a2dfbaa..bb7affe72 100644 --- a/container/gqueue/gqueue.go +++ b/container/gqueue/gqueue.go @@ -40,8 +40,8 @@ const ( ) // New returns an empty queue object. -// Optional parameter is used to limit the size of the queue, which is unlimited in default. -// When is given, the queue will be static and high performance which is comparable with stdlib channel. +// Optional parameter `limit` is used to limit the size of the queue, which is unlimited in default. +// When `limit` is given, the queue will be static and high performance which is comparable with stdlib channel. func New(limit ...int) *Queue { q := &Queue{ closed: gtype.NewBool(), @@ -87,12 +87,12 @@ func (q *Queue) asyncLoopFromListToChannel() { <-q.events } } - // It should be here to close q.C if is unlimited size. + // It should be here to close q.C if `q` is unlimited size. // It's the sender's responsibility to close channel when it should be closed. close(q.C) } -// Push pushes the data into the queue. +// Push pushes the data `v` into the queue. // Note that it would panics if Push is called after the queue is closed. func (q *Queue) Push(v interface{}) { if q.limit > 0 { diff --git a/container/gring/gring.go b/container/gring/gring.go index ac308f56c..464f99f65 100644 --- a/container/gring/gring.go +++ b/container/gring/gring.go @@ -23,8 +23,13 @@ type Ring struct { dirty *gtype.Bool // Dirty, which means the len and cap should be recalculated. It's marked dirty when the size of ring changes. } -// New creates and returns a Ring structure of elements. -// The optional parameter specifies whether using this structure in concurrent safety, +// internalRingItem stores the ring element value. +type internalRingItem struct { + Value interface{} +} + +// New creates and returns a Ring structure of `cap` elements. +// The optional parameter `safe` specifies whether using this structure in concurrent safety, // which is false in default. func New(cap int, safe ...bool) *Ring { return &Ring{ @@ -38,10 +43,13 @@ func New(cap int, safe ...bool) *Ring { // Val returns the item's value of current position. func (r *Ring) Val() interface{} { + var value interface{} r.mu.RLock() - v := r.ring.Value + if r.ring.Value != nil { + value = r.ring.Value.(internalRingItem).Value + } r.mu.RUnlock() - return v + return value } // Len returns the size of ring. @@ -61,17 +69,21 @@ func (r *Ring) checkAndUpdateLenAndCap() { if !r.dirty.Val() { return } + r.mu.RLock() + defer r.mu.RUnlock() totalLen := 0 emptyLen := 0 if r.ring != nil { - r.mu.RLock() + if r.ring.Value == nil { + emptyLen++ + } + totalLen++ for p := r.ring.Next(); p != r.ring; p = p.Next() { if p.Value == nil { emptyLen++ } totalLen++ } - r.mu.RUnlock() } r.cap.Set(totalLen) r.len.Set(totalLen - emptyLen) @@ -84,18 +96,18 @@ func (r *Ring) Set(value interface{}) *Ring { if r.ring.Value == nil { r.len.Add(1) } - r.ring.Value = value + r.ring.Value = internalRingItem{Value: value} r.mu.Unlock() return r } -// Put sets to current item of ring and moves position to next item. +// Put sets `value` to current item of ring and moves position to next item. func (r *Ring) Put(value interface{}) *Ring { r.mu.Lock() if r.ring.Value == nil { r.len.Add(1) } - r.ring.Value = value + r.ring.Value = internalRingItem{Value: value} r.ring = r.ring.Next() r.mu.Unlock() return r @@ -132,8 +144,8 @@ func (r *Ring) Next() *Ring { // // If r and s point to the same ring, linking // them removes the elements between r and s from the ring. -// The removed elements form a subring and the result is a -// reference to that subring (if no elements were removed, +// The removed elements form a sub-ring and the result is a +// reference to that sub-ring (if no elements were removed, // the result is still the original value for r.Next(), // and not nil). // @@ -155,7 +167,7 @@ func (r *Ring) Link(s *Ring) *Ring { // Unlink removes n % r.Len() elements from the ring r, starting // at r.Next(). If n % r.Len() == 0, r remains unchanged. -// The result is the removed subring. r must not be empty. +// The result is the removed sub-ring. r must not be empty. // func (r *Ring) Unlink(n int) *Ring { r.mu.Lock() @@ -166,56 +178,24 @@ func (r *Ring) Unlink(n int) *Ring { } // RLockIteratorNext iterates and locks reading forward -// with given callback function within RWMutex.RLock. -// If returns true, then it continues iterating; or false to stop. +// with given callback function `f` within RWMutex.RLock. +// If `f` returns true, then it continues iterating; or false to stop. func (r *Ring) RLockIteratorNext(f func(value interface{}) bool) { r.mu.RLock() defer r.mu.RUnlock() - if !f(r.ring.Value) { + if r.ring.Value != nil && !f(r.ring.Value.(internalRingItem).Value) { return } for p := r.ring.Next(); p != r.ring; p = p.Next() { - if !f(p.Value) { - break - } - } -} - -// RLockIteratorPrev iterates and locks reading backward -// with given callback function within RWMutex.RLock. -// If returns true, then it continues iterating; or false to stop. -func (r *Ring) RLockIteratorPrev(f func(value interface{}) bool) { - r.mu.RLock() - defer r.mu.RUnlock() - if !f(r.ring.Value) { - return - } - for p := r.ring.Prev(); p != r.ring; p = p.Prev() { - if !f(p.Value) { - break - } - } -} - -// LockIteratorNext iterates and locks writing forward -// with given callback function within RWMutex.RLock. -// If returns true, then it continues iterating; or false to stop. -func (r *Ring) LockIteratorNext(f func(item *ring.Ring) bool) { - r.mu.RLock() - defer r.mu.RUnlock() - if !f(r.ring) { - return - } - for p := r.ring.Next(); p != r.ring; p = p.Next() { - if !f(p) { + if p.Value == nil || !f(p.Value.(internalRingItem).Value) { break } } } // LockIteratorPrev iterates and locks writing backward -// with given callback function within RWMutex.RLock. -// If returns true, then it continues iterating; or false to stop. +// with given callback function `f` within RWMutex.RLock. +// If `f` returns true, then it continues iterating; or false to stop. func (r *Ring) LockIteratorPrev(f func(item *ring.Ring) bool) { r.mu.RLock() defer r.mu.RUnlock() @@ -234,12 +214,13 @@ func (r *Ring) SliceNext() []interface{} { s := make([]interface{}, 0) r.mu.RLock() if r.ring.Value != nil { - s = append(s, r.ring.Value) + s = append(s, r.ring.Value.(internalRingItem).Value) } for p := r.ring.Next(); p != r.ring; p = p.Next() { - if p.Value != nil { - s = append(s, p.Value) + if p.Value == nil { + break } + s = append(s, p.Value.(internalRingItem).Value) } r.mu.RUnlock() return s @@ -250,12 +231,13 @@ func (r *Ring) SlicePrev() []interface{} { s := make([]interface{}, 0) r.mu.RLock() if r.ring.Value != nil { - s = append(s, r.ring.Value) + s = append(s, r.ring.Value.(internalRingItem).Value) } for p := r.ring.Prev(); p != r.ring; p = p.Prev() { - if p.Value != nil { - s = append(s, p.Value) + if p.Value == nil { + break } + s = append(s, p.Value.(internalRingItem).Value) } r.mu.RUnlock() return s diff --git a/container/gring/gring_unit_test.go b/container/gring/gring_unit_test.go index 706f273a3..a226b10d2 100644 --- a/container/gring/gring_unit_test.go +++ b/container/gring/gring_unit_test.go @@ -7,7 +7,6 @@ package gring_test import ( - "container/ring" "testing" "github.com/gogf/gf/container/gring" @@ -44,6 +43,11 @@ func TestRing_Val(t *testing.T) { }) } func TestRing_CapLen(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + r := gring.New(10) + t.Assert(r.Cap(), 10) + t.Assert(r.Len(), 0) + }) gtest.C(t, func(t *gtest.T) { r := gring.New(10) r.Put("goframe") @@ -81,22 +85,22 @@ func TestRing_Link(t *testing.T) { rs := r.Link(s) t.Assert(rs.Move(2).Val(), "b") - }) } func TestRing_Unlink(t *testing.T) { gtest.C(t, func(t *gtest.T) { r := gring.New(5) - for i := 0; i < 5; i++ { - r.Put(i + 1) + for i := 1; i <= 5; i++ { + r.Put(i) } + t.Assert(r.Val(), 1) // 1 2 3 4 // 删除当前位置往后的2个数据,返回被删除的数据 // 重新计算s len s := r.Unlink(2) // 2 3 t.Assert(s.Val(), 2) - t.Assert(s.Len(), 1) + t.Assert(s.Len(), 2) }) } @@ -120,10 +124,10 @@ func TestRing_Slice(t *testing.T) { r.Set(nil) array2 := r.SliceNext() //[4 5 1 2] //返回当前位置往后不为空的元素数组,长度为4 - t.Assert(array2, g.Slice{4, 5, 1, 2}) + t.Assert(array2, g.Slice{nil, 4, 5, 1, 2}) array3 := r.SlicePrev() //[2 1 5 4] - t.Assert(array3, g.Slice{2, 1, 5, 4}) + t.Assert(array3, g.Slice{nil, 2, 1, 5, 4}) s := gring.New(ringLen) for i := 0; i < ringLen; i++ { @@ -131,106 +135,5 @@ func TestRing_Slice(t *testing.T) { } array4 := s.SlicePrev() // [] t.Assert(array4, g.Slice{1, 5, 4, 3, 2}) - - }) -} - -func TestRing_RLockIterator(t *testing.T) { - gtest.C(t, func(t *gtest.T) { - ringLen := 5 - r := gring.New(ringLen) - - //ring不存在有值元素 - r.RLockIteratorNext(func(v interface{}) bool { - t.Assert(v, nil) - return false - }) - r.RLockIteratorNext(func(v interface{}) bool { - t.Assert(v, nil) - return true - }) - - r.RLockIteratorPrev(func(v interface{}) bool { - t.Assert(v, nil) - return true - }) - - for i := 0; i < ringLen; i++ { - r.Put(i + 1) - } - - //回调函数返回true,RLockIteratorNext遍历5次,期望值分别是1、2、3、4、5 - i := 0 - r.RLockIteratorNext(func(v interface{}) bool { - t.Assert(v, i+1) - i++ - return true - }) - - //RLockIteratorPrev遍历1次返回 false,退出遍历 - r.RLockIteratorPrev(func(v interface{}) bool { - t.Assert(v, 1) - return false - }) - - }) -} - -func TestRing_LockIterator(t *testing.T) { - gtest.C(t, func(t *gtest.T) { - ringLen := 5 - r := gring.New(ringLen) - - //不存在有值元素 - r.LockIteratorNext(func(item *ring.Ring) bool { - t.Assert(item.Value, nil) - return false - }) - r.LockIteratorNext(func(item *ring.Ring) bool { - t.Assert(item.Value, nil) - return false - }) - r.LockIteratorNext(func(item *ring.Ring) bool { - t.Assert(item.Value, nil) - return true - }) - - r.LockIteratorPrev(func(item *ring.Ring) bool { - t.Assert(item.Value, nil) - return false - }) - r.LockIteratorPrev(func(item *ring.Ring) bool { - t.Assert(item.Value, nil) - return true - }) - - //ring初始化元素值 - for i := 0; i < ringLen; i++ { - r.Put(i + 1) - } - - //往后遍历组成数据 [1,2,3,4,5] - array1 := g.Slice{1, 2, 3, 4, 5} - ii := 0 - r.LockIteratorNext(func(item *ring.Ring) bool { - //校验每一次遍历取值是否是期望值 - t.Assert(item.Value, array1[ii]) - ii++ - return true - }) - - //往后取3个元素组成数组 - //获得 [1,5,4] - i := 0 - a := g.Slice{1, 5, 4} - r.LockIteratorPrev(func(item *ring.Ring) bool { - if i > 2 { - return false - } - t.Assert(item.Value, a[i]) - i++ - return true - }) - }) } diff --git a/container/gset/gset_any_set.go b/container/gset/gset_any_set.go index 9db79a47a..8e222a8cc 100644 --- a/container/gset/gset_any_set.go +++ b/container/gset/gset_any_set.go @@ -21,7 +21,7 @@ type Set struct { } // New create and returns a new set, which contains un-repeated items. -// The parameter is used to specify whether using set in concurrent-safety, +// The parameter `safe` is used to specify whether using set in concurrent-safety, // which is false in default. func New(safe ...bool) *Set { return NewSet(safe...) @@ -35,8 +35,8 @@ func NewSet(safe ...bool) *Set { } } -// NewFrom returns a new set from . -// Parameter can be either a variable of any type, or a slice. +// NewFrom returns a new set from `items`. +// Parameter `items` can be either a variable of any type, or a slice. func NewFrom(items interface{}, safe ...bool) *Set { m := make(map[interface{}]struct{}) for _, v := range gconv.Interfaces(items) { @@ -48,8 +48,8 @@ func NewFrom(items interface{}, safe ...bool) *Set { } } -// Iterator iterates the set readonly with given callback function , -// if returns true then continue iterating; or false to stop. +// Iterator iterates the set readonly with given callback function `f`, +// if `f` returns true then continue iterating; or false to stop. func (set *Set) Iterator(f func(v interface{}) bool) { set.mu.RLock() defer set.mu.RUnlock() @@ -76,7 +76,7 @@ func (set *Set) Add(items ...interface{}) { // it adds the item to set and returns true if it does not exists in the set, // or else it does nothing and returns false. // -// Note that, if is nil, it does nothing and returns false. +// Note that, if `item` is nil, it does nothing and returns false. func (set *Set) AddIfNotExist(item interface{}) bool { if item == nil { return false @@ -97,9 +97,9 @@ func (set *Set) AddIfNotExist(item interface{}) bool { // AddIfNotExistFunc checks whether item exists in the set, // it adds the item to set and returns true if it does not exists in the set and -// function returns true, or else it does nothing and returns false. +// function `f` returns true, or else it does nothing and returns false. // -// Note that, if is nil, it does nothing and returns false. The function +// Note that, if is nil, it does nothing and returns false. The function `f` // is executed without writing lock. func (set *Set) AddIfNotExistFunc(item interface{}, f func() bool) bool { if item == nil { @@ -123,9 +123,9 @@ func (set *Set) AddIfNotExistFunc(item interface{}, f func() bool) bool { // AddIfNotExistFunc checks whether item exists in the set, // it adds the item to set and returns true if it does not exists in the set and -// function returns true, or else it does nothing and returns false. +// function `f` returns true, or else it does nothing and returns false. // -// Note that, if is nil, it does nothing and returns false. The function +// Note that, if is nil, it does nothing and returns false. The function `f` // is executed within writing lock. func (set *Set) AddIfNotExistFuncLock(item interface{}, f func() bool) bool { if item == nil { @@ -147,7 +147,7 @@ func (set *Set) AddIfNotExistFuncLock(item interface{}, f func() bool) bool { return false } -// Contains checks whether the set contains . +// Contains checks whether the set contains `item`. func (set *Set) Contains(item interface{}) bool { var ok bool set.mu.RLock() @@ -158,7 +158,7 @@ func (set *Set) Contains(item interface{}) bool { return ok } -// Remove deletes from set. +// Remove deletes `item` from set. func (set *Set) Remove(item interface{}) { set.mu.Lock() if set.data != nil { @@ -197,7 +197,7 @@ func (set *Set) Slice() []interface{} { return ret } -// Join joins items with a string . +// Join joins items with a string `glue`. func (set *Set) Join(glue string) string { set.mu.RLock() defer set.mu.RUnlock() @@ -246,14 +246,14 @@ func (set *Set) String() string { return buffer.String() } -// LockFunc locks writing with callback function . +// LockFunc locks writing with callback function `f`. func (set *Set) LockFunc(f func(m map[interface{}]struct{})) { set.mu.Lock() defer set.mu.Unlock() f(set.data) } -// RLockFunc locks reading with callback function . +// RLockFunc locks reading with callback function `f`. func (set *Set) RLockFunc(f func(m map[interface{}]struct{})) { set.mu.RLock() defer set.mu.RUnlock() @@ -280,7 +280,7 @@ func (set *Set) Equal(other *Set) bool { return true } -// IsSubsetOf checks whether the current set is a sub-set of . +// IsSubsetOf checks whether the current set is a sub-set of `other`. func (set *Set) IsSubsetOf(other *Set) bool { if set == other { return true @@ -297,8 +297,8 @@ func (set *Set) IsSubsetOf(other *Set) bool { return true } -// Union returns a new set which is the union of and . -// Which means, all the items in are in or in . +// Union returns a new set which is the union of and `others`. +// Which means, all the items in are in or in `others`. func (set *Set) Union(others ...*Set) (newSet *Set) { newSet = NewSet() set.mu.RLock() @@ -323,8 +323,8 @@ func (set *Set) Union(others ...*Set) (newSet *Set) { return } -// Diff returns a new set which is the difference set from to . -// Which means, all the items in are in but not in . +// Diff returns a new set which is the difference set from to `others`. +// Which means, all the items in are in but not in `others`. func (set *Set) Diff(others ...*Set) (newSet *Set) { newSet = NewSet() set.mu.RLock() @@ -344,8 +344,8 @@ func (set *Set) Diff(others ...*Set) (newSet *Set) { return } -// Intersect returns a new set which is the intersection from to . -// Which means, all the items in are in and also in . +// Intersect returns a new set which is the intersection from to `others`. +// Which means, all the items in are in and also in `others`. func (set *Set) Intersect(others ...*Set) (newSet *Set) { newSet = NewSet() set.mu.RLock() @@ -366,11 +366,11 @@ func (set *Set) Intersect(others ...*Set) (newSet *Set) { return } -// Complement returns a new set which is the complement from to . -// Which means, all the items in are in and not in . +// Complement returns a new set which is the complement from to `full`. +// Which means, all the items in are in and not in `set`. // -// It returns the difference between and -// if the given set is not the full set of . +// It returns the difference between and `set` +// if the given set is not the full set of `set`. func (set *Set) Complement(full *Set) (newSet *Set) { newSet = NewSet() set.mu.RLock() @@ -387,7 +387,7 @@ func (set *Set) Complement(full *Set) (newSet *Set) { return } -// Merge adds items from sets into . +// Merge adds items from sets into `set`. func (set *Set) Merge(others ...*Set) *Set { set.mu.Lock() defer set.mu.Unlock() @@ -428,7 +428,7 @@ func (set *Set) Pop() interface{} { return nil } -// Pops randomly pops items from set. +// Pops randomly pops `size` items from set. // It returns all items if size == -1. func (set *Set) Pops(size int) []interface{} { set.mu.Lock() @@ -452,7 +452,7 @@ func (set *Set) Pops(size int) []interface{} { return array } -// Walk applies a user supplied function to every item of set. +// Walk applies a user supplied function `f` to every item of set. func (set *Set) Walk(f func(item interface{}) interface{}) *Set { set.mu.Lock() defer set.mu.Unlock() diff --git a/container/gset/gset_int_set.go b/container/gset/gset_int_set.go index 39a98d9f3..2fead63dc 100644 --- a/container/gset/gset_int_set.go +++ b/container/gset/gset_int_set.go @@ -20,7 +20,7 @@ type IntSet struct { } // New create and returns a new set, which contains un-repeated items. -// The parameter is used to specify whether using set in concurrent-safety, +// The parameter `safe` is used to specify whether using set in concurrent-safety, // which is false in default. func NewIntSet(safe ...bool) *IntSet { return &IntSet{ @@ -29,7 +29,7 @@ func NewIntSet(safe ...bool) *IntSet { } } -// NewIntSetFrom returns a new set from . +// NewIntSetFrom returns a new set from `items`. func NewIntSetFrom(items []int, safe ...bool) *IntSet { m := make(map[int]struct{}) for _, v := range items { @@ -41,8 +41,8 @@ func NewIntSetFrom(items []int, safe ...bool) *IntSet { } } -// Iterator iterates the set readonly with given callback function , -// if returns true then continue iterating; or false to stop. +// Iterator iterates the set readonly with given callback function `f`, +// if `f` returns true then continue iterating; or false to stop. func (set *IntSet) Iterator(f func(v int) bool) { set.mu.RLock() defer set.mu.RUnlock() @@ -69,7 +69,7 @@ func (set *IntSet) Add(item ...int) { // it adds the item to set and returns true if it does not exists in the set, // or else it does nothing and returns false. // -// Note that, if is nil, it does nothing and returns false. +// Note that, if `item` is nil, it does nothing and returns false. func (set *IntSet) AddIfNotExist(item int) bool { if !set.Contains(item) { set.mu.Lock() @@ -87,9 +87,9 @@ func (set *IntSet) AddIfNotExist(item int) bool { // AddIfNotExistFunc checks whether item exists in the set, // it adds the item to set and returns true if it does not exists in the set and -// function returns true, or else it does nothing and returns false. +// function `f` returns true, or else it does nothing and returns false. // -// Note that, the function is executed without writing lock. +// Note that, the function `f` is executed without writing lock. func (set *IntSet) AddIfNotExistFunc(item int, f func() bool) bool { if !set.Contains(item) { if f() { @@ -109,9 +109,9 @@ func (set *IntSet) AddIfNotExistFunc(item int, f func() bool) bool { // AddIfNotExistFunc checks whether item exists in the set, // it adds the item to set and returns true if it does not exists in the set and -// function returns true, or else it does nothing and returns false. +// function `f` returns true, or else it does nothing and returns false. // -// Note that, the function is executed without writing lock. +// Note that, the function `f` is executed without writing lock. func (set *IntSet) AddIfNotExistFuncLock(item int, f func() bool) bool { if !set.Contains(item) { set.mu.Lock() @@ -129,7 +129,7 @@ func (set *IntSet) AddIfNotExistFuncLock(item int, f func() bool) bool { return false } -// Contains checks whether the set contains . +// Contains checks whether the set contains `item`. func (set *IntSet) Contains(item int) bool { var ok bool set.mu.RLock() @@ -140,7 +140,7 @@ func (set *IntSet) Contains(item int) bool { return ok } -// Remove deletes from set. +// Remove deletes `item` from set. func (set *IntSet) Remove(item int) { set.mu.Lock() if set.data != nil { @@ -179,7 +179,7 @@ func (set *IntSet) Slice() []int { return ret } -// Join joins items with a string . +// Join joins items with a string `glue`. func (set *IntSet) Join(glue string) string { set.mu.RLock() defer set.mu.RUnlock() @@ -206,14 +206,14 @@ func (set *IntSet) String() string { return "[" + set.Join(",") + "]" } -// LockFunc locks writing with callback function . +// LockFunc locks writing with callback function `f`. func (set *IntSet) LockFunc(f func(m map[int]struct{})) { set.mu.Lock() defer set.mu.Unlock() f(set.data) } -// RLockFunc locks reading with callback function . +// RLockFunc locks reading with callback function `f`. func (set *IntSet) RLockFunc(f func(m map[int]struct{})) { set.mu.RLock() defer set.mu.RUnlock() @@ -240,7 +240,7 @@ func (set *IntSet) Equal(other *IntSet) bool { return true } -// IsSubsetOf checks whether the current set is a sub-set of . +// IsSubsetOf checks whether the current set is a sub-set of `other`. func (set *IntSet) IsSubsetOf(other *IntSet) bool { if set == other { return true @@ -257,8 +257,8 @@ func (set *IntSet) IsSubsetOf(other *IntSet) bool { return true } -// Union returns a new set which is the union of and . -// Which means, all the items in are in or in . +// Union returns a new set which is the union of and `other`. +// Which means, all the items in are in or in `other`. func (set *IntSet) Union(others ...*IntSet) (newSet *IntSet) { newSet = NewIntSet() set.mu.RLock() @@ -283,8 +283,8 @@ func (set *IntSet) Union(others ...*IntSet) (newSet *IntSet) { return } -// Diff returns a new set which is the difference set from to . -// Which means, all the items in are in but not in . +// Diff returns a new set which is the difference set from to `other`. +// Which means, all the items in are in but not in `other`. func (set *IntSet) Diff(others ...*IntSet) (newSet *IntSet) { newSet = NewIntSet() set.mu.RLock() @@ -304,8 +304,8 @@ func (set *IntSet) Diff(others ...*IntSet) (newSet *IntSet) { return } -// Intersect returns a new set which is the intersection from to . -// Which means, all the items in are in and also in . +// Intersect returns a new set which is the intersection from to `other`. +// Which means, all the items in are in and also in `other`. func (set *IntSet) Intersect(others ...*IntSet) (newSet *IntSet) { newSet = NewIntSet() set.mu.RLock() @@ -326,11 +326,11 @@ func (set *IntSet) Intersect(others ...*IntSet) (newSet *IntSet) { return } -// Complement returns a new set which is the complement from to . -// Which means, all the items in are in and not in . +// Complement returns a new set which is the complement from to `full`. +// Which means, all the items in are in and not in `set`. // -// It returns the difference between and -// if the given set is not the full set of . +// It returns the difference between and `set` +// if the given set is not the full set of `set`. func (set *IntSet) Complement(full *IntSet) (newSet *IntSet) { newSet = NewIntSet() set.mu.RLock() @@ -347,7 +347,7 @@ func (set *IntSet) Complement(full *IntSet) (newSet *IntSet) { return } -// Merge adds items from sets into . +// Merge adds items from sets into `set`. func (set *IntSet) Merge(others ...*IntSet) *IntSet { set.mu.Lock() defer set.mu.Unlock() @@ -388,7 +388,7 @@ func (set *IntSet) Pop() int { return 0 } -// Pops randomly pops items from set. +// Pops randomly pops `size` items from set. // It returns all items if size == -1. func (set *IntSet) Pops(size int) []int { set.mu.Lock() @@ -412,7 +412,7 @@ func (set *IntSet) Pops(size int) []int { return array } -// Walk applies a user supplied function to every item of set. +// Walk applies a user supplied function `f` to every item of set. func (set *IntSet) Walk(f func(item int) int) *IntSet { set.mu.Lock() defer set.mu.Unlock() diff --git a/container/gset/gset_str_set.go b/container/gset/gset_str_set.go index 24323c3e7..dea06ff17 100644 --- a/container/gset/gset_str_set.go +++ b/container/gset/gset_str_set.go @@ -22,7 +22,7 @@ type StrSet struct { } // NewStrSet create and returns a new set, which contains un-repeated items. -// The parameter is used to specify whether using set in concurrent-safety, +// The parameter `safe` is used to specify whether using set in concurrent-safety, // which is false in default. func NewStrSet(safe ...bool) *StrSet { return &StrSet{ @@ -31,7 +31,7 @@ func NewStrSet(safe ...bool) *StrSet { } } -// NewStrSetFrom returns a new set from . +// NewStrSetFrom returns a new set from `items`. func NewStrSetFrom(items []string, safe ...bool) *StrSet { m := make(map[string]struct{}) for _, v := range items { @@ -43,8 +43,8 @@ func NewStrSetFrom(items []string, safe ...bool) *StrSet { } } -// Iterator iterates the set readonly with given callback function , -// if returns true then continue iterating; or false to stop. +// Iterator iterates the set readonly with given callback function `f`, +// if `f` returns true then continue iterating; or false to stop. func (set *StrSet) Iterator(f func(v string) bool) { set.mu.RLock() defer set.mu.RUnlock() @@ -87,9 +87,9 @@ func (set *StrSet) AddIfNotExist(item string) bool { // AddIfNotExistFunc checks whether item exists in the set, // it adds the item to set and returns true if it does not exists in the set and -// function returns true, or else it does nothing and returns false. +// function `f` returns true, or else it does nothing and returns false. // -// Note that, the function is executed without writing lock. +// Note that, the function `f` is executed without writing lock. func (set *StrSet) AddIfNotExistFunc(item string, f func() bool) bool { if !set.Contains(item) { if f() { @@ -109,9 +109,9 @@ func (set *StrSet) AddIfNotExistFunc(item string, f func() bool) bool { // AddIfNotExistFunc checks whether item exists in the set, // it adds the item to set and returns true if it does not exists in the set and -// function returns true, or else it does nothing and returns false. +// function `f` returns true, or else it does nothing and returns false. // -// Note that, the function is executed without writing lock. +// Note that, the function `f` is executed without writing lock. func (set *StrSet) AddIfNotExistFuncLock(item string, f func() bool) bool { if !set.Contains(item) { set.mu.Lock() @@ -129,7 +129,7 @@ func (set *StrSet) AddIfNotExistFuncLock(item string, f func() bool) bool { return false } -// Contains checks whether the set contains . +// Contains checks whether the set contains `item`. func (set *StrSet) Contains(item string) bool { var ok bool set.mu.RLock() @@ -153,7 +153,7 @@ func (set *StrSet) ContainsI(item string) bool { return false } -// Remove deletes from set. +// Remove deletes `item` from set. func (set *StrSet) Remove(item string) { set.mu.Lock() if set.data != nil { @@ -193,7 +193,7 @@ func (set *StrSet) Slice() []string { return ret } -// Join joins items with a string . +// Join joins items with a string `glue`. func (set *StrSet) Join(glue string) string { set.mu.RLock() defer set.mu.RUnlock() @@ -234,14 +234,14 @@ func (set *StrSet) String() string { return buffer.String() } -// LockFunc locks writing with callback function . +// LockFunc locks writing with callback function `f`. func (set *StrSet) LockFunc(f func(m map[string]struct{})) { set.mu.Lock() defer set.mu.Unlock() f(set.data) } -// RLockFunc locks reading with callback function . +// RLockFunc locks reading with callback function `f`. func (set *StrSet) RLockFunc(f func(m map[string]struct{})) { set.mu.RLock() defer set.mu.RUnlock() @@ -268,7 +268,7 @@ func (set *StrSet) Equal(other *StrSet) bool { return true } -// IsSubsetOf checks whether the current set is a sub-set of . +// IsSubsetOf checks whether the current set is a sub-set of `other`. func (set *StrSet) IsSubsetOf(other *StrSet) bool { if set == other { return true @@ -285,8 +285,8 @@ func (set *StrSet) IsSubsetOf(other *StrSet) bool { return true } -// Union returns a new set which is the union of and . -// Which means, all the items in are in or in . +// Union returns a new set which is the union of and `other`. +// Which means, all the items in are in or in `other`. func (set *StrSet) Union(others ...*StrSet) (newSet *StrSet) { newSet = NewStrSet() set.mu.RLock() @@ -311,8 +311,8 @@ func (set *StrSet) Union(others ...*StrSet) (newSet *StrSet) { return } -// Diff returns a new set which is the difference set from to . -// Which means, all the items in are in but not in . +// Diff returns a new set which is the difference set from to `other`. +// Which means, all the items in are in but not in `other`. func (set *StrSet) Diff(others ...*StrSet) (newSet *StrSet) { newSet = NewStrSet() set.mu.RLock() @@ -332,8 +332,8 @@ func (set *StrSet) Diff(others ...*StrSet) (newSet *StrSet) { return } -// Intersect returns a new set which is the intersection from to . -// Which means, all the items in are in and also in . +// Intersect returns a new set which is the intersection from to `other`. +// Which means, all the items in are in and also in `other`. func (set *StrSet) Intersect(others ...*StrSet) (newSet *StrSet) { newSet = NewStrSet() set.mu.RLock() @@ -354,11 +354,11 @@ func (set *StrSet) Intersect(others ...*StrSet) (newSet *StrSet) { return } -// Complement returns a new set which is the complement from to . -// Which means, all the items in are in and not in . +// Complement returns a new set which is the complement from to `full`. +// Which means, all the items in are in and not in `set`. // -// It returns the difference between and -// if the given set is not the full set of . +// It returns the difference between and `set` +// if the given set is not the full set of `set`. func (set *StrSet) Complement(full *StrSet) (newSet *StrSet) { newSet = NewStrSet() set.mu.RLock() @@ -375,7 +375,7 @@ func (set *StrSet) Complement(full *StrSet) (newSet *StrSet) { return } -// Merge adds items from sets into . +// Merge adds items from sets into `set`. func (set *StrSet) Merge(others ...*StrSet) *StrSet { set.mu.Lock() defer set.mu.Unlock() @@ -416,7 +416,7 @@ func (set *StrSet) Pop() string { return "" } -// Pops randomly pops items from set. +// Pops randomly pops `size` items from set. // It returns all items if size == -1. func (set *StrSet) Pops(size int) []string { set.mu.Lock() @@ -440,7 +440,7 @@ func (set *StrSet) Pops(size int) []string { return array } -// Walk applies a user supplied function to every item of set. +// Walk applies a user supplied function `f` to every item of set. func (set *StrSet) Walk(f func(item string) string) *StrSet { set.mu.Lock() defer set.mu.Unlock() diff --git a/container/gtree/gtree_avltree.go b/container/gtree/gtree_avltree.go index b5ee031dd..deaad2b75 100644 --- a/container/gtree/gtree_avltree.go +++ b/container/gtree/gtree_avltree.go @@ -34,7 +34,7 @@ type AVLTreeNode struct { } // NewAVLTree instantiates an AVL tree with the custom key comparator. -// The parameter is used to specify whether using tree in concurrent-safety, +// The parameter `safe` is used to specify whether using tree in concurrent-safety, // which is false in default. func NewAVLTree(comparator func(v1, v2 interface{}) int, safe ...bool) *AVLTree { return &AVLTree{ @@ -44,7 +44,7 @@ func NewAVLTree(comparator func(v1, v2 interface{}) int, safe ...bool) *AVLTree } // NewAVLTreeFrom instantiates an AVL tree with the custom key comparator and data map. -// The parameter is used to specify whether using tree in concurrent-safety, +// The parameter `safe` is used to specify whether using tree in concurrent-safety, // which is false in default. func NewAVLTreeFrom(comparator func(v1, v2 interface{}) int, data map[interface{}]interface{}, safe ...bool) *AVLTree { tree := NewAVLTree(comparator, safe...) @@ -77,8 +77,8 @@ func (tree *AVLTree) Sets(data map[interface{}]interface{}) { } } -// Search searches the tree with given . -// Second return parameter is true if key was found, otherwise false. +// Search searches the tree with given `key`. +// Second return parameter `found` is true if key was found, otherwise false. func (tree *AVLTree) Search(key interface{}) (value interface{}, found bool) { tree.mu.RLock() defer tree.mu.RUnlock() @@ -88,8 +88,8 @@ func (tree *AVLTree) Search(key interface{}) (value interface{}, found bool) { return nil, false } -// doSearch searches the tree with given . -// Second return parameter is true if key was found, otherwise false. +// doSearch searches the tree with given `key`. +// Second return parameter `found` is true if key was found, otherwise false. func (tree *AVLTree) doSearch(key interface{}) (node *AVLTreeNode, found bool) { node = tree.root for node != nil { @@ -106,21 +106,21 @@ func (tree *AVLTree) doSearch(key interface{}) (node *AVLTreeNode, found bool) { return nil, false } -// Get searches the node in the tree by and returns its value or nil if key is not found in tree. +// Get searches the node in the tree by `key` and returns its value or nil if key is not found in tree. func (tree *AVLTree) Get(key interface{}) (value interface{}) { value, _ = tree.Search(key) return } // doSetWithLockCheck checks whether value of the key exists with mutex.Lock, -// if not exists, set value to the map with given , +// if not exists, set value to the map with given `key`, // or else just return the existing value. // -// When setting value, if is type of , +// When setting value, if `value` is type of , // it will be executed with mutex.Lock of the hash map, -// and its return value will be set to the map with . +// and its return value will be set to the map with `key`. // -// It returns value with given . +// It returns value with given `key`. func (tree *AVLTree) doSetWithLockCheck(key interface{}, value interface{}) interface{} { tree.mu.Lock() defer tree.mu.Unlock() @@ -137,7 +137,7 @@ func (tree *AVLTree) doSetWithLockCheck(key interface{}, value interface{}) inte } // GetOrSet returns the value by key, -// or sets value with given if it does not exist and then returns this value. +// or sets value with given `value` if it does not exist and then returns this value. func (tree *AVLTree) GetOrSet(key interface{}, value interface{}) interface{} { if v, ok := tree.Search(key); !ok { return tree.doSetWithLockCheck(key, value) @@ -147,7 +147,7 @@ func (tree *AVLTree) GetOrSet(key interface{}, value interface{}) interface{} { } // GetOrSetFunc returns the value by key, -// or sets value with returned value of callback function if it does not exist +// or sets value with returned value of callback function `f` if it does not exist // and then returns this value. func (tree *AVLTree) GetOrSetFunc(key interface{}, f func() interface{}) interface{} { if v, ok := tree.Search(key); !ok { @@ -158,10 +158,10 @@ func (tree *AVLTree) GetOrSetFunc(key interface{}, f func() interface{}) interfa } // GetOrSetFuncLock returns the value by key, -// or sets value with returned value of callback function if it does not exist +// or sets value with returned value of callback function `f` if it does not exist // and then returns this value. // -// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function +// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function `f` // with mutex.Lock of the hash map. func (tree *AVLTree) GetOrSetFuncLock(key interface{}, f func() interface{}) interface{} { if v, ok := tree.Search(key); !ok { @@ -171,7 +171,7 @@ func (tree *AVLTree) GetOrSetFuncLock(key interface{}, f func() interface{}) int } } -// GetVar returns a gvar.Var with the value by given . +// GetVar returns a gvar.Var with the value by given `key`. // The returned gvar.Var is un-concurrent safe. func (tree *AVLTree) GetVar(key interface{}) *gvar.Var { return gvar.New(tree.Get(key)) @@ -195,8 +195,8 @@ func (tree *AVLTree) GetVarOrSetFuncLock(key interface{}, f func() interface{}) return gvar.New(tree.GetOrSetFuncLock(key, f)) } -// SetIfNotExist sets to the map if the does not exist, and then returns true. -// It returns false if exists, and would be ignored. +// SetIfNotExist sets to the map if the `key` does not exist, and then returns true. +// It returns false if exists, and `value` would be ignored. func (tree *AVLTree) SetIfNotExist(key interface{}, value interface{}) bool { if !tree.Contains(key) { tree.doSetWithLockCheck(key, value) @@ -205,8 +205,8 @@ func (tree *AVLTree) SetIfNotExist(key interface{}, value interface{}) bool { return false } -// SetIfNotExistFunc sets value with return value of callback function , and then returns true. -// It returns false if exists, and would be ignored. +// SetIfNotExistFunc sets value with return value of callback function `f`, and then returns true. +// It returns false if exists, and `value` would be ignored. func (tree *AVLTree) SetIfNotExistFunc(key interface{}, f func() interface{}) bool { if !tree.Contains(key) { tree.doSetWithLockCheck(key, f()) @@ -215,11 +215,11 @@ func (tree *AVLTree) SetIfNotExistFunc(key interface{}, f func() interface{}) bo return false } -// SetIfNotExistFuncLock sets value with return value of callback function , and then returns true. -// It returns false if exists, and would be ignored. +// SetIfNotExistFuncLock sets value with return value of callback function `f`, and then returns true. +// It returns false if exists, and `value` would be ignored. // // SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that -// it executes function with mutex.Lock of the hash map. +// it executes function `f` with mutex.Lock of the hash map. func (tree *AVLTree) SetIfNotExistFuncLock(key interface{}, f func() interface{}) bool { if !tree.Contains(key) { tree.doSetWithLockCheck(key, f) @@ -228,7 +228,7 @@ func (tree *AVLTree) SetIfNotExistFuncLock(key interface{}, f func() interface{} return false } -// Contains checks whether exists in the tree. +// Contains checks whether `key` exists in the tree. func (tree *AVLTree) Contains(key interface{}) bool { _, ok := tree.Search(key) return ok @@ -243,7 +243,7 @@ func (tree *AVLTree) Remove(key interface{}) (value interface{}) { return } -// Removes batch deletes values of the tree by . +// Removes batch deletes values of the tree by `keys`. func (tree *AVLTree) Removes(keys []interface{}) { tree.mu.Lock() defer tree.mu.Unlock() @@ -386,7 +386,7 @@ func (tree *AVLTree) Clear() { tree.size = 0 } -// Replace the data of the tree with given . +// Replace the data of the tree with given `data`. func (tree *AVLTree) Replace(data map[interface{}]interface{}) { tree.mu.Lock() defer tree.mu.Unlock() @@ -437,7 +437,7 @@ func (tree *AVLTree) MapStrAny() map[string]interface{} { // Note that you should guarantee the value is the same type as key, // or else the comparator would panic. // -// If the type of value is different with key, you pass the new . +// If the type of value is different with key, you pass the new `comparator`. func (tree *AVLTree) Flip(comparator ...func(v1, v2 interface{}) int) { t := (*AVLTree)(nil) if len(comparator) > 0 { @@ -465,18 +465,18 @@ func (tree *AVLTree) IteratorFrom(key interface{}, match bool, f func(key, value tree.IteratorAscFrom(key, match, f) } -// IteratorAsc iterates the tree readonly in ascending order with given callback function . -// If returns true, then it continues iterating; or false to stop. +// IteratorAsc iterates the tree readonly in ascending order with given callback function `f`. +// If `f` returns true, then it continues iterating; or false to stop. func (tree *AVLTree) IteratorAsc(f func(key, value interface{}) bool) { tree.mu.RLock() defer tree.mu.RUnlock() tree.doIteratorAsc(tree.bottom(0), f) } -// IteratorAscFrom iterates the tree readonly in ascending order with given callback function . -// The parameter specifies the start entry for iterating. The specifies whether -// starting iterating if the is fully matched, or else using index searching iterating. -// If returns true, then it continues iterating; or false to stop. +// IteratorAscFrom iterates the tree readonly in ascending order with given callback function `f`. +// The parameter specifies the start entry for iterating. The `match` specifies whether +// starting iterating if the `key` is fully matched, or else using index searching iterating. +// If `f` returns true, then it continues iterating; or false to stop. func (tree *AVLTree) IteratorAscFrom(key interface{}, match bool, f func(key, value interface{}) bool) { tree.mu.RLock() defer tree.mu.RUnlock() @@ -499,18 +499,18 @@ func (tree *AVLTree) doIteratorAsc(node *AVLTreeNode, f func(key, value interfac } } -// IteratorDesc iterates the tree readonly in descending order with given callback function . -// If returns true, then it continues iterating; or false to stop. +// IteratorDesc iterates the tree readonly in descending order with given callback function `f`. +// If `f` returns true, then it continues iterating; or false to stop. func (tree *AVLTree) IteratorDesc(f func(key, value interface{}) bool) { tree.mu.RLock() defer tree.mu.RUnlock() tree.doIteratorDesc(tree.bottom(1), f) } -// IteratorDescFrom iterates the tree readonly in descending order with given callback function . -// The parameter specifies the start entry for iterating. The specifies whether -// starting iterating if the is fully matched, or else using index searching iterating. -// If returns true, then it continues iterating; or false to stop. +// IteratorDescFrom iterates the tree readonly in descending order with given callback function `f`. +// The parameter specifies the start entry for iterating. The `match` specifies whether +// starting iterating if the `key` is fully matched, or else using index searching iterating. +// If `f` returns true, then it continues iterating; or false to stop. func (tree *AVLTree) IteratorDescFrom(key interface{}, match bool, f func(key, value interface{}) bool) { tree.mu.RLock() defer tree.mu.RUnlock() diff --git a/container/gtree/gtree_btree.go b/container/gtree/gtree_btree.go index 45a3068b9..f26783366 100644 --- a/container/gtree/gtree_btree.go +++ b/container/gtree/gtree_btree.go @@ -40,10 +40,10 @@ type BTreeEntry struct { Value interface{} } -// NewBTree instantiates a B-tree with (maximum number of children) and a custom key comparator. -// The parameter is used to specify whether using tree in concurrent-safety, +// NewBTree instantiates a B-tree with `m` (maximum number of children) and a custom key comparator. +// The parameter `safe` is used to specify whether using tree in concurrent-safety, // which is false in default. -// Note that the must be greater or equal than 3, or else it panics. +// Note that the `m` must be greater or equal than 3, or else it panics. func NewBTree(m int, comparator func(v1, v2 interface{}) int, safe ...bool) *BTree { if m < 3 { panic("Invalid order, should be at least 3") @@ -55,8 +55,8 @@ func NewBTree(m int, comparator func(v1, v2 interface{}) int, safe ...bool) *BTr } } -// NewBTreeFrom instantiates a B-tree with (maximum number of children), a custom key comparator and data map. -// The parameter is used to specify whether using tree in concurrent-safety, +// NewBTreeFrom instantiates a B-tree with `m` (maximum number of children), a custom key comparator and data map. +// The parameter `safe` is used to specify whether using tree in concurrent-safety, // which is false in default. func NewBTreeFrom(m int, comparator func(v1, v2 interface{}) int, data map[interface{}]interface{}, safe ...bool) *BTree { tree := NewBTree(m, comparator, safe...) @@ -104,21 +104,21 @@ func (tree *BTree) Sets(data map[interface{}]interface{}) { } } -// Get searches the node in the tree by and returns its value or nil if key is not found in tree. +// Get searches the node in the tree by `key` and returns its value or nil if key is not found in tree. func (tree *BTree) Get(key interface{}) (value interface{}) { value, _ = tree.Search(key) return } // doSetWithLockCheck checks whether value of the key exists with mutex.Lock, -// if not exists, set value to the map with given , +// if not exists, set value to the map with given `key`, // or else just return the existing value. // -// When setting value, if is type of , +// When setting value, if `value` is type of , // it will be executed with mutex.Lock of the hash map, -// and its return value will be set to the map with . +// and its return value will be set to the map with `key`. // -// It returns value with given . +// It returns value with given `key`. func (tree *BTree) doSetWithLockCheck(key interface{}, value interface{}) interface{} { tree.mu.Lock() defer tree.mu.Unlock() @@ -135,7 +135,7 @@ func (tree *BTree) doSetWithLockCheck(key interface{}, value interface{}) interf } // GetOrSet returns the value by key, -// or sets value with given if it does not exist and then returns this value. +// or sets value with given `value` if it does not exist and then returns this value. func (tree *BTree) GetOrSet(key interface{}, value interface{}) interface{} { if v, ok := tree.Search(key); !ok { return tree.doSetWithLockCheck(key, value) @@ -145,7 +145,7 @@ func (tree *BTree) GetOrSet(key interface{}, value interface{}) interface{} { } // GetOrSetFunc returns the value by key, -// or sets value with returned value of callback function if it does not exist +// or sets value with returned value of callback function `f` if it does not exist // and then returns this value. func (tree *BTree) GetOrSetFunc(key interface{}, f func() interface{}) interface{} { if v, ok := tree.Search(key); !ok { @@ -156,10 +156,10 @@ func (tree *BTree) GetOrSetFunc(key interface{}, f func() interface{}) interface } // GetOrSetFuncLock returns the value by key, -// or sets value with returned value of callback function if it does not exist +// or sets value with returned value of callback function `f` if it does not exist // and then returns this value. // -// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function +// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function `f` // with mutex.Lock of the hash map. func (tree *BTree) GetOrSetFuncLock(key interface{}, f func() interface{}) interface{} { if v, ok := tree.Search(key); !ok { @@ -169,7 +169,7 @@ func (tree *BTree) GetOrSetFuncLock(key interface{}, f func() interface{}) inter } } -// GetVar returns a gvar.Var with the value by given . +// GetVar returns a gvar.Var with the value by given `key`. // The returned gvar.Var is un-concurrent safe. func (tree *BTree) GetVar(key interface{}) *gvar.Var { return gvar.New(tree.Get(key)) @@ -193,8 +193,8 @@ func (tree *BTree) GetVarOrSetFuncLock(key interface{}, f func() interface{}) *g return gvar.New(tree.GetOrSetFuncLock(key, f)) } -// SetIfNotExist sets to the map if the does not exist, and then returns true. -// It returns false if exists, and would be ignored. +// SetIfNotExist sets to the map if the `key` does not exist, and then returns true. +// It returns false if exists, and `value` would be ignored. func (tree *BTree) SetIfNotExist(key interface{}, value interface{}) bool { if !tree.Contains(key) { tree.doSetWithLockCheck(key, value) @@ -203,8 +203,8 @@ func (tree *BTree) SetIfNotExist(key interface{}, value interface{}) bool { return false } -// SetIfNotExistFunc sets value with return value of callback function , and then returns true. -// It returns false if exists, and would be ignored. +// SetIfNotExistFunc sets value with return value of callback function `f`, and then returns true. +// It returns false if exists, and `value` would be ignored. func (tree *BTree) SetIfNotExistFunc(key interface{}, f func() interface{}) bool { if !tree.Contains(key) { tree.doSetWithLockCheck(key, f()) @@ -213,11 +213,11 @@ func (tree *BTree) SetIfNotExistFunc(key interface{}, f func() interface{}) bool return false } -// SetIfNotExistFuncLock sets value with return value of callback function , and then returns true. -// It returns false if exists, and would be ignored. +// SetIfNotExistFuncLock sets value with return value of callback function `f`, and then returns true. +// It returns false if exists, and `value` would be ignored. // // SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that -// it executes function with mutex.Lock of the hash map. +// it executes function `f` with mutex.Lock of the hash map. func (tree *BTree) SetIfNotExistFuncLock(key interface{}, f func() interface{}) bool { if !tree.Contains(key) { tree.doSetWithLockCheck(key, f) @@ -226,7 +226,7 @@ func (tree *BTree) SetIfNotExistFuncLock(key interface{}, f func() interface{}) return false } -// Contains checks whether exists in the tree. +// Contains checks whether `key` exists in the tree. func (tree *BTree) Contains(key interface{}) bool { _, ok := tree.Search(key) return ok @@ -244,14 +244,14 @@ func (tree *BTree) doRemove(key interface{}) (value interface{}) { return } -// Remove removes the node from the tree by . +// Remove removes the node from the tree by `key`. func (tree *BTree) Remove(key interface{}) (value interface{}) { tree.mu.Lock() defer tree.mu.Unlock() return tree.doRemove(key) } -// Removes batch deletes values of the tree by . +// Removes batch deletes values of the tree by `keys`. func (tree *BTree) Removes(keys []interface{}) { tree.mu.Lock() defer tree.mu.Unlock() @@ -324,7 +324,7 @@ func (tree *BTree) Clear() { tree.size = 0 } -// Replace the data of the tree with given . +// Replace the data of the tree with given `data`. func (tree *BTree) Replace(data map[interface{}]interface{}) { tree.mu.Lock() defer tree.mu.Unlock() @@ -369,8 +369,8 @@ func (tree *BTree) String() string { return buffer.String() } -// Search searches the tree with given . -// Second return parameter is true if key was found, otherwise false. +// Search searches the tree with given `key`. +// Second return parameter `found` is true if key was found, otherwise false. func (tree *BTree) Search(key interface{}) (value interface{}, found bool) { tree.mu.RLock() defer tree.mu.RUnlock() @@ -381,7 +381,7 @@ func (tree *BTree) Search(key interface{}) (value interface{}, found bool) { return nil, false } -// Search searches the tree with given without mutex. +// Search searches the tree with given `key` without mutex. // It returns the entry if found or otherwise nil. func (tree *BTree) doSearch(key interface{}) *BTreeEntry { node, index, found := tree.searchRecursively(tree.root, key) @@ -406,8 +406,8 @@ func (tree *BTree) IteratorFrom(key interface{}, match bool, f func(key, value i tree.IteratorAscFrom(key, match, f) } -// IteratorAsc iterates the tree readonly in ascending order with given callback function . -// If returns true, then it continues iterating; or false to stop. +// IteratorAsc iterates the tree readonly in ascending order with given callback function `f`. +// If `f` returns true, then it continues iterating; or false to stop. func (tree *BTree) IteratorAsc(f func(key, value interface{}) bool) { tree.mu.RLock() defer tree.mu.RUnlock() @@ -418,10 +418,10 @@ func (tree *BTree) IteratorAsc(f func(key, value interface{}) bool) { tree.doIteratorAsc(node, node.Entries[0], 0, f) } -// IteratorAscFrom iterates the tree readonly in ascending order with given callback function . -// The parameter specifies the start entry for iterating. The specifies whether -// starting iterating if the is fully matched, or else using index searching iterating. -// If returns true, then it continues iterating; or false to stop. +// IteratorAscFrom iterates the tree readonly in ascending order with given callback function `f`. +// The parameter specifies the start entry for iterating. The `match` specifies whether +// starting iterating if the `key` is fully matched, or else using index searching iterating. +// If `f` returns true, then it continues iterating; or false to stop. func (tree *BTree) IteratorAscFrom(key interface{}, match bool, f func(key, value interface{}) bool) { tree.mu.RLock() defer tree.mu.RUnlock() @@ -479,8 +479,8 @@ loop: } } -// IteratorDesc iterates the tree readonly in descending order with given callback function . -// If returns true, then it continues iterating; or false to stop. +// IteratorDesc iterates the tree readonly in descending order with given callback function `f`. +// If `f` returns true, then it continues iterating; or false to stop. func (tree *BTree) IteratorDesc(f func(key, value interface{}) bool) { tree.mu.RLock() defer tree.mu.RUnlock() @@ -493,10 +493,10 @@ func (tree *BTree) IteratorDesc(f func(key, value interface{}) bool) { tree.doIteratorDesc(node, entry, index, f) } -// IteratorDescFrom iterates the tree readonly in descending order with given callback function . -// The parameter specifies the start entry for iterating. The specifies whether -// starting iterating if the is fully matched, or else using index searching iterating. -// If returns true, then it continues iterating; or false to stop. +// IteratorDescFrom iterates the tree readonly in descending order with given callback function `f`. +// The parameter specifies the start entry for iterating. The `match` specifies whether +// starting iterating if the `key` is fully matched, or else using index searching iterating. +// If `f` returns true, then it continues iterating; or false to stop. func (tree *BTree) IteratorDescFrom(key interface{}, match bool, f func(key, value interface{}) bool) { tree.mu.RLock() defer tree.mu.RUnlock() @@ -510,8 +510,8 @@ func (tree *BTree) IteratorDescFrom(key interface{}, match bool, f func(key, val } } -// IteratorDesc iterates the tree readonly in descending order with given callback function . -// If returns true, then it continues iterating; or false to stop. +// IteratorDesc iterates the tree readonly in descending order with given callback function `f`. +// If `f` returns true, then it continues iterating; or false to stop. func (tree *BTree) doIteratorDesc(node *BTreeNode, entry *BTreeEntry, index int, f func(key, value interface{}) bool) { first := true loop: diff --git a/container/gtree/gtree_redblacktree.go b/container/gtree/gtree_redblacktree.go index 7ccf0fd1c..e75d04ffd 100644 --- a/container/gtree/gtree_redblacktree.go +++ b/container/gtree/gtree_redblacktree.go @@ -41,7 +41,7 @@ type RedBlackTreeNode struct { } // NewRedBlackTree instantiates a red-black tree with the custom key comparator. -// The parameter is used to specify whether using tree in concurrent-safety, +// The parameter `safe` is used to specify whether using tree in concurrent-safety, // which is false in default. func NewRedBlackTree(comparator func(v1, v2 interface{}) int, safe ...bool) *RedBlackTree { return &RedBlackTree{ @@ -50,8 +50,8 @@ func NewRedBlackTree(comparator func(v1, v2 interface{}) int, safe ...bool) *Red } } -// NewRedBlackTreeFrom instantiates a red-black tree with the custom key comparator and map. -// The parameter is used to specify whether using tree in concurrent-safety, +// NewRedBlackTreeFrom instantiates a red-black tree with the custom key comparator and `data` map. +// The parameter `safe` is used to specify whether using tree in concurrent-safety, // which is false in default. func NewRedBlackTreeFrom(comparator func(v1, v2 interface{}) int, data map[interface{}]interface{}, safe ...bool) *RedBlackTree { tree := NewRedBlackTree(comparator, safe...) @@ -146,21 +146,21 @@ func (tree *RedBlackTree) doSet(key interface{}, value interface{}) { tree.size++ } -// Get searches the node in the tree by and returns its value or nil if key is not found in tree. +// Get searches the node in the tree by `key` and returns its value or nil if key is not found in tree. func (tree *RedBlackTree) Get(key interface{}) (value interface{}) { value, _ = tree.Search(key) return } // doSetWithLockCheck checks whether value of the key exists with mutex.Lock, -// if not exists, set value to the map with given , +// if not exists, set value to the map with given `key`, // or else just return the existing value. // -// When setting value, if is type of , +// When setting value, if `value` is type of , // it will be executed with mutex.Lock of the hash map, -// and its return value will be set to the map with . +// and its return value will be set to the map with `key`. // -// It returns value with given . +// It returns value with given `key`. func (tree *RedBlackTree) doSetWithLockCheck(key interface{}, value interface{}) interface{} { tree.mu.Lock() defer tree.mu.Unlock() @@ -177,7 +177,7 @@ func (tree *RedBlackTree) doSetWithLockCheck(key interface{}, value interface{}) } // GetOrSet returns the value by key, -// or sets value with given if it does not exist and then returns this value. +// or sets value with given `value` if it does not exist and then returns this value. func (tree *RedBlackTree) GetOrSet(key interface{}, value interface{}) interface{} { if v, ok := tree.Search(key); !ok { return tree.doSetWithLockCheck(key, value) @@ -187,7 +187,7 @@ func (tree *RedBlackTree) GetOrSet(key interface{}, value interface{}) interface } // GetOrSetFunc returns the value by key, -// or sets value with returned value of callback function if it does not exist +// or sets value with returned value of callback function `f` if it does not exist // and then returns this value. func (tree *RedBlackTree) GetOrSetFunc(key interface{}, f func() interface{}) interface{} { if v, ok := tree.Search(key); !ok { @@ -198,10 +198,10 @@ func (tree *RedBlackTree) GetOrSetFunc(key interface{}, f func() interface{}) in } // GetOrSetFuncLock returns the value by key, -// or sets value with returned value of callback function if it does not exist +// or sets value with returned value of callback function `f` if it does not exist // and then returns this value. // -// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function +// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function `f` // with mutex.Lock of the hash map. func (tree *RedBlackTree) GetOrSetFuncLock(key interface{}, f func() interface{}) interface{} { if v, ok := tree.Search(key); !ok { @@ -211,7 +211,7 @@ func (tree *RedBlackTree) GetOrSetFuncLock(key interface{}, f func() interface{} } } -// GetVar returns a gvar.Var with the value by given . +// GetVar returns a gvar.Var with the value by given `key`. // The returned gvar.Var is un-concurrent safe. func (tree *RedBlackTree) GetVar(key interface{}) *gvar.Var { return gvar.New(tree.Get(key)) @@ -235,8 +235,8 @@ func (tree *RedBlackTree) GetVarOrSetFuncLock(key interface{}, f func() interfac return gvar.New(tree.GetOrSetFuncLock(key, f)) } -// SetIfNotExist sets to the map if the does not exist, and then returns true. -// It returns false if exists, and would be ignored. +// SetIfNotExist sets to the map if the `key` does not exist, and then returns true. +// It returns false if exists, and `value` would be ignored. func (tree *RedBlackTree) SetIfNotExist(key interface{}, value interface{}) bool { if !tree.Contains(key) { tree.doSetWithLockCheck(key, value) @@ -245,8 +245,8 @@ func (tree *RedBlackTree) SetIfNotExist(key interface{}, value interface{}) bool return false } -// SetIfNotExistFunc sets value with return value of callback function , and then returns true. -// It returns false if exists, and would be ignored. +// SetIfNotExistFunc sets value with return value of callback function `f`, and then returns true. +// It returns false if exists, and `value` would be ignored. func (tree *RedBlackTree) SetIfNotExistFunc(key interface{}, f func() interface{}) bool { if !tree.Contains(key) { tree.doSetWithLockCheck(key, f()) @@ -255,11 +255,11 @@ func (tree *RedBlackTree) SetIfNotExistFunc(key interface{}, f func() interface{ return false } -// SetIfNotExistFuncLock sets value with return value of callback function , and then returns true. -// It returns false if exists, and would be ignored. +// SetIfNotExistFuncLock sets value with return value of callback function `f`, and then returns true. +// It returns false if exists, and `value` would be ignored. // // SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that -// it executes function with mutex.Lock of the hash map. +// it executes function `f` with mutex.Lock of the hash map. func (tree *RedBlackTree) SetIfNotExistFuncLock(key interface{}, f func() interface{}) bool { if !tree.Contains(key) { tree.doSetWithLockCheck(key, f) @@ -268,13 +268,13 @@ func (tree *RedBlackTree) SetIfNotExistFuncLock(key interface{}, f func() interf return false } -// Contains checks whether exists in the tree. +// Contains checks whether `key` exists in the tree. func (tree *RedBlackTree) Contains(key interface{}) bool { _, ok := tree.Search(key) return ok } -// doRemove removes the node from the tree by without mutex. +// doRemove removes the node from the tree by `key` without mutex. func (tree *RedBlackTree) doRemove(key interface{}) (value interface{}) { child := (*RedBlackTreeNode)(nil) node, found := tree.doSearch(key) @@ -307,14 +307,14 @@ func (tree *RedBlackTree) doRemove(key interface{}) (value interface{}) { return } -// Remove removes the node from the tree by . +// Remove removes the node from the tree by `key`. func (tree *RedBlackTree) Remove(key interface{}) (value interface{}) { tree.mu.Lock() defer tree.mu.Unlock() return tree.doRemove(key) } -// Removes batch deletes values of the tree by . +// Removes batch deletes values of the tree by `keys`. func (tree *RedBlackTree) Removes(keys []interface{}) { tree.mu.Lock() defer tree.mu.Unlock() @@ -436,7 +436,7 @@ func (tree *RedBlackTree) rightNode() *RedBlackTreeNode { // Floor Finds floor node of the input key, return the floor node or nil if no floor node is found. // Second return parameter is true if floor was found, otherwise false. // -// Floor node is defined as the largest node that its key is smaller than or equal to the given . +// Floor node is defined as the largest node that its key is smaller than or equal to the given `key`. // A floor node may not be found, either because the tree is empty, or because // all nodes in the tree are larger than the given node. func (tree *RedBlackTree) Floor(key interface{}) (floor *RedBlackTreeNode, found bool) { @@ -464,7 +464,7 @@ func (tree *RedBlackTree) Floor(key interface{}) (floor *RedBlackTreeNode, found // Ceiling finds ceiling node of the input key, return the ceiling node or nil if no ceiling node is found. // Second return parameter is true if ceiling was found, otherwise false. // -// Ceiling node is defined as the smallest node that its key is larger than or equal to the given . +// Ceiling node is defined as the smallest node that its key is larger than or equal to the given `key`. // A ceiling node may not be found, either because the tree is empty, or because // all nodes in the tree are smaller than the given node. func (tree *RedBlackTree) Ceiling(key interface{}) (ceiling *RedBlackTreeNode, found bool) { @@ -499,18 +499,18 @@ func (tree *RedBlackTree) IteratorFrom(key interface{}, match bool, f func(key, tree.IteratorAscFrom(key, match, f) } -// IteratorAsc iterates the tree readonly in ascending order with given callback function . -// If returns true, then it continues iterating; or false to stop. +// IteratorAsc iterates the tree readonly in ascending order with given callback function `f`. +// If `f` returns true, then it continues iterating; or false to stop. func (tree *RedBlackTree) IteratorAsc(f func(key, value interface{}) bool) { tree.mu.RLock() defer tree.mu.RUnlock() tree.doIteratorAsc(tree.leftNode(), f) } -// IteratorAscFrom iterates the tree readonly in ascending order with given callback function . -// The parameter specifies the start entry for iterating. The specifies whether -// starting iterating if the is fully matched, or else using index searching iterating. -// If returns true, then it continues iterating; or false to stop. +// IteratorAscFrom iterates the tree readonly in ascending order with given callback function `f`. +// The parameter specifies the start entry for iterating. The `match` specifies whether +// starting iterating if the `key` is fully matched, or else using index searching iterating. +// If `f` returns true, then it continues iterating; or false to stop. func (tree *RedBlackTree) IteratorAscFrom(key interface{}, match bool, f func(key, value interface{}) bool) { tree.mu.RLock() defer tree.mu.RUnlock() @@ -550,18 +550,18 @@ loop: } } -// IteratorDesc iterates the tree readonly in descending order with given callback function . -// If returns true, then it continues iterating; or false to stop. +// IteratorDesc iterates the tree readonly in descending order with given callback function `f`. +// If `f` returns true, then it continues iterating; or false to stop. func (tree *RedBlackTree) IteratorDesc(f func(key, value interface{}) bool) { tree.mu.RLock() defer tree.mu.RUnlock() tree.doIteratorDesc(tree.rightNode(), f) } -// IteratorDescFrom iterates the tree readonly in descending order with given callback function . -// The parameter specifies the start entry for iterating. The specifies whether -// starting iterating if the is fully matched, or else using index searching iterating. -// If returns true, then it continues iterating; or false to stop. +// IteratorDescFrom iterates the tree readonly in descending order with given callback function `f`. +// The parameter specifies the start entry for iterating. The `match` specifies whether +// starting iterating if the `key` is fully matched, or else using index searching iterating. +// If `f` returns true, then it continues iterating; or false to stop. func (tree *RedBlackTree) IteratorDescFrom(key interface{}, match bool, f func(key, value interface{}) bool) { tree.mu.RLock() defer tree.mu.RUnlock() @@ -609,7 +609,7 @@ func (tree *RedBlackTree) Clear() { tree.size = 0 } -// Replace the data of the tree with given . +// Replace the data of the tree with given `data`. func (tree *RedBlackTree) Replace(data map[interface{}]interface{}) { tree.mu.Lock() defer tree.mu.Unlock() @@ -636,8 +636,8 @@ func (tree *RedBlackTree) Print() { fmt.Println(tree.String()) } -// Search searches the tree with given . -// Second return parameter is true if key was found, otherwise false. +// Search searches the tree with given `key`. +// Second return parameter `found` is true if key was found, otherwise false. func (tree *RedBlackTree) Search(key interface{}) (value interface{}, found bool) { tree.mu.RLock() defer tree.mu.RUnlock() @@ -652,7 +652,7 @@ func (tree *RedBlackTree) Search(key interface{}) (value interface{}, found bool // Note that you should guarantee the value is the same type as key, // or else the comparator would panic. // -// If the type of value is different with key, you pass the new . +// If the type of value is different with key, you pass the new `comparator`. func (tree *RedBlackTree) Flip(comparator ...func(v1, v2 interface{}) int) { t := (*RedBlackTree)(nil) if len(comparator) > 0 { @@ -698,7 +698,7 @@ func (tree *RedBlackTree) output(node *RedBlackTreeNode, prefix string, isTail b } } -// doSearch searches the tree with given without mutex. +// doSearch searches the tree with given `key` without mutex. // It returns the node if found or otherwise nil. func (tree *RedBlackTree) doSearch(key interface{}) (node *RedBlackTreeNode, found bool) { node = tree.root diff --git a/container/gtype/bool.go b/container/gtype/gtype_bool.go similarity index 94% rename from container/gtype/bool.go rename to container/gtype/gtype_bool.go index adb49db20..4b7e45909 100644 --- a/container/gtype/bool.go +++ b/container/gtype/gtype_bool.go @@ -23,7 +23,7 @@ var ( ) // NewBool creates and returns a concurrent-safe object for bool type, -// with given initial value . +// with given initial value `value`. func NewBool(value ...bool) *Bool { t := &Bool{} if len(value) > 0 { @@ -41,7 +41,7 @@ func (v *Bool) Clone() *Bool { return NewBool(v.Val()) } -// Set atomically stores into t.value and returns the previous value of t.value. +// Set atomically stores `value` into t.value and returns the previous value of t.value. func (v *Bool) Set(value bool) (old bool) { if value { old = atomic.SwapInt32(&v.value, 1) == 1 @@ -91,7 +91,7 @@ func (v *Bool) UnmarshalJSON(b []byte) error { return nil } -// UnmarshalValue is an interface implement which sets any type of value for . +// UnmarshalValue is an interface implement which sets any type of value for `v`. func (v *Bool) UnmarshalValue(value interface{}) error { v.Set(gconv.Bool(value)) return nil diff --git a/container/gtype/byte.go b/container/gtype/gtype_byte.go similarity index 85% rename from container/gtype/byte.go rename to container/gtype/gtype_byte.go index 3b2a8d09b..9315e529c 100644 --- a/container/gtype/byte.go +++ b/container/gtype/gtype_byte.go @@ -18,7 +18,7 @@ type Byte struct { } // NewByte creates and returns a concurrent-safe object for byte type, -// with given initial value . +// with given initial value `value`. func NewByte(value ...byte) *Byte { if len(value) > 0 { return &Byte{ @@ -33,7 +33,7 @@ func (v *Byte) Clone() *Byte { return NewByte(v.Val()) } -// Set atomically stores into t.value and returns the previous value of t.value. +// Set atomically stores `value` into t.value and returns the previous value of t.value. func (v *Byte) Set(value byte) (old byte) { return byte(atomic.SwapInt32(&v.value, int32(value))) } @@ -43,7 +43,7 @@ func (v *Byte) Val() byte { return byte(atomic.LoadInt32(&v.value)) } -// Add atomically adds to t.value and returns the new value. +// Add atomically adds `delta` to t.value and returns the new value. func (v *Byte) Add(delta byte) (new byte) { return byte(atomic.AddInt32(&v.value, int32(delta))) } @@ -60,16 +60,16 @@ func (v *Byte) String() string { // MarshalJSON implements the interface MarshalJSON for json.Marshal. func (v *Byte) MarshalJSON() ([]byte, error) { - return gconv.UnsafeStrToBytes(strconv.FormatUint(uint64(v.Val()), 10)), nil + return []byte(strconv.FormatUint(uint64(v.Val()), 10)), nil } // UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal. func (v *Byte) UnmarshalJSON(b []byte) error { - v.Set(gconv.Uint8(gconv.UnsafeBytesToStr(b))) + v.Set(gconv.Uint8(string(b))) return nil } -// UnmarshalValue is an interface implement which sets any type of value for . +// UnmarshalValue is an interface implement which sets any type of value for `v`. func (v *Byte) UnmarshalValue(value interface{}) error { v.Set(gconv.Byte(value)) return nil diff --git a/container/gtype/bytes.go b/container/gtype/gtype_bytes.go similarity index 88% rename from container/gtype/bytes.go rename to container/gtype/gtype_bytes.go index 9574558cb..9f91254ee 100644 --- a/container/gtype/bytes.go +++ b/container/gtype/gtype_bytes.go @@ -19,7 +19,7 @@ type Bytes struct { } // NewBytes creates and returns a concurrent-safe object for []byte type, -// with given initial value . +// with given initial value `value`. func NewBytes(value ...[]byte) *Bytes { t := &Bytes{} if len(value) > 0 { @@ -33,8 +33,8 @@ func (v *Bytes) Clone() *Bytes { return NewBytes(v.Val()) } -// Set atomically stores into t.value and returns the previous value of t.value. -// Note: The parameter cannot be nil. +// Set atomically stores `value` into t.value and returns the previous value of t.value. +// Note: The parameter `value` cannot be nil. func (v *Bytes) Set(value []byte) (old []byte) { old = v.Val() v.value.Store(value) @@ -59,7 +59,7 @@ func (v *Bytes) MarshalJSON() ([]byte, error) { val := v.Val() dst := make([]byte, base64.StdEncoding.EncodedLen(len(val))) base64.StdEncoding.Encode(dst, val) - return gconv.UnsafeStrToBytes(`"` + gconv.UnsafeBytesToStr(dst) + `"`), nil + return []byte(`"` + string(dst) + `"`), nil } // UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal. @@ -73,7 +73,7 @@ func (v *Bytes) UnmarshalJSON(b []byte) error { return nil } -// UnmarshalValue is an interface implement which sets any type of value for . +// UnmarshalValue is an interface implement which sets any type of value for `v`. func (v *Bytes) UnmarshalValue(value interface{}) error { v.Set(gconv.Bytes(value)) return nil diff --git a/container/gtype/float32.go b/container/gtype/gtype_float32.go similarity index 87% rename from container/gtype/float32.go rename to container/gtype/gtype_float32.go index 2eaeb8960..7da59ce87 100644 --- a/container/gtype/float32.go +++ b/container/gtype/gtype_float32.go @@ -20,7 +20,7 @@ type Float32 struct { } // NewFloat32 creates and returns a concurrent-safe object for float32 type, -// with given initial value . +// with given initial value `value`. func NewFloat32(value ...float32) *Float32 { if len(value) > 0 { return &Float32{ @@ -35,7 +35,7 @@ func (v *Float32) Clone() *Float32 { return NewFloat32(v.Val()) } -// Set atomically stores into t.value and returns the previous value of t.value. +// Set atomically stores `value` into t.value and returns the previous value of t.value. func (v *Float32) Set(value float32) (old float32) { return math.Float32frombits(atomic.SwapUint32(&v.value, math.Float32bits(value))) } @@ -45,7 +45,7 @@ func (v *Float32) Val() float32 { return math.Float32frombits(atomic.LoadUint32(&v.value)) } -// Add atomically adds to t.value and returns the new value. +// Add atomically adds `delta` to t.value and returns the new value. func (v *Float32) Add(delta float32) (new float32) { for { old := math.Float32frombits(v.value) @@ -73,16 +73,16 @@ func (v *Float32) String() string { // MarshalJSON implements the interface MarshalJSON for json.Marshal. func (v *Float32) MarshalJSON() ([]byte, error) { - return gconv.UnsafeStrToBytes(strconv.FormatFloat(float64(v.Val()), 'g', -1, 32)), nil + return []byte(strconv.FormatFloat(float64(v.Val()), 'g', -1, 32)), nil } // UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal. func (v *Float32) UnmarshalJSON(b []byte) error { - v.Set(gconv.Float32(gconv.UnsafeBytesToStr(b))) + v.Set(gconv.Float32(string(b))) return nil } -// UnmarshalValue is an interface implement which sets any type of value for . +// UnmarshalValue is an interface implement which sets any type of value for `v`. func (v *Float32) UnmarshalValue(value interface{}) error { v.Set(gconv.Float32(value)) return nil diff --git a/container/gtype/float64.go b/container/gtype/gtype_float64.go similarity index 87% rename from container/gtype/float64.go rename to container/gtype/gtype_float64.go index ecc80facc..340bdef00 100644 --- a/container/gtype/float64.go +++ b/container/gtype/gtype_float64.go @@ -20,7 +20,7 @@ type Float64 struct { } // NewFloat64 creates and returns a concurrent-safe object for float64 type, -// with given initial value . +// with given initial value `value`. func NewFloat64(value ...float64) *Float64 { if len(value) > 0 { return &Float64{ @@ -35,7 +35,7 @@ func (v *Float64) Clone() *Float64 { return NewFloat64(v.Val()) } -// Set atomically stores into t.value and returns the previous value of t.value. +// Set atomically stores `value` into t.value and returns the previous value of t.value. func (v *Float64) Set(value float64) (old float64) { return math.Float64frombits(atomic.SwapUint64(&v.value, math.Float64bits(value))) } @@ -45,7 +45,7 @@ func (v *Float64) Val() float64 { return math.Float64frombits(atomic.LoadUint64(&v.value)) } -// Add atomically adds to t.value and returns the new value. +// Add atomically adds `delta` to t.value and returns the new value. func (v *Float64) Add(delta float64) (new float64) { for { old := math.Float64frombits(v.value) @@ -73,16 +73,16 @@ func (v *Float64) String() string { // MarshalJSON implements the interface MarshalJSON for json.Marshal. func (v *Float64) MarshalJSON() ([]byte, error) { - return gconv.UnsafeStrToBytes(strconv.FormatFloat(v.Val(), 'g', -1, 64)), nil + return []byte(strconv.FormatFloat(v.Val(), 'g', -1, 64)), nil } // UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal. func (v *Float64) UnmarshalJSON(b []byte) error { - v.Set(gconv.Float64(gconv.UnsafeBytesToStr(b))) + v.Set(gconv.Float64(string(b))) return nil } -// UnmarshalValue is an interface implement which sets any type of value for . +// UnmarshalValue is an interface implement which sets any type of value for `v`. func (v *Float64) UnmarshalValue(value interface{}) error { v.Set(gconv.Float64(value)) return nil diff --git a/container/gtype/int.go b/container/gtype/gtype_int.go similarity index 86% rename from container/gtype/int.go rename to container/gtype/gtype_int.go index c1b2543f0..ca420e945 100644 --- a/container/gtype/int.go +++ b/container/gtype/gtype_int.go @@ -18,7 +18,7 @@ type Int struct { } // NewInt creates and returns a concurrent-safe object for int type, -// with given initial value . +// with given initial value `value`. func NewInt(value ...int) *Int { if len(value) > 0 { return &Int{ @@ -33,7 +33,7 @@ func (v *Int) Clone() *Int { return NewInt(v.Val()) } -// Set atomically stores into t.value and returns the previous value of t.value. +// Set atomically stores `value` into t.value and returns the previous value of t.value. func (v *Int) Set(value int) (old int) { return int(atomic.SwapInt64(&v.value, int64(value))) } @@ -43,7 +43,7 @@ func (v *Int) Val() int { return int(atomic.LoadInt64(&v.value)) } -// Add atomically adds to t.value and returns the new value. +// Add atomically adds `delta` to t.value and returns the new value. func (v *Int) Add(delta int) (new int) { return int(atomic.AddInt64(&v.value, int64(delta))) } @@ -60,16 +60,16 @@ func (v *Int) String() string { // MarshalJSON implements the interface MarshalJSON for json.Marshal. func (v *Int) MarshalJSON() ([]byte, error) { - return gconv.UnsafeStrToBytes(strconv.Itoa(v.Val())), nil + return []byte(strconv.Itoa(v.Val())), nil } // UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal. func (v *Int) UnmarshalJSON(b []byte) error { - v.Set(gconv.Int(gconv.UnsafeBytesToStr(b))) + v.Set(gconv.Int(string(b))) return nil } -// UnmarshalValue is an interface implement which sets any type of value for . +// UnmarshalValue is an interface implement which sets any type of value for `v`. func (v *Int) UnmarshalValue(value interface{}) error { v.Set(gconv.Int(value)) return nil diff --git a/container/gtype/int32.go b/container/gtype/gtype_int32.go similarity index 86% rename from container/gtype/int32.go rename to container/gtype/gtype_int32.go index 63d4a5d23..7c74a5b95 100644 --- a/container/gtype/int32.go +++ b/container/gtype/gtype_int32.go @@ -18,7 +18,7 @@ type Int32 struct { } // NewInt32 creates and returns a concurrent-safe object for int32 type, -// with given initial value . +// with given initial value `value`. func NewInt32(value ...int32) *Int32 { if len(value) > 0 { return &Int32{ @@ -33,7 +33,7 @@ func (v *Int32) Clone() *Int32 { return NewInt32(v.Val()) } -// Set atomically stores into t.value and returns the previous value of t.value. +// Set atomically stores `value` into t.value and returns the previous value of t.value. func (v *Int32) Set(value int32) (old int32) { return atomic.SwapInt32(&v.value, value) } @@ -43,7 +43,7 @@ func (v *Int32) Val() int32 { return atomic.LoadInt32(&v.value) } -// Add atomically adds to t.value and returns the new value. +// Add atomically adds `delta` to t.value and returns the new value. func (v *Int32) Add(delta int32) (new int32) { return atomic.AddInt32(&v.value, delta) } @@ -60,16 +60,16 @@ func (v *Int32) String() string { // MarshalJSON implements the interface MarshalJSON for json.Marshal. func (v *Int32) MarshalJSON() ([]byte, error) { - return gconv.UnsafeStrToBytes(strconv.Itoa(int(v.Val()))), nil + return []byte(strconv.Itoa(int(v.Val()))), nil } // UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal. func (v *Int32) UnmarshalJSON(b []byte) error { - v.Set(gconv.Int32(gconv.UnsafeBytesToStr(b))) + v.Set(gconv.Int32(string(b))) return nil } -// UnmarshalValue is an interface implement which sets any type of value for . +// UnmarshalValue is an interface implement which sets any type of value for `v`. func (v *Int32) UnmarshalValue(value interface{}) error { v.Set(gconv.Int32(value)) return nil diff --git a/container/gtype/int64.go b/container/gtype/gtype_int64.go similarity index 86% rename from container/gtype/int64.go rename to container/gtype/gtype_int64.go index b9c356ebd..92610455c 100644 --- a/container/gtype/int64.go +++ b/container/gtype/gtype_int64.go @@ -18,7 +18,7 @@ type Int64 struct { } // NewInt64 creates and returns a concurrent-safe object for int64 type, -// with given initial value . +// with given initial value `value`. func NewInt64(value ...int64) *Int64 { if len(value) > 0 { return &Int64{ @@ -33,7 +33,7 @@ func (v *Int64) Clone() *Int64 { return NewInt64(v.Val()) } -// Set atomically stores into t.value and returns the previous value of t.value. +// Set atomically stores `value` into t.value and returns the previous value of t.value. func (v *Int64) Set(value int64) (old int64) { return atomic.SwapInt64(&v.value, value) } @@ -43,7 +43,7 @@ func (v *Int64) Val() int64 { return atomic.LoadInt64(&v.value) } -// Add atomically adds to t.value and returns the new value. +// Add atomically adds `delta` to t.value and returns the new value. func (v *Int64) Add(delta int64) (new int64) { return atomic.AddInt64(&v.value, delta) } @@ -60,16 +60,16 @@ func (v *Int64) String() string { // MarshalJSON implements the interface MarshalJSON for json.Marshal. func (v *Int64) MarshalJSON() ([]byte, error) { - return gconv.UnsafeStrToBytes(strconv.FormatInt(v.Val(), 10)), nil + return []byte(strconv.FormatInt(v.Val(), 10)), nil } // UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal. func (v *Int64) UnmarshalJSON(b []byte) error { - v.Set(gconv.Int64(gconv.UnsafeBytesToStr(b))) + v.Set(gconv.Int64(string(b))) return nil } -// UnmarshalValue is an interface implement which sets any type of value for . +// UnmarshalValue is an interface implement which sets any type of value for `v`. func (v *Int64) UnmarshalValue(value interface{}) error { v.Set(gconv.Int64(value)) return nil diff --git a/container/gtype/interface.go b/container/gtype/gtype_interface.go similarity index 91% rename from container/gtype/interface.go rename to container/gtype/gtype_interface.go index 8cd554dde..a58ba9031 100644 --- a/container/gtype/interface.go +++ b/container/gtype/gtype_interface.go @@ -18,7 +18,7 @@ type Interface struct { } // NewInterface creates and returns a concurrent-safe object for interface{} type, -// with given initial value . +// with given initial value `value`. func NewInterface(value ...interface{}) *Interface { t := &Interface{} if len(value) > 0 && value[0] != nil { @@ -32,8 +32,8 @@ func (v *Interface) Clone() *Interface { return NewInterface(v.Val()) } -// Set atomically stores into t.value and returns the previous value of t.value. -// Note: The parameter cannot be nil. +// Set atomically stores `value` into t.value and returns the previous value of t.value. +// Note: The parameter `value` cannot be nil. func (v *Interface) Set(value interface{}) (old interface{}) { old = v.Val() v.value.Store(value) @@ -66,7 +66,7 @@ func (v *Interface) UnmarshalJSON(b []byte) error { return nil } -// UnmarshalValue is an interface implement which sets any type of value for . +// UnmarshalValue is an interface implement which sets any type of value for `v`. func (v *Interface) UnmarshalValue(value interface{}) error { v.Set(value) return nil diff --git a/container/gtype/string.go b/container/gtype/gtype_string.go similarity index 87% rename from container/gtype/string.go rename to container/gtype/gtype_string.go index 0e1483b6f..02803a09c 100644 --- a/container/gtype/string.go +++ b/container/gtype/gtype_string.go @@ -18,7 +18,7 @@ type String struct { } // NewString creates and returns a concurrent-safe object for string type, -// with given initial value . +// with given initial value `value`. func NewString(value ...string) *String { t := &String{} if len(value) > 0 { @@ -32,7 +32,7 @@ func (v *String) Clone() *String { return NewString(v.Val()) } -// Set atomically stores into t.value and returns the previous value of t.value. +// Set atomically stores `value` into t.value and returns the previous value of t.value. func (v *String) Set(value string) (old string) { old = v.Val() v.value.Store(value) @@ -55,16 +55,16 @@ func (v *String) String() string { // MarshalJSON implements the interface MarshalJSON for json.Marshal. func (v *String) MarshalJSON() ([]byte, error) { - return gconv.UnsafeStrToBytes(`"` + v.Val() + `"`), nil + return []byte(`"` + v.Val() + `"`), nil } // UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal. func (v *String) UnmarshalJSON(b []byte) error { - v.Set(gconv.UnsafeBytesToStr(bytes.Trim(b, `"`))) + v.Set(string(bytes.Trim(b, `"`))) return nil } -// UnmarshalValue is an interface implement which sets any type of value for . +// UnmarshalValue is an interface implement which sets any type of value for `v`. func (v *String) UnmarshalValue(value interface{}) error { v.Set(gconv.String(value)) return nil diff --git a/container/gtype/uint.go b/container/gtype/gtype_uint.go similarity index 85% rename from container/gtype/uint.go rename to container/gtype/gtype_uint.go index b9203a9af..613e09488 100644 --- a/container/gtype/uint.go +++ b/container/gtype/gtype_uint.go @@ -18,7 +18,7 @@ type Uint struct { } // NewUint creates and returns a concurrent-safe object for uint type, -// with given initial value . +// with given initial value `value`. func NewUint(value ...uint) *Uint { if len(value) > 0 { return &Uint{ @@ -33,7 +33,7 @@ func (v *Uint) Clone() *Uint { return NewUint(v.Val()) } -// Set atomically stores into t.value and returns the previous value of t.value. +// Set atomically stores `value` into t.value and returns the previous value of t.value. func (v *Uint) Set(value uint) (old uint) { return uint(atomic.SwapUint64(&v.value, uint64(value))) } @@ -43,7 +43,7 @@ func (v *Uint) Val() uint { return uint(atomic.LoadUint64(&v.value)) } -// Add atomically adds to t.value and returns the new value. +// Add atomically adds `delta` to t.value and returns the new value. func (v *Uint) Add(delta uint) (new uint) { return uint(atomic.AddUint64(&v.value, uint64(delta))) } @@ -60,16 +60,16 @@ func (v *Uint) String() string { // MarshalJSON implements the interface MarshalJSON for json.Marshal. func (v *Uint) MarshalJSON() ([]byte, error) { - return gconv.UnsafeStrToBytes(strconv.FormatUint(uint64(v.Val()), 10)), nil + return []byte(strconv.FormatUint(uint64(v.Val()), 10)), nil } // UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal. func (v *Uint) UnmarshalJSON(b []byte) error { - v.Set(gconv.Uint(gconv.UnsafeBytesToStr(b))) + v.Set(gconv.Uint(string(b))) return nil } -// UnmarshalValue is an interface implement which sets any type of value for . +// UnmarshalValue is an interface implement which sets any type of value for `v`. func (v *Uint) UnmarshalValue(value interface{}) error { v.Set(gconv.Uint(value)) return nil diff --git a/container/gtype/uint32.go b/container/gtype/gtype_uint32.go similarity index 85% rename from container/gtype/uint32.go rename to container/gtype/gtype_uint32.go index 2fbdcb030..d42133d75 100644 --- a/container/gtype/uint32.go +++ b/container/gtype/gtype_uint32.go @@ -18,7 +18,7 @@ type Uint32 struct { } // NewUint32 creates and returns a concurrent-safe object for uint32 type, -// with given initial value . +// with given initial value `value`. func NewUint32(value ...uint32) *Uint32 { if len(value) > 0 { return &Uint32{ @@ -33,7 +33,7 @@ func (v *Uint32) Clone() *Uint32 { return NewUint32(v.Val()) } -// Set atomically stores into t.value and returns the previous value of t.value. +// Set atomically stores `value` into t.value and returns the previous value of t.value. func (v *Uint32) Set(value uint32) (old uint32) { return atomic.SwapUint32(&v.value, value) } @@ -43,7 +43,7 @@ func (v *Uint32) Val() uint32 { return atomic.LoadUint32(&v.value) } -// Add atomically adds to t.value and returns the new value. +// Add atomically adds `delta` to t.value and returns the new value. func (v *Uint32) Add(delta uint32) (new uint32) { return atomic.AddUint32(&v.value, delta) } @@ -60,16 +60,16 @@ func (v *Uint32) String() string { // MarshalJSON implements the interface MarshalJSON for json.Marshal. func (v *Uint32) MarshalJSON() ([]byte, error) { - return gconv.UnsafeStrToBytes(strconv.FormatUint(uint64(v.Val()), 10)), nil + return []byte(strconv.FormatUint(uint64(v.Val()), 10)), nil } // UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal. func (v *Uint32) UnmarshalJSON(b []byte) error { - v.Set(gconv.Uint32(gconv.UnsafeBytesToStr(b))) + v.Set(gconv.Uint32(string(b))) return nil } -// UnmarshalValue is an interface implement which sets any type of value for . +// UnmarshalValue is an interface implement which sets any type of value for `v`. func (v *Uint32) UnmarshalValue(value interface{}) error { v.Set(gconv.Uint32(value)) return nil diff --git a/container/gtype/uint64.go b/container/gtype/gtype_uint64.go similarity index 86% rename from container/gtype/uint64.go rename to container/gtype/gtype_uint64.go index 580163bb5..01a4a3346 100644 --- a/container/gtype/uint64.go +++ b/container/gtype/gtype_uint64.go @@ -18,7 +18,7 @@ type Uint64 struct { } // NewUint64 creates and returns a concurrent-safe object for uint64 type, -// with given initial value . +// with given initial value `value`. func NewUint64(value ...uint64) *Uint64 { if len(value) > 0 { return &Uint64{ @@ -33,7 +33,7 @@ func (v *Uint64) Clone() *Uint64 { return NewUint64(v.Val()) } -// Set atomically stores into t.value and returns the previous value of t.value. +// Set atomically stores `value` into t.value and returns the previous value of t.value. func (v *Uint64) Set(value uint64) (old uint64) { return atomic.SwapUint64(&v.value, value) } @@ -43,7 +43,7 @@ func (v *Uint64) Val() uint64 { return atomic.LoadUint64(&v.value) } -// Add atomically adds to t.value and returns the new value. +// Add atomically adds `delta` to t.value and returns the new value. func (v *Uint64) Add(delta uint64) (new uint64) { return atomic.AddUint64(&v.value, delta) } @@ -60,16 +60,16 @@ func (v *Uint64) String() string { // MarshalJSON implements the interface MarshalJSON for json.Marshal. func (v *Uint64) MarshalJSON() ([]byte, error) { - return gconv.UnsafeStrToBytes(strconv.FormatUint(v.Val(), 10)), nil + return []byte(strconv.FormatUint(v.Val(), 10)), nil } // UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal. func (v *Uint64) UnmarshalJSON(b []byte) error { - v.Set(gconv.Uint64(gconv.UnsafeBytesToStr(b))) + v.Set(gconv.Uint64(string(b))) return nil } -// UnmarshalValue is an interface implement which sets any type of value for . +// UnmarshalValue is an interface implement which sets any type of value for `v`. func (v *Uint64) UnmarshalValue(value interface{}) error { v.Set(gconv.Uint64(value)) return nil diff --git a/container/gtype/z_bench_basic_test.go b/container/gtype/gtype_z_bench_basic_test.go similarity index 100% rename from container/gtype/z_bench_basic_test.go rename to container/gtype/gtype_z_bench_basic_test.go diff --git a/container/gtype/z_bench_json_test.go b/container/gtype/gtype_z_bench_json_test.go similarity index 100% rename from container/gtype/z_bench_json_test.go rename to container/gtype/gtype_z_bench_json_test.go diff --git a/container/gtype/z_unit_bool_test.go b/container/gtype/gtype_z_unit_bool_test.go similarity index 100% rename from container/gtype/z_unit_bool_test.go rename to container/gtype/gtype_z_unit_bool_test.go diff --git a/container/gtype/z_unit_byte_test.go b/container/gtype/gtype_z_unit_byte_test.go similarity index 100% rename from container/gtype/z_unit_byte_test.go rename to container/gtype/gtype_z_unit_byte_test.go diff --git a/container/gtype/z_unit_bytes_test.go b/container/gtype/gtype_z_unit_bytes_test.go similarity index 100% rename from container/gtype/z_unit_bytes_test.go rename to container/gtype/gtype_z_unit_bytes_test.go diff --git a/container/gtype/z_unit_float32_test.go b/container/gtype/gtype_z_unit_float32_test.go similarity index 100% rename from container/gtype/z_unit_float32_test.go rename to container/gtype/gtype_z_unit_float32_test.go diff --git a/container/gtype/z_unit_float64_test.go b/container/gtype/gtype_z_unit_float64_test.go similarity index 100% rename from container/gtype/z_unit_float64_test.go rename to container/gtype/gtype_z_unit_float64_test.go diff --git a/container/gtype/z_unit_int32_test.go b/container/gtype/gtype_z_unit_int32_test.go similarity index 100% rename from container/gtype/z_unit_int32_test.go rename to container/gtype/gtype_z_unit_int32_test.go diff --git a/container/gtype/z_unit_int64_test.go b/container/gtype/gtype_z_unit_int64_test.go similarity index 100% rename from container/gtype/z_unit_int64_test.go rename to container/gtype/gtype_z_unit_int64_test.go diff --git a/container/gtype/z_unit_int_test.go b/container/gtype/gtype_z_unit_int_test.go similarity index 100% rename from container/gtype/z_unit_int_test.go rename to container/gtype/gtype_z_unit_int_test.go diff --git a/container/gtype/z_unit_interface_test.go b/container/gtype/gtype_z_unit_interface_test.go similarity index 100% rename from container/gtype/z_unit_interface_test.go rename to container/gtype/gtype_z_unit_interface_test.go diff --git a/container/gtype/z_unit_string_test.go b/container/gtype/gtype_z_unit_string_test.go similarity index 100% rename from container/gtype/z_unit_string_test.go rename to container/gtype/gtype_z_unit_string_test.go diff --git a/container/gtype/z_unit_uint32_test.go b/container/gtype/gtype_z_unit_uint32_test.go similarity index 100% rename from container/gtype/z_unit_uint32_test.go rename to container/gtype/gtype_z_unit_uint32_test.go diff --git a/container/gtype/z_unit_uint64_test.go b/container/gtype/gtype_z_unit_uint64_test.go similarity index 100% rename from container/gtype/z_unit_uint64_test.go rename to container/gtype/gtype_z_unit_uint64_test.go diff --git a/container/gtype/z_unit_uint_test.go b/container/gtype/gtype_z_unit_uint_test.go similarity index 100% rename from container/gtype/z_unit_uint_test.go rename to container/gtype/gtype_z_unit_uint_test.go diff --git a/crypto/gaes/gaes.go b/crypto/gaes/gaes.go index 43bc0600a..4048311f4 100644 --- a/crypto/gaes/gaes.go +++ b/crypto/gaes/gaes.go @@ -31,9 +31,9 @@ func Decrypt(cipherText []byte, key []byte, iv ...[]byte) ([]byte, error) { return DecryptCBC(cipherText, key, iv...) } -// EncryptCBC encrypts

using CBC mode. +// EncryptCBC encrypts `plainText` using CBC mode. // Note that the key must be 16/24/32 bit length. -// The parameter <iv> initialization vector is unnecessary. +// The parameter `iv` initialization vector is unnecessary. func EncryptCBC(plainText []byte, key []byte, iv ...[]byte) ([]byte, error) { block, err := aes.NewCipher(key) if err != nil { @@ -54,9 +54,9 @@ func EncryptCBC(plainText []byte, key []byte, iv ...[]byte) ([]byte, error) { return cipherText, nil } -// DecryptCBC decrypts <cipherText> using CBC mode. +// DecryptCBC decrypts `cipherText` using CBC mode. // Note that the key must be 16/24/32 bit length. -// The parameter <iv> initialization vector is unnecessary. +// The parameter `iv` initialization vector is unnecessary. func DecryptCBC(cipherText []byte, key []byte, iv ...[]byte) ([]byte, error) { block, err := aes.NewCipher(key) if err != nil { @@ -116,9 +116,9 @@ func PKCS5UnPadding(src []byte, blockSize int) ([]byte, error) { return src[:(length - unpadding)], nil } -// EncryptCFB encrypts <plainText> using CFB mode. +// EncryptCFB encrypts `plainText` using CFB mode. // Note that the key must be 16/24/32 bit length. -// The parameter <iv> initialization vector is unnecessary. +// The parameter `iv` initialization vector is unnecessary. func EncryptCFB(plainText []byte, key []byte, padding *int, iv ...[]byte) ([]byte, error) { block, err := aes.NewCipher(key) if err != nil { @@ -138,9 +138,9 @@ func EncryptCFB(plainText []byte, key []byte, padding *int, iv ...[]byte) ([]byt return cipherText, nil } -// DecryptCFB decrypts <plainText> using CFB mode. +// DecryptCFB decrypts `plainText` using CFB mode. // Note that the key must be 16/24/32 bit length. -// The parameter <iv> initialization vector is unnecessary. +// The parameter `iv` initialization vector is unnecessary. func DecryptCFB(cipherText []byte, key []byte, unPadding int, iv ...[]byte) ([]byte, error) { block, err := aes.NewCipher(key) if err != nil { diff --git a/crypto/gcrc32/gcrc32.go b/crypto/gcrc32/gcrc32.go index 59b193bd2..64ed4f4a4 100644 --- a/crypto/gcrc32/gcrc32.go +++ b/crypto/gcrc32/gcrc32.go @@ -14,7 +14,7 @@ import ( ) // Encrypt encrypts any type of variable using CRC32 algorithms. -// It uses gconv package to convert <v> to its bytes type. +// It uses gconv package to convert `v` to its bytes type. func Encrypt(v interface{}) uint32 { return crc32.ChecksumIEEE(gconv.Bytes(v)) } diff --git a/crypto/gdes/gdes.go b/crypto/gdes/gdes.go index 8b00e1a7c..ff7a358e2 100644 --- a/crypto/gdes/gdes.go +++ b/crypto/gdes/gdes.go @@ -20,7 +20,7 @@ const ( PKCS5PADDING ) -// EncryptECB encrypts <plainText> using ECB mode. +// EncryptECB encrypts `plainText` using ECB mode. func EncryptECB(plainText []byte, key []byte, padding int) ([]byte, error) { text, err := Padding(plainText, padding) if err != nil { @@ -42,7 +42,7 @@ func EncryptECB(plainText []byte, key []byte, padding int) ([]byte, error) { return cipherText, nil } -// DecryptECB decrypts <cipherText> using ECB mode. +// DecryptECB decrypts `cipherText` using ECB mode. func DecryptECB(cipherText []byte, key []byte, padding int) ([]byte, error) { text := make([]byte, len(cipherText)) block, err := des.NewCipher(key) @@ -63,8 +63,8 @@ func DecryptECB(cipherText []byte, key []byte, padding int) ([]byte, error) { return plainText, nil } -// EncryptECBTriple encrypts <plainText> using TripleDES and ECB mode. -// The length of the <key> should be either 16 or 24 bytes. +// EncryptECBTriple encrypts `plainText` using TripleDES and ECB mode. +// The length of the `key` should be either 16 or 24 bytes. func EncryptECBTriple(plainText []byte, key []byte, padding int) ([]byte, error) { if len(key) != 16 && len(key) != 24 { return nil, gerror.NewCode(gcode.CodeInvalidParameter, "key length error") @@ -97,8 +97,8 @@ func EncryptECBTriple(plainText []byte, key []byte, padding int) ([]byte, error) return cipherText, nil } -// DecryptECBTriple decrypts <cipherText> using TripleDES and ECB mode. -// The length of the <key> should be either 16 or 24 bytes. +// DecryptECBTriple decrypts `cipherText` using TripleDES and ECB mode. +// The length of the `key` should be either 16 or 24 bytes. func DecryptECBTriple(cipherText []byte, key []byte, padding int) ([]byte, error) { if len(key) != 16 && len(key) != 24 { return nil, gerror.NewCode(gcode.CodeInvalidParameter, "key length error") @@ -131,7 +131,7 @@ func DecryptECBTriple(cipherText []byte, key []byte, padding int) ([]byte, error return plainText, nil } -// EncryptCBC encrypts <plainText> using CBC mode. +// EncryptCBC encrypts `plainText` using CBC mode. func EncryptCBC(plainText []byte, key []byte, iv []byte, padding int) ([]byte, error) { block, err := des.NewCipher(key) if err != nil { @@ -154,7 +154,7 @@ func EncryptCBC(plainText []byte, key []byte, iv []byte, padding int) ([]byte, e return cipherText, nil } -// DecryptCBC decrypts <cipherText> using CBC mode. +// DecryptCBC decrypts `cipherText` using CBC mode. func DecryptCBC(cipherText []byte, key []byte, iv []byte, padding int) ([]byte, error) { block, err := des.NewCipher(key) if err != nil { @@ -177,7 +177,7 @@ func DecryptCBC(cipherText []byte, key []byte, iv []byte, padding int) ([]byte, return plainText, nil } -// EncryptCBCTriple encrypts <plainText> using TripleDES and CBC mode. +// EncryptCBCTriple encrypts `plainText` using TripleDES and CBC mode. func EncryptCBCTriple(plainText []byte, key []byte, iv []byte, padding int) ([]byte, error) { if len(key) != 16 && len(key) != 24 { return nil, gerror.NewCode(gcode.CodeInvalidParameter, "key length invalid") @@ -212,7 +212,7 @@ func EncryptCBCTriple(plainText []byte, key []byte, iv []byte, padding int) ([]b return cipherText, nil } -// DecryptCBCTriple decrypts <cipherText> using TripleDES and CBC mode. +// DecryptCBCTriple decrypts `cipherText` using TripleDES and CBC mode. func DecryptCBCTriple(cipherText []byte, key []byte, iv []byte, padding int) ([]byte, error) { if len(key) != 16 && len(key) != 24 { return nil, gerror.NewCode(gcode.CodeInvalidParameter, "key length invalid") diff --git a/crypto/gmd5/gmd5.go b/crypto/gmd5/gmd5.go index ab16f1cf7..9f35b87d5 100644 --- a/crypto/gmd5/gmd5.go +++ b/crypto/gmd5/gmd5.go @@ -17,13 +17,13 @@ import ( ) // Encrypt encrypts any type of variable using MD5 algorithms. -// It uses gconv package to convert <v> to its bytes type. +// It uses gconv package to convert `v` to its bytes type. func Encrypt(data interface{}) (encrypt string, err error) { return EncryptBytes(gconv.Bytes(data)) } // MustEncrypt encrypts any type of variable using MD5 algorithms. -// It uses gconv package to convert <v> to its bytes type. +// It uses gconv package to convert `v` to its bytes type. // It panics if any error occurs. func MustEncrypt(data interface{}) string { result, err := Encrypt(data) @@ -33,7 +33,7 @@ func MustEncrypt(data interface{}) string { return result } -// EncryptBytes encrypts <data> using MD5 algorithms. +// EncryptBytes encrypts `data` using MD5 algorithms. func EncryptBytes(data []byte) (encrypt string, err error) { h := md5.New() if _, err = h.Write([]byte(data)); err != nil { @@ -42,7 +42,7 @@ func EncryptBytes(data []byte) (encrypt string, err error) { return fmt.Sprintf("%x", h.Sum(nil)), nil } -// MustEncryptBytes encrypts <data> using MD5 algorithms. +// MustEncryptBytes encrypts `data` using MD5 algorithms. // It panics if any error occurs. func MustEncryptBytes(data []byte) string { result, err := EncryptBytes(data) @@ -52,12 +52,12 @@ func MustEncryptBytes(data []byte) string { return result } -// EncryptBytes encrypts string <data> using MD5 algorithms. +// EncryptBytes encrypts string `data` using MD5 algorithms. func EncryptString(data string) (encrypt string, err error) { return EncryptBytes([]byte(data)) } -// MustEncryptString encrypts string <data> using MD5 algorithms. +// MustEncryptString encrypts string `data` using MD5 algorithms. // It panics if any error occurs. func MustEncryptString(data string) string { result, err := EncryptString(data) @@ -67,7 +67,7 @@ func MustEncryptString(data string) string { return result } -// EncryptFile encrypts file content of <path> using MD5 algorithms. +// EncryptFile encrypts file content of `path` using MD5 algorithms. func EncryptFile(path string) (encrypt string, err error) { f, err := os.Open(path) if err != nil { @@ -82,7 +82,7 @@ func EncryptFile(path string) (encrypt string, err error) { return fmt.Sprintf("%x", h.Sum(nil)), nil } -// MustEncryptFile encrypts file content of <path> using MD5 algorithms. +// MustEncryptFile encrypts file content of `path` using MD5 algorithms. // It panics if any error occurs. func MustEncryptFile(path string) string { result, err := EncryptFile(path) diff --git a/crypto/gsha1/gsha1.go b/crypto/gsha1/gsha1.go index 7f8b6347f..50beeeb58 100644 --- a/crypto/gsha1/gsha1.go +++ b/crypto/gsha1/gsha1.go @@ -17,13 +17,13 @@ import ( ) // Encrypt encrypts any type of variable using SHA1 algorithms. -// It uses gconv package to convert <v> to its bytes type. +// It uses package gconv to convert `v` to its bytes type. func Encrypt(v interface{}) string { r := sha1.Sum(gconv.Bytes(v)) return hex.EncodeToString(r[:]) } -// EncryptFile encrypts file content of <path> using SHA1 algorithms. +// EncryptFile encrypts file content of `path` using SHA1 algorithms. func EncryptFile(path string) (encrypt string, err error) { f, err := os.Open(path) if err != nil { @@ -38,7 +38,7 @@ func EncryptFile(path string) (encrypt string, err error) { return hex.EncodeToString(h.Sum(nil)), nil } -// MustEncryptFile encrypts file content of <path> using SHA1 algorithms. +// MustEncryptFile encrypts file content of `path` using SHA1 algorithms. // It panics if any error occurs. func MustEncryptFile(path string) string { result, err := EncryptFile(path) diff --git a/database/gdb/gdb_core.go b/database/gdb/gdb_core.go index 58519e927..1f84516c5 100644 --- a/database/gdb/gdb_core.go +++ b/database/gdb/gdb_core.go @@ -205,20 +205,21 @@ func (c *Core) GetScan(pointer interface{}, sql string, args ...interface{}) err t := reflect.TypeOf(pointer) k := t.Kind() if k != reflect.Ptr { - return fmt.Errorf("params should be type of pointer, but got: %v", k) + return gerror.NewCodef(gcode.CodeInvalidParameter, "params should be type of pointer, but got: %v", k) } k = t.Elem().Kind() switch k { case reflect.Array, reflect.Slice: return c.db.GetCore().GetStructs(pointer, sql, args...) + case reflect.Struct: return c.db.GetCore().GetStruct(pointer, sql, args...) } - return fmt.Errorf("element type should be type of struct/slice, unsupported: %v", k) + return gerror.NewCodef(gcode.CodeInvalidParameter, "element type should be type of struct/slice, unsupported: %v", k) } // GetValue queries and returns the field value from database. -// The sql should queries only one field from database, or else it returns only one +// The sql should query only one field from database, or else it returns only one // field of the result. func (c *Core) GetValue(sql string, args ...interface{}) (Value, error) { one, err := c.db.GetOne(sql, args...) @@ -392,7 +393,7 @@ func (c *Core) DoInsert(ctx context.Context, link Link, table string, list List, params []interface{} // Values that will be committed to underlying database driver. onDuplicateStr string // onDuplicateStr is used in "ON DUPLICATE KEY UPDATE" statement. ) - // Handle the field names and place holders. + // Handle the field names and placeholders. for k, _ := range list[0] { keys = append(keys, k) } @@ -423,7 +424,7 @@ func (c *Core) DoInsert(ctx context.Context, link Link, table string, list List, } } valueHolder = append(valueHolder, "("+gstr.Join(values, ",")+")") - // Batch package checks: It meets the batch number or it is the last element. + // Batch package checks: It meets the batch number, or it is the last element. if len(valueHolder) == option.BatchCount || (i == listLength-1 && len(valueHolder) > 0) { r, err := c.db.DoExec(ctx, link, fmt.Sprintf( "%s INTO %s(%s) VALUES%s %s", diff --git a/database/gdb/gdb_core_transaction.go b/database/gdb/gdb_core_transaction.go index 0252f1096..476fc9465 100644 --- a/database/gdb/gdb_core_transaction.go +++ b/database/gdb/gdb_core_transaction.go @@ -9,7 +9,8 @@ package gdb import ( "context" "database/sql" - "fmt" + "github.com/gogf/gf/errors/gcode" + "github.com/gogf/gf/errors/gerror" "reflect" "github.com/gogf/gf/container/gtype" @@ -117,8 +118,12 @@ func (c *Core) Transaction(ctx context.Context, f func(ctx context.Context, tx * tx.ctx = WithTX(tx.ctx, tx) defer func() { if err == nil { - if e := recover(); e != nil { - err = fmt.Errorf("%v", e) + if exception := recover(); exception != nil { + if v, ok := exception.(error); ok && gerror.HasStack(v) { + err = v + } else { + err = gerror.NewCodef(gcode.CodeInternalError, "%+v", exception) + } } } if err != nil { @@ -307,8 +312,12 @@ func (tx *TX) Transaction(ctx context.Context, f func(ctx context.Context, tx *T } defer func() { if err == nil { - if e := recover(); e != nil { - err = fmt.Errorf("%v", e) + if exception := recover(); exception != nil { + if v, ok := exception.(error); ok && gerror.HasStack(v) { + err = v + } else { + err = gerror.NewCodef(gcode.CodeInternalError, "%+v", exception) + } } } if err != nil { @@ -398,21 +407,21 @@ func (tx *TX) GetScan(pointer interface{}, sql string, args ...interface{}) erro t := reflect.TypeOf(pointer) k := t.Kind() if k != reflect.Ptr { - return fmt.Errorf("params should be type of pointer, but got: %v", k) + return gerror.NewCodef(gcode.CodeInvalidParameter, "params should be type of pointer, but got: %v", k) } k = t.Elem().Kind() switch k { case reflect.Array, reflect.Slice: return tx.GetStructs(pointer, sql, args...) + case reflect.Struct: return tx.GetStruct(pointer, sql, args...) - default: - return fmt.Errorf("element type should be type of struct/slice, unsupported: %v", k) } + return gerror.NewCodef(gcode.CodeInvalidParameter, "element type should be type of struct/slice, unsupported: %v", k) } // GetValue queries and returns the field value from database. -// The sql should queries only one field from database, or else it returns only one +// The sql should query only one field from database, or else it returns only one // field of the result. func (tx *TX) GetValue(sql string, args ...interface{}) (Value, error) { one, err := tx.GetOne(sql, args...) diff --git a/database/gdb/gdb_func.go b/database/gdb/gdb_func.go index 87c6e8763..6b18b2c26 100644 --- a/database/gdb/gdb_func.go +++ b/database/gdb/gdb_func.go @@ -31,28 +31,28 @@ import ( "github.com/gogf/gf/util/gconv" ) -// apiString is the type assert api for String. -type apiString interface { +// iString is the type assert api for String. +type iString interface { String() string } -// apiIterator is the type assert api for Iterator. -type apiIterator interface { +// iIterator is the type assert api for Iterator. +type iIterator interface { Iterator(f func(key, value interface{}) bool) } -// apiInterfaces is the type assert api for Interfaces. -type apiInterfaces interface { +// iInterfaces is the type assert api for Interfaces. +type iInterfaces interface { Interfaces() []interface{} } -// apiMapStrAny is the interface support for converting struct parameter to map. -type apiMapStrAny interface { +// iMapStrAny is the interface support for converting struct parameter to map. +type iMapStrAny interface { MapStrAny() map[string]interface{} } -// apiTableName is the interface for retrieving table name fro struct. -type apiTableName interface { +// iTableName is the interface for retrieving table name fro struct. +type iTableName interface { TableName() string } @@ -104,7 +104,7 @@ func (m *Model) guessPrimaryTableName(tableStr string) string { func getTableNameFromOrmTag(object interface{}) string { var tableName string // Use the interface value. - if r, ok := object.(apiTableName); ok { + if r, ok := object.(iTableName); ok { tableName = r.TableName() } // User meta data tag "orm". @@ -222,7 +222,7 @@ func ConvertDataForTableRecord(value interface{}) map[string]interface{} { default: // Use string conversion in default. - if s, ok := v.(apiString); ok { + if s, ok := v.(iString); ok { data[k] = s.String() } else { // Convert the value to JSON. @@ -246,7 +246,7 @@ func DataToMapDeep(value interface{}) map[string]interface{} { default: // Use string conversion in default. - if s, ok := v.(apiString); ok { + if s, ok := v.(iString); ok { m[k] = s.String() } else { m[k] = v @@ -457,11 +457,11 @@ func formatWhere(db DB, in formatWhereInput) (newWhere string, newArgs []interfa } case reflect.Struct: - // If `where` struct implements apiIterator interface, + // If `where` struct implements iIterator interface, // it then uses its Iterate function to iterate its key-value pairs. // For example, ListMap and TreeMap are ordered map, - // which implement apiIterator interface and are index-friendly for where conditions. - if iterator, ok := in.Where.(apiIterator); ok { + // which implement iIterator interface and are index-friendly for where conditions. + if iterator, ok := in.Where.(iIterator); ok { iterator.Iterator(func(key, value interface{}) bool { ketStr := gconv.String(key) if gregex.IsMatchString(regularFieldNameRegPattern, ketStr) { @@ -764,7 +764,7 @@ func handleArguments(sql string, args []interface{}) (newSql string, newArgs []i default: // It converts the struct to string in default // if it has implemented the String interface. - if v, ok := arg.(apiString); ok { + if v, ok := arg.(iString); ok { newArgs = append(newArgs, v.String()) continue } diff --git a/database/gdb/gdb_model.go b/database/gdb/gdb_model.go index e7d4f823f..717ab6e01 100644 --- a/database/gdb/gdb_model.go +++ b/database/gdb/gdb_model.go @@ -57,7 +57,7 @@ type Model struct { type ModelHandler func(m *Model) *Model // ChunkHandler is a function that is used in function Chunk, which handles given Result and error. -// It returns true if it wants continue chunking, or else it returns false to stop chunking. +// It returns true if it wants to continue chunking, or else it returns false to stop chunking. type ChunkHandler func(result Result, err error) bool // ModelWhereHolder is the holder for where condition preparing. diff --git a/database/gdb/gdb_model_cache.go b/database/gdb/gdb_model_cache.go index b9ba72873..da485db4b 100644 --- a/database/gdb/gdb_model_cache.go +++ b/database/gdb/gdb_model_cache.go @@ -7,6 +7,7 @@ package gdb import ( + "github.com/gogf/gf/internal/intlog" "time" ) @@ -38,6 +39,10 @@ func (m *Model) Cache(duration time.Duration, name ...string) *Model { // cache feature is enabled. func (m *Model) checkAndRemoveCache() { if m.cacheEnabled && m.cacheDuration < 0 && len(m.cacheName) > 0 { - m.db.GetCache().Ctx(m.GetCtx()).Remove(m.cacheName) + var ctx = m.GetCtx() + _, err := m.db.GetCache().Remove(ctx, m.cacheName) + if err != nil { + intlog.Error(ctx, err) + } } } diff --git a/database/gdb/gdb_model_condition.go b/database/gdb/gdb_model_condition.go index 2ff16eb4c..9a6d4ac50 100644 --- a/database/gdb/gdb_model_condition.go +++ b/database/gdb/gdb_model_condition.go @@ -62,7 +62,7 @@ func (m *Model) WherePri(where interface{}, args ...interface{}) *Model { } // Wheref builds condition string using fmt.Sprintf and arguments. -// Note that if the number of `args` is more than the place holder in `format`, +// Note that if the number of `args` is more than the placeholder in `format`, // the extra `args` will be used as the where condition arguments of the Model. func (m *Model) Wheref(format string, args ...interface{}) *Model { var ( diff --git a/database/gdb/gdb_model_fields.go b/database/gdb/gdb_model_fields.go index a4115039e..0238e8d20 100644 --- a/database/gdb/gdb_model_fields.go +++ b/database/gdb/gdb_model_fields.go @@ -9,6 +9,8 @@ package gdb import ( "fmt" "github.com/gogf/gf/container/gset" + "github.com/gogf/gf/errors/gcode" + "github.com/gogf/gf/errors/gerror" "github.com/gogf/gf/text/gstr" "github.com/gogf/gf/util/gconv" "github.com/gogf/gf/util/gutil" @@ -247,7 +249,7 @@ func (m *Model) HasField(field string) (bool, error) { return false, err } if len(tableFields) == 0 { - return false, fmt.Errorf(`empty table fields for table "%s"`, m.tables) + return false, gerror.NewCodef(gcode.CodeNotFound, `empty table fields for table "%s"`, m.tables) } fieldsArray := make([]string, len(tableFields)) for k, v := range tableFields { diff --git a/database/gdb/gdb_model_insert.go b/database/gdb/gdb_model_insert.go index 78099b4e6..47fe25045 100644 --- a/database/gdb/gdb_model_insert.go +++ b/database/gdb/gdb_model_insert.go @@ -88,7 +88,7 @@ func (m *Model) Data(data ...interface{}) *Model { model.data = ConvertDataForTableRecord(data[0]) case reflect.Struct: - if v, ok := data[0].(apiInterfaces); ok { + if v, ok := data[0].(iInterfaces); ok { var ( array = v.Interfaces() list = make(List, len(array)) @@ -265,7 +265,7 @@ func (m *Model) doInsertWithOption(insertOption int) (result sql.Result, err err list = List{ConvertDataForTableRecord(value)} case reflect.Struct: - if v, ok := value.(apiInterfaces); ok { + if v, ok := value.(iInterfaces); ok { var ( array = v.Interfaces() ) diff --git a/database/gdb/gdb_model_select.go b/database/gdb/gdb_model_select.go index eefbec99b..eaadc8208 100644 --- a/database/gdb/gdb_model_select.go +++ b/database/gdb/gdb_model_select.go @@ -226,7 +226,11 @@ func (m *Model) doStruct(pointer interface{}, where ...interface{}) error { model := m // Auto selecting fields by struct attributes. if model.fieldsEx == "" && (model.fields == "" || model.fields == "*") { - model = m.Fields(pointer) + if v, ok := pointer.(reflect.Value); ok { + model = m.Fields(v.Interface()) + } else { + model = m.Fields(pointer) + } } one, err := model.One(where...) if err != nil { @@ -267,11 +271,19 @@ func (m *Model) doStructs(pointer interface{}, where ...interface{}) error { model := m // Auto selecting fields by struct attributes. if model.fieldsEx == "" && (model.fields == "" || model.fields == "*") { - model = m.Fields( - reflect.New( - reflect.ValueOf(pointer).Elem().Type().Elem(), - ).Interface(), - ) + if v, ok := pointer.(reflect.Value); ok { + model = m.Fields( + reflect.New( + v.Type().Elem(), + ).Interface(), + ) + } else { + model = m.Fields( + reflect.New( + reflect.ValueOf(pointer).Elem().Type().Elem(), + ).Interface(), + ) + } } all, err := model.All(where...) if err != nil { @@ -323,7 +335,6 @@ func (m *Model) Scan(pointer interface{}, where ...interface{}) error { reflectValue = reflectValue.Elem() reflectKind = reflectValue.Kind() } - switch reflectKind { case reflect.Slice, reflect.Array: return m.doStructs(pointer, where...) @@ -520,15 +531,18 @@ func (m *Model) UnionAll(unions ...*Model) *Model { // doGetAllBySql does the select statement on the database. func (m *Model) doGetAllBySql(sql string, args ...interface{}) (result Result, err error) { - cacheKey := "" - cacheObj := m.db.GetCache().Ctx(m.GetCtx()) + var ( + ctx = m.GetCtx() + cacheKey = "" + cacheObj = m.db.GetCache() + ) // Retrieve from cache. if m.cacheEnabled && m.tx == nil { cacheKey = m.cacheName if len(cacheKey) == 0 { cacheKey = sql + ", @PARAMS:" + gconv.String(args) } - if v, _ := cacheObj.GetVar(cacheKey); !v.IsNil() { + if v, _ := cacheObj.Get(ctx, cacheKey); !v.IsNil() { if result, ok := v.Val().(Result); ok { // In-memory cache. return result, nil @@ -549,7 +563,7 @@ func (m *Model) doGetAllBySql(sql string, args ...interface{}) (result Result, e // Cache the result. if cacheKey != "" && err == nil { if m.cacheDuration < 0 { - if _, err := cacheObj.Remove(cacheKey); err != nil { + if _, err := cacheObj.Remove(ctx, cacheKey); err != nil { intlog.Error(m.GetCtx(), err) } } else { @@ -557,7 +571,7 @@ func (m *Model) doGetAllBySql(sql string, args ...interface{}) (result Result, e if result == nil { result = Result{} } - if err := cacheObj.Set(cacheKey, result, m.cacheDuration); err != nil { + if err := cacheObj.Set(ctx, cacheKey, result, m.cacheDuration); err != nil { intlog.Error(m.GetCtx(), err) } } diff --git a/database/gdb/gdb_model_with.go b/database/gdb/gdb_model_with.go index 36782fffc..014df31a5 100644 --- a/database/gdb/gdb_model_with.go +++ b/database/gdb/gdb_model_with.go @@ -155,12 +155,10 @@ func (m *Model) doWithScanStruct(pointer interface{}) error { if parsedTagOutput.Order != "" { model = model.Order(parsedTagOutput.Order) } - err = model.Fields(fieldKeys).Where(relatedSourceName, relatedTargetValue).Scan(bindToReflectValue) if err != nil { return err } - } return nil } diff --git a/database/gdb/gdb_type_record.go b/database/gdb/gdb_type_record.go index eff35a1f4..e5c471892 100644 --- a/database/gdb/gdb_type_record.go +++ b/database/gdb/gdb_type_record.go @@ -14,21 +14,16 @@ import ( "github.com/gogf/gf/util/gconv" ) -// Interface converts and returns `r` as type of interface{}. -func (r Record) Interface() interface{} { - return r -} - // Json converts `r` to JSON format content. func (r Record) Json() string { content, _ := gparser.VarToJson(r.Map()) - return gconv.UnsafeBytesToStr(content) + return string(content) } // Xml converts `r` to XML format content. func (r Record) Xml(rootTag ...string) string { content, _ := gparser.VarToXml(r.Map(), rootTag...) - return gconv.UnsafeBytesToStr(content) + return string(content) } // Map converts `r` to map[string]interface{}. diff --git a/database/gdb/gdb_type_result.go b/database/gdb/gdb_type_result.go index cfe1ba92a..619cd33c5 100644 --- a/database/gdb/gdb_type_result.go +++ b/database/gdb/gdb_type_result.go @@ -13,11 +13,6 @@ import ( "math" ) -// Interface converts and returns `r` as type of interface{}. -func (r Result) Interface() interface{} { - return r -} - // IsEmpty checks and returns whether `r` is empty. func (r Result) IsEmpty() bool { return r.Len() == 0 @@ -33,7 +28,7 @@ func (r Result) Size() int { return r.Len() } -// Chunk splits an Result into multiple Results, +// Chunk splits a Result into multiple Results, // the size of each array is determined by `size`. // The last chunk may contain less than size elements. func (r Result) Chunk(size int) []Result { diff --git a/database/gdb/gdb_z_mysql_association_with_test.go b/database/gdb/gdb_z_mysql_association_with_test.go index 7345221d1..aef619da9 100644 --- a/database/gdb/gdb_z_mysql_association_with_test.go +++ b/database/gdb/gdb_z_mysql_association_with_test.go @@ -1991,3 +1991,44 @@ PRIMARY KEY (id) t.Assert(user.UserScores[4].Score, 5) }) } + +func Test_With_Feature_Issue1401(t *testing.T) { + var ( + table1 = "parcels" + table2 = "parcel_items" + ) + array := gstr.SplitAndTrim(gtest.TestDataContent(`issue1401.sql`), ";") + for _, v := range array { + if _, err := db.Exec(v); err != nil { + gtest.Error(err) + } + } + defer dropTable(table1) + defer dropTable(table2) + + gtest.C(t, func(t *gtest.T) { + type NItem struct { + Id int `json:"id"` + ParcelId int `json:"parcel_id"` + } + + type ParcelItem struct { + gmeta.Meta `orm:"table:parcel_items"` + NItem + } + + type ParcelRsp struct { + gmeta.Meta `orm:"table:parcels"` + Id int `json:"id"` + Items []*ParcelItem `json:"items" orm:"with:parcel_id=Id"` + } + + parcelDetail := &ParcelRsp{} + err := db.Model(table1).With(parcelDetail.Items).Where("id", 3).Scan(&parcelDetail) + t.AssertNil(err) + t.Assert(parcelDetail.Id, 3) + t.Assert(len(parcelDetail.Items), 1) + t.Assert(parcelDetail.Items[0].Id, 2) + t.Assert(parcelDetail.Items[0].ParcelId, 3) + }) +} diff --git a/database/gdb/gdb_z_mysql_struct_test.go b/database/gdb/gdb_z_mysql_struct_test.go index 5f12869a2..1ec74b655 100644 --- a/database/gdb/gdb_z_mysql_struct_test.go +++ b/database/gdb/gdb_z_mysql_struct_test.go @@ -14,6 +14,7 @@ import ( "github.com/gogf/gf/frame/g" "github.com/gogf/gf/os/gtime" "github.com/gogf/gf/test/gtest" + "github.com/gogf/gf/text/gstr" "github.com/gogf/gf/util/gconv" "reflect" "testing" @@ -480,3 +481,119 @@ func Test_Scan_AutoFilteringByStructAttributes(t *testing.T) { t.Assert(users[0].Id, 1) }) } + +func Test_Scan_JsonAttributes(t *testing.T) { + type GiftImage struct { + Uid string `json:"uid"` + Url string `json:"url"` + Status string `json:"status"` + Name string `json:"name"` + } + + type GiftComment struct { + Name string `json:"name"` + Field string `json:"field"` + Required bool `json:"required"` + } + + type Prop struct { + Name string `json:"name"` + Values []string `json:"values"` + } + + type Sku struct { + GiftId int64 `json:"gift_id"` + Name string `json:"name"` + ScorePrice int `json:"score_price"` + MarketPrice int `json:"market_price"` + CostPrice int `json:"cost_price"` + Stock int `json:"stock"` + } + + type Covers struct { + List []GiftImage `json:"list"` + } + + type GiftEntity struct { + Id int64 `json:"id"` + StoreId int64 `json:"store_id"` + GiftType int `json:"gift_type"` + GiftName string `json:"gift_name"` + Description string `json:"description"` + Covers Covers `json:"covers"` + Cover string `json:"cover"` + GiftCategoryId []int64 `json:"gift_category_id"` + HasProps bool `json:"has_props"` + OutSn string `json:"out_sn"` + IsLimitSell bool `json:"is_limit_sell"` + LimitSellType int `json:"limit_sell_type"` + LimitSellCycle string `json:"limit_sell_cycle"` + LimitSellCycleCount int `json:"limit_sell_cycle_count"` + LimitSellCustom bool `json:"limit_sell_custom"` // 只允许特定会员兑换 + LimitCustomerTags []int64 `json:"limit_customer_tags"` // 允许兑换的成员 + ScorePrice int `json:"score_price"` + MarketPrice float64 `json:"market_price"` + CostPrice int `json:"cost_price"` + Stock int `json:"stock"` + Props []Prop `json:"props"` + Skus []Sku `json:"skus"` + ExpressType []string `json:"express_type"` + Comments []GiftComment `json:"comments"` + Content string `json:"content"` + AtLeastRechargeCount int `json:"at_least_recharge_count"` + Status int `json:"status"` + } + + type User struct { + Id int + Passport string + } + + var ( + table = "jfy_gift" + ) + array := gstr.SplitAndTrim(gtest.TestDataContent(`issue1380.sql`), ";") + for _, v := range array { + if _, err := db.Exec(v); err != nil { + gtest.Error(err) + } + } + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + var ( + entity = new(GiftEntity) + err = db.Model(table).Where("id", 17).Scan(entity) + ) + t.AssertNil(err) + t.Assert(len(entity.Skus), 2) + + t.Assert(entity.Skus[0].Name, "red") + t.Assert(entity.Skus[0].Stock, 10) + t.Assert(entity.Skus[0].GiftId, 1) + t.Assert(entity.Skus[0].CostPrice, 80) + t.Assert(entity.Skus[0].ScorePrice, 188) + t.Assert(entity.Skus[0].MarketPrice, 388) + + t.Assert(entity.Skus[1].Name, "blue") + t.Assert(entity.Skus[1].Stock, 100) + t.Assert(entity.Skus[1].GiftId, 2) + t.Assert(entity.Skus[1].CostPrice, 81) + t.Assert(entity.Skus[1].ScorePrice, 200) + t.Assert(entity.Skus[1].MarketPrice, 288) + + t.Assert(entity.Id, 17) + t.Assert(entity.StoreId, 100004) + t.Assert(entity.GiftType, 1) + t.Assert(entity.GiftName, "GIFT") + t.Assert(entity.Description, "支持个性定制的父亲节老师长辈的专属礼物") + t.Assert(len(entity.Covers.List), 3) + t.Assert(entity.OutSn, "259402") + t.Assert(entity.LimitCustomerTags, "[]") + t.Assert(entity.ScorePrice, 10) + t.Assert(len(entity.Props), 1) + t.Assert(len(entity.Comments), 2) + t.Assert(entity.Status, 99) + t.Assert(entity.Content, `<p>礼品详情</p>`) + }) +} diff --git a/database/gdb/testdata/issue1380.sql b/database/gdb/testdata/issue1380.sql new file mode 100644 index 000000000..59aefb551 --- /dev/null +++ b/database/gdb/testdata/issue1380.sql @@ -0,0 +1,35 @@ +CREATE TABLE `jfy_gift` ( +`id` int(0) UNSIGNED NOT NULL AUTO_INCREMENT, +`gift_name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '礼品名称', +`at_least_recharge_count` int(0) UNSIGNED NOT NULL DEFAULT 1 COMMENT '最少兑换数量', +`comments` json NOT NULL COMMENT '礼品留言', +`content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '礼品详情', +`cost_price` decimal(10, 2) NULL DEFAULT NULL COMMENT '成本价', +`cover` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '封面', +`covers` json NOT NULL COMMENT '礼品图片库', +`description` varchar(62) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '礼品备注', +`express_type` json NOT NULL COMMENT '配送方式', +`gift_type` int(0) NOT NULL COMMENT '礼品类型:1:实物;2:虚拟;3:优惠券;4:积分券', +`has_props` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否有多个属性', +`is_limit_sell` tinyint(0) UNSIGNED NOT NULL DEFAULT 0 COMMENT '是否限购', +`limit_customer_tags` json NOT NULL COMMENT '语序购买的会员标签', +`limit_sell_custom` tinyint(0) UNSIGNED NOT NULL DEFAULT 0 COMMENT '是否开启允许购买的会员标签', +`limit_sell_cycle` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '限购周期', +`limit_sell_cycle_count` int(0) NOT NULL COMMENT '限购期内允许购买的数量', +`limit_sell_type` tinyint(0) NOT NULL COMMENT '限购类型', +`market_price` decimal(10, 2) NOT NULL COMMENT '市场价', +`out_sn` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '内部编码', +`props` json NOT NULL COMMENT '规格', +`skus` json NOT NULL COMMENT 'SKU', +`score_price` decimal(10, 2) NOT NULL COMMENT '兑换所需积分', +`stock` int(0) NOT NULL COMMENT '库存', +`create_at` datetime(0) NOT NULL COMMENT '创建日期', +`store_id` int(0) NOT NULL COMMENT '所属商城', +`status` int(0) UNSIGNED NULL DEFAULT 1 COMMENT '1:下架;20:审核中;30:复审中;99:上架', +`view_count` int(0) NOT NULL DEFAULT 0 COMMENT '访问量', +`sell_count` int(0) NULL DEFAULT 0 COMMENT '销量', +PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic; + + +INSERT INTO `jfy_gift` VALUES (17, 'GIFT', 1, '[{\"name\": \"身份证\", \"field\": \"idcard\", \"required\": false}, {\"name\": \"留言2\", \"field\": \"text\", \"required\": false}]', '<p>礼品详情</p>', 0.00, '', '{\"list\": [{\"uid\": \"vc-upload-1629292486099-3\", \"url\": \"https://cdn.taobao.com/sULsYiwaOPjsKGoBXwKtuewPzACpBDfQ.jpg\", \"name\": \"O1CN01OH6PIP1Oc5ot06U17_!!922361725.jpg\", \"status\": \"done\"}, {\"uid\": \"vc-upload-1629292486099-4\", \"url\": \"https://cdn.taobao.com/lqLHDcrFTgNvlWyXfLYZwmsrODzIBtFH.jpg\", \"name\": \"O1CN018hBckI1Oc5ouc8ppl_!!922361725.jpg\", \"status\": \"done\"}, {\"uid\": \"vc-upload-1629292486099-5\", \"url\": \"https://cdn.taobao.com/pvqyutXckICmHhbPBQtrVLHuMlXuGxUg.jpg\", \"name\": \"O1CN0185Ubp91Oc5osQTTcc_!!922361725.jpg\", \"status\": \"done\"}]}', '支持个性定制的父亲节老师长辈的专属礼物', '[\"快递包邮\", \"同城配送\"]', 1, 0, 0, '[]', 0, 'day', 0, 1, 0.00, '259402', '[{\"name\": \"颜色\", \"values\": [\"红色\", \"蓝色\"]}]', '[{\"name\": \"red\", \"stock\": 10, \"gift_id\": 1, \"cost_price\": 80, \"score_price\": 188, \"market_price\": 388}, {\"name\": \"blue\", \"stock\": 100, \"gift_id\": 2, \"cost_price\": 81, \"score_price\": 200, \"market_price\": 288}]', 10.00, 0, '2021-08-18 21:26:13', 100004, 99, 0, 0); diff --git a/database/gdb/testdata/issue1401.sql b/database/gdb/testdata/issue1401.sql new file mode 100644 index 000000000..b09087326 --- /dev/null +++ b/database/gdb/testdata/issue1401.sql @@ -0,0 +1,32 @@ +-- ---------------------------- +-- Table structure for parcel_items +-- ---------------------------- +DROP TABLE IF EXISTS `parcel_items`; +CREATE TABLE `parcel_items` ( + `id` int(11) NOT NULL, + `parcel_id` int(11) NULL DEFAULT NULL, + `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL, + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of parcel_items +-- ---------------------------- +INSERT INTO `parcel_items` VALUES (1, 1, '新品'); +INSERT INTO `parcel_items` VALUES (2, 3, '新品2'); + +-- ---------------------------- +-- Table structure for parcels +-- ---------------------------- +DROP TABLE IF EXISTS `parcels`; +CREATE TABLE `parcels` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of parcels +-- ---------------------------- +INSERT INTO `parcels` VALUES (1); +INSERT INTO `parcels` VALUES (2); +INSERT INTO `parcels` VALUES (3); \ No newline at end of file diff --git a/database/gredis/gredis.go b/database/gredis/gredis.go index 8de774e15..4bd6f3702 100644 --- a/database/gredis/gredis.go +++ b/database/gredis/gredis.go @@ -140,7 +140,7 @@ func New(config *Config) *Redis { // NewFromStr creates a redis client object with given configuration string. // Redis client maintains a connection pool automatically. -// The parameter <str> like: +// The parameter `str` like: // 127.0.0.1:6379,0 // 127.0.0.1:6379,0,password func NewFromStr(str string) (*Redis, error) { diff --git a/database/gredis/gredis_config.go b/database/gredis/gredis_config.go index e6fcae37e..310c113da 100644 --- a/database/gredis/gredis_config.go +++ b/database/gredis/gredis_config.go @@ -29,7 +29,7 @@ var ( ) // SetConfig sets the global configuration for specified group. -// If <name> is not passed, it sets configuration for the default group name. +// If `name` is not passed, it sets configuration for the default group name. func SetConfig(config *Config, name ...string) { group := DefaultGroupName if len(name) > 0 { @@ -42,7 +42,7 @@ func SetConfig(config *Config, name ...string) { } // SetConfigByStr sets the global configuration for specified group with string. -// If <name> is not passed, it sets configuration for the default group name. +// If `name` is not passed, it sets configuration for the default group name. func SetConfigByStr(str string, name ...string) error { group := DefaultGroupName if len(name) > 0 { @@ -58,7 +58,7 @@ func SetConfigByStr(str string, name ...string) error { } // GetConfig returns the global configuration with specified group name. -// If <name> is not passed, it returns configuration of the default group name. +// If `name` is not passed, it returns configuration of the default group name. func GetConfig(name ...string) (config *Config, ok bool) { group := DefaultGroupName if len(name) > 0 { @@ -71,7 +71,7 @@ func GetConfig(name ...string) (config *Config, ok bool) { } // RemoveConfig removes the global configuration with specified group. -// If <name> is not passed, it removes configuration of the default group name. +// If `name` is not passed, it removes configuration of the default group name. func RemoveConfig(name ...string) { group := DefaultGroupName if len(name) > 0 { diff --git a/database/gredis/gredis_conn.go b/database/gredis/gredis_conn.go index a56e9ddd7..347fe79be 100644 --- a/database/gredis/gredis_conn.go +++ b/database/gredis/gredis_conn.go @@ -117,7 +117,7 @@ func (c *Conn) ReceiveVarWithTimeout(timeout time.Duration) (*gvar.Var, error) { func resultToVar(result interface{}, err error) (*gvar.Var, error) { if err == nil { if result, ok := result.([]byte); ok { - return gvar.New(gconv.UnsafeBytesToStr(result)), err + return gvar.New(string(result)), err } // It treats all returned slice as string slice. if result, ok := result.([]interface{}); ok { diff --git a/database/gredis/gredis_instance.go b/database/gredis/gredis_instance.go index 4a5afcd25..9e8049180 100644 --- a/database/gredis/gredis_instance.go +++ b/database/gredis/gredis_instance.go @@ -14,7 +14,7 @@ var ( ) // Instance returns an instance of redis client with specified group. -// The <name> param is unnecessary, if <name> is not passed, +// The <name> param is unnecessary, if `name` is not passed, // it returns a redis instance with default configuration group. func Instance(name ...string) *Redis { group := DefaultGroupName diff --git a/encoding/gbase64/gbase64.go b/encoding/gbase64/gbase64.go index b88373677..30e104aec 100644 --- a/encoding/gbase64/gbase64.go +++ b/encoding/gbase64/gbase64.go @@ -9,7 +9,6 @@ package gbase64 import ( "encoding/base64" - "github.com/gogf/gf/util/gconv" "io/ioutil" ) @@ -27,7 +26,7 @@ func EncodeString(src string) string { // EncodeToString encodes bytes to string with BASE64 algorithm. func EncodeToString(src []byte) string { - return gconv.UnsafeBytesToStr(Encode(src)) + return string(Encode(src)) } // EncryptFile encodes file content of <path> using BASE64 algorithms. @@ -55,7 +54,7 @@ func EncodeFileToString(path string) (string, error) { if err != nil { return "", err } - return gconv.UnsafeBytesToStr(content), nil + return string(content), nil } // MustEncodeFileToString encodes file content of <path> to string using BASE64 algorithms. @@ -103,7 +102,7 @@ func MustDecodeString(data string) []byte { // DecodeString decodes string with BASE64 algorithm. func DecodeToString(data string) (string, error) { b, err := DecodeString(data) - return gconv.UnsafeBytesToStr(b), err + return string(b), err } // MustDecodeToString decodes string with BASE64 algorithm. diff --git a/encoding/gini/gini.go b/encoding/gini/gini.go index 0ff476b46..a0b31f37f 100644 --- a/encoding/gini/gini.go +++ b/encoding/gini/gini.go @@ -79,24 +79,23 @@ func Decode(data []byte) (res map[string]interface{}, err error) { // Encode converts map to INI format. func Encode(data map[string]interface{}) (res []byte, err error) { w := new(bytes.Buffer) - w.WriteString("; this ini file is produced by package gini\n") for k, v := range data { n, err := w.WriteString(fmt.Sprintf("[%s]\n", k)) if err != nil || n == 0 { - return nil, fmt.Errorf("write data failed. %v", err) + return nil, gerror.WrapCodef(gcode.CodeInternalError, err, "write data failed") } for kk, vv := range v.(map[string]interface{}) { n, err := w.WriteString(fmt.Sprintf("%s=%s\n", kk, vv.(string))) if err != nil || n == 0 { - return nil, fmt.Errorf("write data failed. %v", err) + return nil, gerror.WrapCodef(gcode.CodeInternalError, err, "write data failed") } } } res = make([]byte, w.Len()) n, err := w.Read(res) if err != nil || n == 0 { - return nil, fmt.Errorf("write data failed. %v", err) + return nil, gerror.WrapCodef(gcode.CodeInternalError, err, "write data failed") } return res, nil diff --git a/encoding/gjson/gjson.go b/encoding/gjson/gjson.go index 887b0f232..d33e6338e 100644 --- a/encoding/gjson/gjson.go +++ b/encoding/gjson/gjson.go @@ -38,8 +38,8 @@ type Options struct { StrNumber bool // StrNumber causes the Decoder to unmarshal a number into an interface{} as a string instead of as a float64. } -// apiInterface is used for type assert api for Interface(). -type apiInterface interface { +// iInterface is used for type assert api for Interface(). +type iInterface interface { Interface() interface{} } @@ -50,7 +50,7 @@ type apiInterface interface { func (j *Json) setValue(pattern string, value interface{}, removed bool) error { if value != nil { if utils.IsStruct(value) { - if v, ok := value.(apiInterface); ok { + if v, ok := value.(iInterface); ok { value = v.Interface() } } @@ -322,17 +322,28 @@ func (j *Json) getPointerByPatternWithViolenceCheck(pattern string) *interface{} if !j.vc { return j.getPointerByPatternWithoutViolenceCheck(pattern) } - index := len(pattern) - start := 0 - length := 0 - pointer := j.p + + // It returns nil if pattern is empty. + if pattern == "" { + return nil + } + // It returns all if pattern is ".". + if pattern == "." { + return j.p + } + + var ( + index = len(pattern) + start = 0 + length = 0 + pointer = j.p + ) if index == 0 { return pointer } for { if r := j.checkPatternByPointer(pattern[start:index], pointer); r != nil { - length += index - start - if start > 0 { + if length += index - start; start > 0 { length += 1 } start = index + 1 @@ -361,6 +372,16 @@ func (j *Json) getPointerByPatternWithoutViolenceCheck(pattern string) *interfac if j.vc { return j.getPointerByPatternWithViolenceCheck(pattern) } + + // It returns nil if pattern is empty. + if pattern == "" { + return nil + } + // It returns all if pattern is ".". + if pattern == "." { + return j.p + } + pointer := j.p if len(pattern) == 0 { return pointer diff --git a/encoding/gjson/gjson_api.go b/encoding/gjson/gjson_api.go index 642990201..672c322ac 100644 --- a/encoding/gjson/gjson_api.go +++ b/encoding/gjson/gjson_api.go @@ -8,6 +8,8 @@ package gjson import ( "fmt" + "github.com/gogf/gf/errors/gcode" + "github.com/gogf/gf/errors/gerror" "time" "github.com/gogf/gf/util/gutil" @@ -59,11 +61,6 @@ func (j *Json) Get(pattern string, def ...interface{}) interface{} { return nil } - // It returns all if pattern is ".". - if pattern == "." { - return *j.p - } - var result *interface{} if j.vc { result = j.getPointerByPattern(pattern) @@ -309,14 +306,20 @@ func (j *Json) Len(pattern string) int { // The target value by <pattern> should be type of slice. func (j *Json) Append(pattern string, value interface{}) error { p := j.getPointerByPattern(pattern) - if p == nil { + if p == nil || *p == nil { + if pattern == "." { + return j.Set("0", value) + } return j.Set(fmt.Sprintf("%s.0", pattern), value) } switch (*p).(type) { case []interface{}: + if pattern == "." { + return j.Set(fmt.Sprintf("%d", len((*p).([]interface{}))), value) + } return j.Set(fmt.Sprintf("%s.%d", pattern, len((*p).([]interface{}))), value) } - return fmt.Errorf("invalid variable type of %s", pattern) + return gerror.NewCodef(gcode.CodeInvalidParameter, "invalid variable type of %s", pattern) } // GetStruct retrieves the value by specified <pattern> and converts it to specified object diff --git a/encoding/gjson/gjson_api_encoding.go b/encoding/gjson/gjson_api_encoding.go index cea7a8a1b..559a20464 100644 --- a/encoding/gjson/gjson_api_encoding.go +++ b/encoding/gjson/gjson_api_encoding.go @@ -12,7 +12,6 @@ import ( "github.com/gogf/gf/encoding/gxml" "github.com/gogf/gf/encoding/gyaml" "github.com/gogf/gf/internal/json" - "github.com/gogf/gf/util/gconv" ) // ======================================================================== @@ -50,7 +49,7 @@ func (j *Json) MustToJson() []byte { } func (j *Json) MustToJsonString() string { - return gconv.UnsafeBytesToStr(j.MustToJson()) + return string(j.MustToJson()) } func (j *Json) MustToJsonIndent() []byte { @@ -62,7 +61,7 @@ func (j *Json) MustToJsonIndent() []byte { } func (j *Json) MustToJsonIndentString() string { - return gconv.UnsafeBytesToStr(j.MustToJsonIndent()) + return string(j.MustToJsonIndent()) } // ======================================================================== @@ -96,7 +95,7 @@ func (j *Json) MustToXml(rootTag ...string) []byte { } func (j *Json) MustToXmlString(rootTag ...string) string { - return gconv.UnsafeBytesToStr(j.MustToXml(rootTag...)) + return string(j.MustToXml(rootTag...)) } func (j *Json) MustToXmlIndent(rootTag ...string) []byte { @@ -108,7 +107,7 @@ func (j *Json) MustToXmlIndent(rootTag ...string) []byte { } func (j *Json) MustToXmlIndentString(rootTag ...string) string { - return gconv.UnsafeBytesToStr(j.MustToXmlIndent(rootTag...)) + return string(j.MustToXmlIndent(rootTag...)) } // ======================================================================== @@ -135,7 +134,7 @@ func (j *Json) MustToYaml() []byte { } func (j *Json) MustToYamlString() string { - return gconv.UnsafeBytesToStr(j.MustToYaml()) + return string(j.MustToYaml()) } // ======================================================================== @@ -162,7 +161,7 @@ func (j *Json) MustToToml() []byte { } func (j *Json) MustToTomlString() string { - return gconv.UnsafeBytesToStr(j.MustToToml()) + return string(j.MustToToml()) } // ======================================================================== @@ -192,5 +191,5 @@ func (j *Json) MustToIni() []byte { // MustToIniString . func (j *Json) MustToIniString() string { - return gconv.UnsafeBytesToStr(j.MustToIni()) + return string(j.MustToIni()) } diff --git a/encoding/gjson/gjson_api_new_load.go b/encoding/gjson/gjson_api_new_load.go index f9b5c673b..cc7fc10f3 100644 --- a/encoding/gjson/gjson_api_new_load.go +++ b/encoding/gjson/gjson_api_new_load.go @@ -8,7 +8,6 @@ package gjson import ( "bytes" - "fmt" "github.com/gogf/gf/errors/gcode" "github.com/gogf/gf/errors/gerror" "reflect" @@ -260,12 +259,14 @@ func doLoadContentWithOptions(dataType string, data []byte, options Options) (*J if data, err = gtoml.ToJson(data); err != nil { return nil, err } + case "ini", ".ini": if data, err = gini.ToJson(data); err != nil { return nil, err } + default: - err = gerror.NewCode(gcode.CodeInvalidParameter, "unsupported type for loading") + err = gerror.NewCodef(gcode.CodeInvalidParameter, `unsupported type "%s" for loading`, dataType) } if err != nil { return nil, err @@ -279,7 +280,7 @@ func doLoadContentWithOptions(dataType string, data []byte, options Options) (*J } switch result.(type) { case string, []byte: - return nil, fmt.Errorf(`json decoding failed for content: %s`, string(data)) + return nil, gerror.NewCodef(gcode.CodeInternalError, `json decoding failed for content: %s`, data) } return NewWithOptions(result, options), nil } diff --git a/encoding/gjson/gjson_stdlib_json_util.go b/encoding/gjson/gjson_stdlib_json_util.go index be1c57668..28cfccb37 100644 --- a/encoding/gjson/gjson_stdlib_json_util.go +++ b/encoding/gjson/gjson_stdlib_json_util.go @@ -35,7 +35,7 @@ func Decode(data interface{}) (interface{}, error) { } } -// Decode decodes json format <data> to specified golang variable <v>. +// DecodeTo decodes json format <data> to specified golang variable <v>. // The parameter <data> can be either bytes or string type. // The parameter <v> should be a pointer type. func DecodeTo(data interface{}, v interface{}) error { diff --git a/encoding/gjson/gjson_z_unit_basic_test.go b/encoding/gjson/gjson_z_unit_basic_test.go index 7013f2fbf..27b8bee65 100644 --- a/encoding/gjson/gjson_z_unit_basic_test.go +++ b/encoding/gjson/gjson_z_unit_basic_test.go @@ -244,6 +244,22 @@ func Test_Append(t *testing.T) { }) } +func Test_RawArray(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + j := gjson.New(nil) + t.AssertNil(j.Set("0", 1)) + t.AssertNil(j.Set("1", 2)) + t.Assert(j.MustToJsonString(), `[1,2]`) + }) + + gtest.C(t, func(t *gtest.T) { + j := gjson.New(nil) + t.AssertNil(j.Append(".", 1)) + t.AssertNil(j.Append(".", 2)) + t.Assert(j.MustToJsonString(), `[1,2]`) + }) +} + func TestJson_ToJson(t *testing.T) { gtest.C(t, func(t *gtest.T) { p := gjson.New(1) diff --git a/errors/gerror/gerror.go b/errors/gerror/gerror.go index 268af2fab..255e56591 100644 --- a/errors/gerror/gerror.go +++ b/errors/gerror/gerror.go @@ -6,8 +6,8 @@ // Package gerror provides simple functions to manipulate errors. // -// Very note that, this package is quite a base package, which should not import extra -// packages except standard packages, to avoid cycle imports. +// Very note that, this package is quite a basic package, which SHOULD NOT import extra +// packages except standard packages and internal packages, to avoid cycle imports. package gerror import ( @@ -15,32 +15,32 @@ import ( "github.com/gogf/gf/errors/gcode" ) -// apiCode is the interface for Code feature. -type apiCode interface { +// iCode is the interface for Code feature. +type iCode interface { Error() string Code() gcode.Code } -// apiStack is the interface for Stack feature. -type apiStack interface { +// iStack is the interface for Stack feature. +type iStack interface { Error() string Stack() string } -// apiCause is the interface for Cause feature. -type apiCause interface { +// iCause is the interface for Cause feature. +type iCause interface { Error() string Cause() error } -// apiCurrent is the interface for Current feature. -type apiCurrent interface { +// iCurrent is the interface for Current feature. +type iCurrent interface { Error() string Current() error } -// apiNext is the interface for Next feature. -type apiNext interface { +// iNext is the interface for Next feature. +type iNext interface { Error() string Next() error } @@ -64,7 +64,7 @@ func Newf(format string, args ...interface{}) error { } // NewSkip creates and returns an error which is formatted from given text. -// The parameter <skip> specifies the stack callers skipped amount. +// The parameter `skip` specifies the stack callers skipped amount. func NewSkip(skip int, text string) error { return &Error{ stack: callers(skip), @@ -74,7 +74,7 @@ func NewSkip(skip int, text string) error { } // NewSkipf returns an error that formats as the given format and args. -// The parameter <skip> specifies the stack callers skipped amount. +// The parameter `skip` specifies the stack callers skipped amount. func NewSkipf(skip int, format string, args ...interface{}) error { return &Error{ stack: callers(skip), @@ -99,7 +99,7 @@ func Wrap(err error, text string) error { // Wrapf returns an error annotating err with a stack trace // at the point Wrapf is called, and the format specifier. -// It returns nil if given <err> is nil. +// It returns nil if given `err` is nil. func Wrapf(err error, format string, args ...interface{}) error { if err == nil { return nil @@ -114,7 +114,7 @@ func Wrapf(err error, format string, args ...interface{}) error { // WrapSkip wraps error with text. // It returns nil if given err is nil. -// The parameter <skip> specifies the stack callers skipped amount. +// The parameter `skip` specifies the stack callers skipped amount. func WrapSkip(skip int, err error, text string) error { if err == nil { return nil @@ -129,7 +129,7 @@ func WrapSkip(skip int, err error, text string) error { // WrapSkipf wraps error with text that is formatted with given format and args. // It returns nil if given err is nil. -// The parameter <skip> specifies the stack callers skipped amount. +// The parameter `skip` specifies the stack callers skipped amount. func WrapSkipf(skip int, err error, format string, args ...interface{}) error { if err == nil { return nil @@ -165,7 +165,7 @@ func NewCodef(code gcode.Code, format string, args ...interface{}) error { } // NewCodeSkip creates and returns an error which has error code and is formatted from given text. -// The parameter <skip> specifies the stack callers skipped amount. +// The parameter `skip` specifies the stack callers skipped amount. func NewCodeSkip(code gcode.Code, skip int, text ...string) error { errText := "" if len(text) > 0 { @@ -179,7 +179,7 @@ func NewCodeSkip(code gcode.Code, skip int, text ...string) error { } // NewCodeSkipf returns an error that has error code and formats as the given format and args. -// The parameter <skip> specifies the stack callers skipped amount. +// The parameter `skip` specifies the stack callers skipped amount. func NewCodeSkipf(code gcode.Code, skip int, format string, args ...interface{}) error { return &Error{ stack: callers(skip), @@ -207,7 +207,7 @@ func WrapCode(code gcode.Code, err error, text ...string) error { } // WrapCodef wraps error with code and format specifier. -// It returns nil if given <err> is nil. +// It returns nil if given `err` is nil. func WrapCodef(code gcode.Code, err error, format string, args ...interface{}) error { if err == nil { return nil @@ -222,7 +222,7 @@ func WrapCodef(code gcode.Code, err error, format string, args ...interface{}) e // WrapCodeSkip wraps error with code and text. // It returns nil if given err is nil. -// The parameter <skip> specifies the stack callers skipped amount. +// The parameter `skip` specifies the stack callers skipped amount. func WrapCodeSkip(code gcode.Code, skip int, err error, text ...string) error { if err == nil { return nil @@ -241,7 +241,7 @@ func WrapCodeSkip(code gcode.Code, skip int, err error, text ...string) error { // WrapCodeSkipf wraps error with code and text that is formatted with given format and args. // It returns nil if given err is nil. -// The parameter <skip> specifies the stack callers skipped amount. +// The parameter `skip` specifies the stack callers skipped amount. func WrapCodeSkipf(code gcode.Code, skip int, err error, format string, args ...interface{}) error { if err == nil { return nil @@ -258,17 +258,17 @@ func WrapCodeSkipf(code gcode.Code, skip int, err error, format string, args ... // It returns CodeNil if it has no error code or it does not implements interface Code. func Code(err error) gcode.Code { if err != nil { - if e, ok := err.(apiCode); ok { + if e, ok := err.(iCode); ok { return e.Code() } } return gcode.CodeNil } -// Cause returns the root cause error of <err>. +// Cause returns the root cause error of `err`. func Cause(err error) error { if err != nil { - if e, ok := err.(apiCause); ok { + if e, ok := err.(iCause); ok { return e.Cause() } } @@ -276,12 +276,12 @@ func Cause(err error) error { } // Stack returns the stack callers as string. -// It returns the error string directly if the <err> does not support stacks. +// It returns the error string directly if the `err` does not support stacks. func Stack(err error) string { if err == nil { return "" } - if e, ok := err.(apiStack); ok { + if e, ok := err.(iStack); ok { return e.Stack() } return err.Error() @@ -293,7 +293,7 @@ func Current(err error) error { if err == nil { return nil } - if e, ok := err.(apiCurrent); ok { + if e, ok := err.(iCurrent); ok { return e.Current() } return err @@ -305,8 +305,14 @@ func Next(err error) error { if err == nil { return nil } - if e, ok := err.(apiNext); ok { + if e, ok := err.(iNext); ok { return e.Next() } return nil } + +// HasStack checks and returns whether `err` implemented interface `iStack`. +func HasStack(err error) bool { + _, ok := err.(iStack) + return ok +} diff --git a/errors/gerror/gerror_error.go b/errors/gerror/gerror_error.go index bbc00bdf1..1ffb76be5 100644 --- a/errors/gerror/gerror_error.go +++ b/errors/gerror/gerror_error.go @@ -80,7 +80,7 @@ func (err *Error) Cause() error { if e, ok := loop.error.(*Error); ok { // Internal Error struct. loop = e - } else if e, ok := loop.error.(apiCause); ok { + } else if e, ok := loop.error.(iCause); ok { // Other Error that implements ApiCause interface. return e.Cause() } else { @@ -124,7 +124,7 @@ func (err *Error) Format(s fmt.State, verb rune) { } // Stack returns the stack callers as string. -// It returns an empty string if the <err> does not support stacks. +// It returns an empty string if the `err` does not support stacks. func (err *Error) Stack() string { if err == nil { return "" @@ -202,7 +202,7 @@ func formatSubStack(st stack, buffer *bytes.Buffer) { continue } } - // Avoid stack string like "<autogenerated>" + // Avoid stack string like "`autogenerated`" if strings.Contains(file, "<") { continue } diff --git a/errors/gerror/gerror_z_unit_test.go b/errors/gerror/gerror_z_unit_test.go index 05521833c..607af3987 100644 --- a/errors/gerror/gerror_z_unit_test.go +++ b/errors/gerror/gerror_z_unit_test.go @@ -319,3 +319,12 @@ func Test_Json(t *testing.T) { t.Assert(string(b), `"2: 1"`) }) } + +func Test_HasStack(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + err1 := errors.New("1") + err2 := gerror.New("1") + t.Assert(gerror.HasStack(err1), false) + t.Assert(gerror.HasStack(err2), true) + }) +} diff --git a/frame/g/g_func.go b/frame/g/g_func.go index 5034a8f08..10981ea8d 100644 --- a/frame/g/g_func.go +++ b/frame/g/g_func.go @@ -21,7 +21,7 @@ func NewVar(i interface{}, safe ...bool) *Var { } // Wait is an alias of ghttp.Wait, which blocks until all the web servers shutdown. -// It's commonly used in multiple servers situation. +// It's commonly used in multiple servers' situation. func Wait() { ghttp.Wait() } @@ -43,8 +43,7 @@ func Export(i ...interface{}) string { return gutil.Export(i...) } -// Throw throws a exception, which can be caught by TryCatch function. -// It always be used in TryCatch function. +// Throw throws an exception, which can be caught by TryCatch function. func Throw(exception interface{}) { gutil.Throw(exception) } @@ -56,22 +55,22 @@ func Try(try func()) (err error) { } // TryCatch implements try...catch... logistics using internal panic...recover. -// It automatically calls function <catch> if any exception occurs ans passes the exception as an error. +// It automatically calls function `catch` if any exception occurs ans passes the exception as an error. func TryCatch(try func(), catch ...func(exception error)) { gutil.TryCatch(try, catch...) } -// IsNil checks whether given <value> is nil. -// Parameter <traceSource> is used for tracing to the source variable if given <value> is type -// of a pinter that also points to a pointer. It returns nil if the source is nil when <traceSource> +// IsNil checks whether given `value` is nil. +// Parameter <traceSource> is used for tracing to the source variable if given `value` is type +// of pinter that also points to a pointer. It returns nil if the source is nil when `traceSource` // is true. -// Note that it might use reflect feature which affects performance a little bit. +// Note that it might use reflect feature which affects performance a little. func IsNil(value interface{}, traceSource ...bool) bool { return empty.IsNil(value, traceSource...) } -// IsEmpty checks whether given <value> empty. -// It returns true if <value> is in: 0, nil, false, "", len(slice/map/chan) == 0. +// IsEmpty checks whether given `value` empty. +// It returns true if `value` is in: 0, nil, false, "", len(slice/map/chan) == 0. // Or else it returns true. func IsEmpty(value interface{}) bool { return empty.IsEmpty(value) diff --git a/frame/g/g_object.go b/frame/g/g_object.go index 571d47247..4776fd9f9 100644 --- a/frame/g/g_object.go +++ b/frame/g/g_object.go @@ -58,13 +58,13 @@ func Cfg(name ...string) *gcfg.Config { } // Resource returns an instance of Resource. -// The parameter <name> is the name for the instance. +// The parameter `name` is the name for the instance. func Resource(name ...string) *gres.Resource { return gins.Resource(name...) } // I18n returns an instance of gi18n.Manager. -// The parameter <name> is the name for the instance. +// The parameter `name` is the name for the instance. func I18n(name ...string) *gi18n.Manager { return gins.I18n(name...) } @@ -76,7 +76,7 @@ func Res(name ...string) *gres.Resource { } // Log returns an instance of glog.Logger. -// The parameter <name> is the name for the instance. +// The parameter `name` is the name for the instance. func Log(name ...string) *glog.Logger { return gins.Log(name...) } @@ -89,7 +89,7 @@ func DB(name ...string) gdb.DB { // Table is alias of Model. // The database component is designed not only for // relational databases but also for NoSQL databases in the future. The name -// "Table" is not proper for that purpose any more. +// "Table" is not proper for that purpose anymore. // Deprecated, use Model instead. func Table(tableNameOrStruct ...interface{}) *gdb.Model { return DB().Model(tableNameOrStruct...) @@ -100,6 +100,11 @@ func Model(tableNameOrStruct ...interface{}) *gdb.Model { return DB().Model(tableNameOrStruct...) } +// ModelRaw creates and returns a model based on a raw sql not a table. +func ModelRaw(rawSql string, args ...interface{}) *gdb.Model { + return DB().Raw(rawSql, args...) +} + // Redis returns an instance of redis client with specified configuration group name. func Redis(name ...string) *gredis.Redis { return gins.Redis(name...) diff --git a/frame/gins/gins.go b/frame/gins/gins.go index af822b0f6..719cf9bba 100644 --- a/frame/gins/gins.go +++ b/frame/gins/gins.go @@ -33,24 +33,24 @@ func GetOrSet(name string, instance interface{}) interface{} { } // GetOrSetFunc returns the instance by name, -// or sets instance with returned value of callback function <f> if it does not exist +// or sets instance with returned value of callback function `f` if it does not exist // and then returns this instance. func GetOrSetFunc(name string, f func() interface{}) interface{} { return instances.GetOrSetFunc(name, f) } // GetOrSetFuncLock returns the instance by name, -// or sets instance with returned value of callback function <f> if it does not exist +// or sets instance with returned value of callback function `f` if it does not exist // and then returns this instance. // -// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function <f> +// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function `f` // with mutex.Lock of the hash map. func GetOrSetFuncLock(name string, f func() interface{}) interface{} { return instances.GetOrSetFuncLock(name, f) } -// SetIfNotExist sets <instance> to the map if the <name> does not exist, then returns true. -// It returns false if <name> exists, and <instance> would be ignored. +// SetIfNotExist sets <instance> to the map if the `name` does not exist, then returns true. +// It returns false if <name> exists, and `instance` would be ignored. func SetIfNotExist(name string, instance interface{}) bool { return instances.SetIfNotExist(name, instance) } diff --git a/frame/gins/gins_config.go b/frame/gins/gins_config.go index 38bca58b4..b6d0be9cf 100644 --- a/frame/gins/gins_config.go +++ b/frame/gins/gins_config.go @@ -11,7 +11,7 @@ import ( ) // Config returns an instance of View with default settings. -// The parameter <name> is the name for the instance. +// The parameter `name` is the name for the instance. func Config(name ...string) *gcfg.Config { return gcfg.Instance(name...) } diff --git a/frame/gins/gins_database.go b/frame/gins/gins_database.go index dfe83eae7..8d722a10d 100644 --- a/frame/gins/gins_database.go +++ b/frame/gins/gins_database.go @@ -77,7 +77,7 @@ func Database(name ...string) gdb.DB { if len(configMap) == 0 { configMap = make(map[string]interface{}) } - // Parse <m> as map-slice and adds it to gdb's global configurations. + // Parse `m` as map-slice and adds it to gdb's global configurations. for g, groupConfig := range configMap { cg := gdb.ConfigGroup{} switch value := groupConfig.(type) { @@ -102,7 +102,7 @@ func Database(name ...string) gdb.DB { } } } - // Parse <m> as a single node configuration, + // Parse `m` as a single node configuration, // which is the default group configuration. if node := parseDBConfigNode(configMap); node != nil { cg := gdb.ConfigGroup{} diff --git a/frame/gins/gins_i18n.go b/frame/gins/gins_i18n.go index 71b57b63a..110896b42 100644 --- a/frame/gins/gins_i18n.go +++ b/frame/gins/gins_i18n.go @@ -11,7 +11,7 @@ import ( ) // I18n returns an instance of gi18n.Manager. -// The parameter <name> is the name for the instance. +// The parameter `name` is the name for the instance. func I18n(name ...string) *gi18n.Manager { return gi18n.Instance(name...) } diff --git a/frame/gins/gins_log.go b/frame/gins/gins_log.go index 3ec6c691c..30018f031 100644 --- a/frame/gins/gins_log.go +++ b/frame/gins/gins_log.go @@ -18,7 +18,7 @@ const ( ) // Log returns an instance of glog.Logger. -// The parameter <name> is the name for the instance. +// The parameter `name` is the name for the instance. func Log(name ...string) *glog.Logger { instanceName := glog.DefaultName if len(name) > 0 && name[0] != "" { diff --git a/frame/gins/gins_resource.go b/frame/gins/gins_resource.go index fa97179fb..30f78ba00 100644 --- a/frame/gins/gins_resource.go +++ b/frame/gins/gins_resource.go @@ -11,7 +11,7 @@ import ( ) // Resource returns an instance of Resource. -// The parameter <name> is the name for the instance. +// The parameter `name` is the name for the instance. func Resource(name ...string) *gres.Resource { return gres.Instance(name...) } diff --git a/frame/gins/gins_view.go b/frame/gins/gins_view.go index ab49298fe..c67cef1ac 100644 --- a/frame/gins/gins_view.go +++ b/frame/gins/gins_view.go @@ -18,7 +18,7 @@ const ( ) // View returns an instance of View with default settings. -// The parameter <name> is the name for the instance. +// The parameter `name` is the name for the instance. func View(name ...string) *gview.View { instanceName := gview.DefaultName if len(name) > 0 && name[0] != "" { diff --git a/frame/gmvc/view.go b/frame/gmvc/view.go index 3f77dce2b..ff623aa60 100644 --- a/frame/gmvc/view.go +++ b/frame/gmvc/view.go @@ -53,7 +53,7 @@ func (view *View) Assign(key string, value interface{}) { view.mu.Unlock() } -// Parse parses given template file <tpl> with assigned template variables +// Parse parses given template file `tpl` with assigned template variables // and returns the parsed template content. func (view *View) Parse(file string) (string, error) { view.mu.RLock() @@ -62,7 +62,7 @@ func (view *View) Parse(file string) (string, error) { return buffer, err } -// ParseContent parses given template file <file> with assigned template variables +// ParseContent parses given template file `file` with assigned template variables // and returns the parsed template content. func (view *View) ParseContent(content string) (string, error) { view.mu.RLock() @@ -71,23 +71,23 @@ func (view *View) ParseContent(content string) (string, error) { return buffer, err } -// LockFunc locks writing for template variables by callback function <f>. +// LockFunc locks writing for template variables by callback function `f`. func (view *View) LockFunc(f func(data gview.Params)) { view.mu.Lock() defer view.mu.Unlock() f(view.data) } -// RLockFunc locks reading for template variables by callback function <f>. +// RLockFunc locks reading for template variables by callback function `f`. func (view *View) RLockFunc(f func(data gview.Params)) { view.mu.RLock() defer view.mu.RUnlock() f(view.data) } -// BindFunc registers customized template function named <name> -// with given function <function> to current view object. -// The <name> is the function name which can be called in template content. +// BindFunc registers customized template function named `name` +// with given function `function` to current view object. +// The `name` is the function name which can be called in template content. func (view *View) BindFunc(name string, function interface{}) { view.view.BindFunc(name, function) } diff --git a/go.mod b/go.mod index bbdb48b3a..fc660eac6 100644 --- a/go.mod +++ b/go.mod @@ -3,18 +3,18 @@ module github.com/gogf/gf go 1.14 require ( - github.com/BurntSushi/toml v0.3.1 + github.com/BurntSushi/toml v0.4.1 github.com/clbanning/mxj v1.8.5-0.20200714211355-ff02cfb8ea28 github.com/fatih/color v1.12.0 - github.com/fsnotify/fsnotify v1.4.9 + github.com/fsnotify/fsnotify v1.5.1 github.com/go-sql-driver/mysql v1.6.0 github.com/gomodule/redigo v1.8.5 github.com/gorilla/websocket v1.4.2 github.com/grokify/html-strip-tags-go v0.0.0-20190921062105-daaa06bf1aaf github.com/olekukonko/tablewriter v0.0.5 - go.opentelemetry.io/otel v1.0.0-RC2 - go.opentelemetry.io/otel/oteltest v1.0.0-RC2 - go.opentelemetry.io/otel/trace v1.0.0-RC2 + go.opentelemetry.io/otel v1.0.0-RC3 + go.opentelemetry.io/otel/oteltest v1.0.0-RC3 + go.opentelemetry.io/otel/trace v1.0.0-RC3 golang.org/x/net v0.0.0-20210520170846-37e1c6afe023 golang.org/x/text v0.3.6 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b diff --git a/go.sum b/go.sum index 72133957f..269310b56 100644 --- a/go.sum +++ b/go.sum @@ -1,13 +1,13 @@ -github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v0.4.1 h1:GaI7EiDXDRfa8VshkTj7Fym7ha+y8/XxIgD2okUIjLw= +github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/clbanning/mxj v1.8.5-0.20200714211355-ff02cfb8ea28 h1:LdXxtjzvZYhhUaonAaAKArG3pyC67kGL3YY+6hGG8G4= github.com/clbanning/mxj v1.8.5-0.20200714211355-ff02cfb8ea28/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5PVGJng= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fatih/color v1.12.0 h1:mRhaKNwANqRgUBGKmnI5ZxEk7QXmjQeCcuYFMX2bfcc= github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= -github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= +github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/gomodule/redigo v1.8.5 h1:nRAxCa+SVsyjSBrtZmG/cqb6VbTmuRzpg/PoTFlpumc= @@ -32,20 +32,20 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -go.opentelemetry.io/otel v1.0.0-RC2 h1:SHhxSjB+omnGZPgGlKe+QMp3MyazcOHdQ8qwo89oKbg= -go.opentelemetry.io/otel v1.0.0-RC2/go.mod h1:w1thVQ7qbAy8MHb0IFj8a5Q2QU0l2ksf8u/CN8m3NOM= -go.opentelemetry.io/otel/oteltest v1.0.0-RC2 h1:xNKqMhlZYkASSyvF4JwObZFMq0jhFN3c3SP+2rCzVPk= -go.opentelemetry.io/otel/oteltest v1.0.0-RC2/go.mod h1:kiQ4tw5tAL4JLTbcOYwK1CWI1HkT5aiLzHovgOVnz/A= -go.opentelemetry.io/otel/trace v1.0.0-RC2 h1:dunAP0qDULMIT82atj34m5RgvsIK6LcsXf1c/MsYg1w= -go.opentelemetry.io/otel/trace v1.0.0-RC2/go.mod h1:JPQ+z6nNw9mqEGT8o3eoPTdnNI+Aj5JcxEsVGREIAy4= +go.opentelemetry.io/otel v1.0.0-RC3 h1:kvwiyEkiUT/JaadXzVLI/R1wDO934A7r3Bs2wEe6wqA= +go.opentelemetry.io/otel v1.0.0-RC3/go.mod h1:Ka5j3ua8tZs4Rkq4Ex3hwgBgOchyPVq5S6P2lz//nKQ= +go.opentelemetry.io/otel/oteltest v1.0.0-RC3 h1:MjaeegZTaX0Bv9uB9CrdVjOFM/8slRjReoWoV9xDCpY= +go.opentelemetry.io/otel/oteltest v1.0.0-RC3/go.mod h1:xpzajI9JBRr7gX63nO6kAmImmYIAtuQblZ36Z+LfCjE= +go.opentelemetry.io/otel/trace v1.0.0-RC3 h1:9F0ayEvlxv8BmNmPbU005WK7hC+7KbOazCPZjNa1yME= +go.opentelemetry.io/otel/trace v1.0.0-RC3/go.mod h1:VUt2TUYd8S2/ZRX09ZDFZQwn2RqfMB5MzO17jBojGxo= golang.org/x/net v0.0.0-20210520170846-37e1c6afe023 h1:ADo5wSpq2gqaCGQWzk7S5vd//0iyyLeAratkEoG5dLE= golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da h1:b3NXsE2LusjYGGjL5bxEVZZORm/YEFFrWFjR8eFrw/c= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= diff --git a/internal/empty/empty.go b/internal/empty/empty.go index af1b7fe75..43ea50976 100644 --- a/internal/empty/empty.go +++ b/internal/empty/empty.go @@ -12,22 +12,22 @@ import ( "time" ) -// apiString is used for type assert api for String(). -type apiString interface { +// iString is used for type assert api for String(). +type iString interface { String() string } -// apiInterfaces is used for type assert api for Interfaces. -type apiInterfaces interface { +// iInterfaces is used for type assert api for Interfaces. +type iInterfaces interface { Interfaces() []interface{} } -// apiMapStrAny is the interface support for converting struct parameter to map. -type apiMapStrAny interface { +// iMapStrAny is the interface support for converting struct parameter to map. +type iMapStrAny interface { MapStrAny() map[string]interface{} } -type apiTime interface { +type iTime interface { Date() (year int, month time.Month, day int) IsZero() bool } @@ -88,25 +88,25 @@ func IsEmpty(value interface{}) bool { // ========================= // Common interfaces checks. // ========================= - if f, ok := value.(apiTime); ok { + if f, ok := value.(iTime); ok { if f == nil { return true } return f.IsZero() } - if f, ok := value.(apiString); ok { + if f, ok := value.(iString); ok { if f == nil { return true } return f.String() == "" } - if f, ok := value.(apiInterfaces); ok { + if f, ok := value.(iInterfaces); ok { if f == nil { return true } return len(f.Interfaces()) == 0 } - if f, ok := value.(apiMapStrAny); ok { + if f, ok := value.(iMapStrAny); ok { if f == nil { return true } @@ -210,25 +210,25 @@ func IsEmpty(value interface{}) bool { // // ========================= // // Common interfaces checks. // // ========================= -// if f, ok := value.(apiTime); ok { +// if f, ok := value.(iTime); ok { // if f == nil { // return true // } // return f.IsZero() // } -// if f, ok := value.(apiString); ok { +// if f, ok := value.(iString); ok { // if f == nil { // return true // } // return f.String() == "" // } -// if f, ok := value.(apiInterfaces); ok { +// if f, ok := value.(iInterfaces); ok { // if f == nil { // return true // } // return len(f.Interfaces()) == 0 // } -// if f, ok := value.(apiMapStrAny); ok { +// if f, ok := value.(iMapStrAny); ok { // if f == nil { // return true // } diff --git a/net/ghttp/ghttp.go b/net/ghttp/ghttp.go index f4f55c34b..7e7febfe3 100644 --- a/net/ghttp/ghttp.go +++ b/net/ghttp/ghttp.go @@ -95,12 +95,6 @@ type ( Handler *handlerItem // Handler object. } - // errorStack is the interface for Stack feature. - errorStack interface { - Error() string - Stack() string - } - // Listening file descriptor mapping. // The key is either "http" or "https" and the value is its FD. listenerFdMap = map[string]string diff --git a/net/ghttp/ghttp_func.go b/net/ghttp/ghttp_func.go index a4d96037e..3f440d61b 100644 --- a/net/ghttp/ghttp_func.go +++ b/net/ghttp/ghttp_func.go @@ -29,18 +29,18 @@ func niceCallFunc(f func()) { return default: - if _, ok := exception.(errorStack); ok { + if v, ok := exception.(error); ok && gerror.HasStack(v) { // It's already an error that has stack info. - panic(exception) + panic(v) } else { // Create a new error with stack info. // Note that there's a skip pointing the start stacktrace // of the real error point. - if err, ok := exception.(error); ok { - if gerror.Code(err) != gcode.CodeNil { - panic(err) + if v, ok := exception.(error); ok { + if gerror.Code(v) != gcode.CodeNil { + panic(v) } else { - panic(gerror.WrapCodeSkip(gcode.CodeInternalError, 1, err, "")) + panic(gerror.WrapCodeSkip(gcode.CodeInternalError, 1, v, "")) } } else { panic(gerror.NewCodeSkipf(gcode.CodeInternalError, 1, "%+v", exception)) diff --git a/net/ghttp/ghttp_request_middleware.go b/net/ghttp/ghttp_request_middleware.go index 7f7956a37..e1ad211a0 100644 --- a/net/ghttp/ghttp_request_middleware.go +++ b/net/ghttp/ghttp_request_middleware.go @@ -99,9 +99,9 @@ func (m *middleware) Next() { loop = false } }, func(exception error) { - if e, ok := exception.(errorStack); ok { + if v, ok := exception.(error); ok && gerror.HasStack(v) { // It's already an error that has stack info. - m.request.error = e + m.request.error = v } else { // Create a new error with stack info. // Note that there's a skip pointing the start stacktrace diff --git a/net/ghttp/ghttp_request_param.go b/net/ghttp/ghttp_request_param.go index 8c9689b2e..c6a044d97 100644 --- a/net/ghttp/ghttp_request_param.go +++ b/net/ghttp/ghttp_request_param.go @@ -70,7 +70,8 @@ func (r *Request) doParse(pointer interface{}, requestType int) error { reflectKind1 = reflectVal1.Kind() ) if reflectKind1 != reflect.Ptr { - return fmt.Errorf( + return gerror.NewCodef( + gcode.CodeInvalidParameter, "parameter should be type of *struct/**struct/*[]struct/*[]*struct, but got: %v", reflectKind1, ) @@ -174,7 +175,7 @@ func (r *Request) GetBody() []byte { // GetBodyString retrieves and returns request body content as string. // It can be called multiple times retrieving the same body content. func (r *Request) GetBodyString() string { - return gconv.UnsafeBytesToStr(r.GetBody()) + return string(r.GetBody()) } // GetJson parses current request content as JSON format, and returns the JSON object. @@ -374,7 +375,7 @@ func (r *Request) parseForm() { // It might be JSON/XML content. if s := gstr.Trim(name + strings.Join(values, " ")); len(s) > 0 { if s[0] == '{' && s[len(s)-1] == '}' || s[0] == '<' && s[len(s)-1] == '>' { - r.bodyContent = gconv.UnsafeStrToBytes(s) + r.bodyContent = []byte(s) params = "" break } diff --git a/net/ghttp/ghttp_server_graceful.go b/net/ghttp/ghttp_server_graceful.go index 8f6d60b53..2641d1424 100644 --- a/net/ghttp/ghttp_server_graceful.go +++ b/net/ghttp/ghttp_server_graceful.go @@ -9,7 +9,6 @@ package ghttp import ( "context" "crypto/tls" - "fmt" "github.com/gogf/gf/errors/gcode" "github.com/gogf/gf/errors/gerror" "github.com/gogf/gf/os/gproc" @@ -162,19 +161,21 @@ func (s *gracefulServer) doServe() error { // getNetListener retrieves and returns the wrapped net.Listener. func (s *gracefulServer) getNetListener() (net.Listener, error) { - var ln net.Listener - var err error + var ( + ln net.Listener + err error + ) if s.fd > 0 { f := os.NewFile(s.fd, "") ln, err = net.FileListener(f) if err != nil { - err = fmt.Errorf("%d: net.FileListener error: %v", gproc.Pid(), err) + err = gerror.WrapCodef(gcode.CodeInternalError, err, "%d: net.FileListener failed", gproc.Pid()) return nil, err } } else { ln, err = net.Listen("tcp", s.httpServer.Addr) if err != nil { - err = fmt.Errorf("%d: net.Listen error: %v", gproc.Pid(), err) + err = gerror.WrapCodef(gcode.CodeInternalError, err, "%d: net.Listen failed", gproc.Pid()) } } return ln, err diff --git a/net/ghttp/ghttp_server_handler.go b/net/ghttp/ghttp_server_handler.go index 30d747c80..d6d46bf04 100644 --- a/net/ghttp/ghttp_server_handler.go +++ b/net/ghttp/ghttp_server_handler.go @@ -67,11 +67,11 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { } else { if exception := recover(); exception != nil { request.Response.WriteStatus(http.StatusInternalServerError) - if err, ok := exception.(error); ok { - if code := gerror.Code(err); code != gcode.CodeNil { - s.handleErrorLog(err, request) + if v, ok := exception.(error); ok { + if code := gerror.Code(v); code != gcode.CodeNil { + s.handleErrorLog(v, request) } else { - s.handleErrorLog(gerror.WrapCodeSkip(gcode.CodeInternalError, 1, err, ""), request) + s.handleErrorLog(gerror.WrapCodeSkip(gcode.CodeInternalError, 1, v, ""), request) } } else { s.handleErrorLog(gerror.NewCodeSkipf(gcode.CodeInternalError, 1, "%+v", exception), request) diff --git a/net/ghttp/ghttp_server_router_serve.go b/net/ghttp/ghttp_server_router_serve.go index 00987de67..17fd011c1 100644 --- a/net/ghttp/ghttp_server_router_serve.go +++ b/net/ghttp/ghttp_server_router_serve.go @@ -10,6 +10,7 @@ import ( "fmt" "github.com/gogf/gf/errors/gcode" "github.com/gogf/gf/errors/gerror" + "github.com/gogf/gf/internal/intlog" "github.com/gogf/gf/internal/json" "strings" @@ -37,7 +38,10 @@ func (s *Server) serveHandlerKey(method, path, domain string) string { // getHandlersWithCache searches the router item with cache feature for given request. func (s *Server) getHandlersWithCache(r *Request) (parsedItems []*handlerParsedItem, hasHook, hasServe bool) { - method := r.Method + var ( + ctx = r.Context() + method = r.Method + ) // Special http method OPTIONS handling. // It searches the handler with the request method instead of OPTIONS method. if method == "OPTIONS" { @@ -46,7 +50,8 @@ func (s *Server) getHandlersWithCache(r *Request) (parsedItems []*handlerParsedI } } // Search and cache the router handlers. - value, _ := s.serveCache.GetOrSetFunc( + value, err := s.serveCache.GetOrSetFunc( + ctx, s.serveHandlerKey(method, r.URL.Path, r.GetHost()), func() (interface{}, error) { parsedItems, hasHook, hasServe = s.searchHandlers(method, r.URL.Path, r.GetHost()) @@ -55,8 +60,11 @@ func (s *Server) getHandlersWithCache(r *Request) (parsedItems []*handlerParsedI } return nil, nil }, routeCacheDuration) + if err != nil { + intlog.Error(ctx, err) + } if value != nil { - item := value.(*handlerCacheItem) + item := value.Val().(*handlerCacheItem) return item.parsedItems, item.hasHook, item.hasServe } return diff --git a/net/ghttp/internal/client/client_dump.go b/net/ghttp/internal/client/client_dump.go index 9ac718a65..38774ab36 100644 --- a/net/ghttp/internal/client/client_dump.go +++ b/net/ghttp/internal/client/client_dump.go @@ -12,8 +12,6 @@ import ( "io/ioutil" "net/http" "net/http/httputil" - - "github.com/gogf/gf/util/gconv" ) // dumpTextFormat is the format of the dumped raw string @@ -31,7 +29,7 @@ func getResponseBody(res *http.Response) string { } bodyContent, _ := ioutil.ReadAll(res.Body) res.Body = utils.NewReadCloser(bodyContent, true) - return gconv.UnsafeBytesToStr(bodyContent) + return string(bodyContent) } // RawRequest returns the raw content of the request. @@ -51,7 +49,7 @@ func (r *Response) RawRequest() string { return fmt.Sprintf( dumpTextFormat, "REQUEST ", - gconv.UnsafeBytesToStr(bs), + string(bs), r.requestBody, ) } @@ -70,7 +68,7 @@ func (r *Response) RawResponse() string { return fmt.Sprintf( dumpTextFormat, "RESPONSE", - gconv.UnsafeBytesToStr(bs), + string(bs), getResponseBody(r.Response), ) } diff --git a/net/ghttp/internal/client/client_response.go b/net/ghttp/internal/client/client_response.go index 324115ebf..54699562c 100644 --- a/net/ghttp/internal/client/client_response.go +++ b/net/ghttp/internal/client/client_response.go @@ -9,8 +9,6 @@ package client import ( "io/ioutil" "net/http" - - "github.com/gogf/gf/util/gconv" ) // Response is the struct for client request response. @@ -65,7 +63,7 @@ func (r *Response) ReadAll() []byte { // ReadAllString retrieves and returns the response content as string. func (r *Response) ReadAllString() string { - return gconv.UnsafeBytesToStr(r.ReadAll()) + return string(r.ReadAll()) } // Close closes the response when it will never be used. diff --git a/net/gsmtp/gsmtp.go b/net/gsmtp/gsmtp.go index 37c8dfd5d..a1096b2dc 100644 --- a/net/gsmtp/gsmtp.go +++ b/net/gsmtp/gsmtp.go @@ -14,12 +14,13 @@ package gsmtp import ( "encoding/base64" "fmt" - "github.com/gogf/gf/util/gconv" + "github.com/gogf/gf/errors/gcode" + "github.com/gogf/gf/errors/gerror" "net/smtp" "strings" ) -// SMTP is the structure for smtp connection +// SMTP is the structure for smtp connection. type SMTP struct { Address string Username string @@ -41,7 +42,7 @@ var ( ) // SendMail connects to the server at addr, switches to TLS if -// possible, authenticates with the optional mechanism a if possible, +// possible, authenticates with the optional mechanism an if possible, // and then sends an email from address <from>, to addresses <to>, with // message msg. // @@ -53,13 +54,21 @@ func (s *SMTP) SendMail(from, tos, subject, body string, contentType ...string) hp = strings.Split(s.Address, ":") ) if s.Address == "" || len(hp) > 2 { - return fmt.Errorf("server address is either empty or incorrect: %s", s.Address) + return gerror.NewCodef( + gcode.CodeInvalidParameter, + "server address is either empty or incorrect: %s", + s.Address, + ) } else if len(hp) == 1 { server = s.Address address = server + ":25" } else if len(hp) == 2 { if (hp[0] == "") || (hp[1] == "") { - return fmt.Errorf("server address is either empty or incorrect: %s", s.Address) + return gerror.NewCodef( + gcode.CodeInvalidParameter, + "server address is either empty or incorrect: %s", + s.Address, + ) } server = hp[0] address = s.Address @@ -75,17 +84,17 @@ func (s *SMTP) SendMail(from, tos, subject, body string, contentType ...string) } } if len(tosArr) == 0 { - return fmt.Errorf("tos if invalid: %s", tos) + return gerror.NewCodef(gcode.CodeInvalidParameter, `invalid parameter "tos": %s`, tos) } if !strings.Contains(from, "@") { - return fmt.Errorf("from is invalid: %s", from) + return gerror.NewCodef(gcode.CodeInvalidParameter, `invalid parameter "from": %s`, from) } header := map[string]string{ "From": from, "To": strings.Join(tosArr, ";"), - "Subject": fmt.Sprintf("=?UTF-8?B?%s?=", contentEncoding.EncodeToString(gconv.UnsafeStrToBytes(subject))), + "Subject": fmt.Sprintf("=?UTF-8?B?%s?=", contentEncoding.EncodeToString([]byte(subject))), "MIME-Version": "1.0", "Content-Type": "text/plain; charset=UTF-8", "Content-Transfer-Encoding": "base64", @@ -97,12 +106,12 @@ func (s *SMTP) SendMail(from, tos, subject, body string, contentType ...string) for k, v := range header { message += fmt.Sprintf("%s: %s\r\n", k, v) } - message += "\r\n" + contentEncoding.EncodeToString(gconv.UnsafeStrToBytes(body)) + message += "\r\n" + contentEncoding.EncodeToString([]byte(body)) return smtp.SendMail( address, smtp.PlainAuth("", s.Username, s.Password, server), from, tosArr, - gconv.UnsafeStrToBytes(message), + []byte(message), ) } diff --git a/net/gsmtp/gsmtp_test.go b/net/gsmtp/gsmtp_test.go index 9688a9fae..361cac1ca 100644 --- a/net/gsmtp/gsmtp_test.go +++ b/net/gsmtp/gsmtp_test.go @@ -34,7 +34,7 @@ func TestAddress(t *testing.T) { } func TestFrom(t *testing.T) { - errMessage := "from is invalid" + errMessage := `invalid parameter "from"` errValues := []string{ "", @@ -55,7 +55,7 @@ func TestFrom(t *testing.T) { } func TestTos(t *testing.T) { - errMessage := "tos if invalid" + errMessage := `invalid parameter "tos"` errValues := []string{ "", diff --git a/net/gtcp/gtcp_conn_pkg.go b/net/gtcp/gtcp_conn_pkg.go index ef090adcf..923217437 100644 --- a/net/gtcp/gtcp_conn_pkg.go +++ b/net/gtcp/gtcp_conn_pkg.go @@ -8,7 +8,8 @@ package gtcp import ( "encoding/binary" - "fmt" + "github.com/gogf/gf/errors/gcode" + "github.com/gogf/gf/errors/gerror" "time" ) @@ -46,7 +47,8 @@ func (c *Conn) SendPkg(data []byte, option ...PkgOption) error { } length := len(data) if length > pkgOption.MaxDataSize { - return fmt.Errorf( + return gerror.NewCodef( + gcode.CodeInvalidParameter, `data too long, data size %d exceeds allowed max data size %d`, length, pkgOption.MaxDataSize, ) @@ -116,7 +118,7 @@ func (c *Conn) RecvPkg(option ...PkgOption) (result []byte, err error) { // It here validates the size of the package. // It clears the buffer and returns error immediately if it validates failed. if length < 0 || length > pkgOption.MaxDataSize { - return nil, fmt.Errorf(`invalid package size %d`, length) + return nil, gerror.NewCodef(gcode.CodeInvalidParameter, `invalid package size %d`, length) } // Empty package. if length == 0 { @@ -147,7 +149,8 @@ func getPkgOption(option ...PkgOption) (*PkgOption, error) { pkgOption.HeaderSize = pkgHeaderSizeDefault } if pkgOption.HeaderSize > pkgHeaderSizeMax { - return nil, fmt.Errorf( + return nil, gerror.NewCodef( + gcode.CodeInvalidParameter, `package header size %d definition exceeds max header size %d`, pkgOption.HeaderSize, pkgHeaderSizeMax, ) @@ -166,7 +169,8 @@ func getPkgOption(option ...PkgOption) (*PkgOption, error) { } } if pkgOption.MaxDataSize > 0x7FFFFFFF { - return nil, fmt.Errorf( + return nil, gerror.NewCodef( + gcode.CodeInvalidParameter, `package data size %d definition exceeds allowed max data size %d`, pkgOption.MaxDataSize, 0x7FFFFFFF, ) diff --git a/os/gcache/gcache.go b/os/gcache/gcache.go index 8a0b1c07d..45782bc5f 100644 --- a/os/gcache/gcache.go +++ b/os/gcache/gcache.go @@ -5,6 +5,7 @@ // You can obtain one at https://github.com/gogf/gf. // Package gcache provides kinds of cache management for process. +// // It provides a concurrent-safe in-memory cache adapter for process in default. package gcache @@ -17,123 +18,164 @@ import ( // Default cache object. var defaultCache = New() -// Ctx is a chaining function, which shallowly clones current object and sets the context -// for next operation. -func Ctx(ctx context.Context) *Cache { - return defaultCache.Ctx(ctx) -} - // Set sets cache with `key`-`value` pair, which is expired after `duration`. -// It does not expire if `duration` == 0. -func Set(key interface{}, value interface{}, duration time.Duration) error { - return defaultCache.Set(key, value, duration) -} - -// SetIfNotExist sets cache with `key`-`value` pair if `key` does not exist in the cache, -// which is expired after `duration`. It does not expire if `duration` == 0. -func SetIfNotExist(key interface{}, value interface{}, duration time.Duration) (bool, error) { - return defaultCache.SetIfNotExist(key, value, duration) -} - -// Sets batch sets cache with key-value pairs by `data`, which is expired after `duration`. // // It does not expire if `duration` == 0. -func Sets(data map[interface{}]interface{}, duration time.Duration) error { - return defaultCache.Sets(data, duration) +// It deletes the keys of `data` if `duration` < 0 or given `value` is nil. +func Set(ctx context.Context, key interface{}, value interface{}, duration time.Duration) error { + return defaultCache.Set(ctx, key, value, duration) } -// Get returns the value of `key`. -// It returns nil if it does not exist or its value is nil. -func Get(key interface{}) (interface{}, error) { - return defaultCache.Get(key) -} - -// GetVar retrieves and returns the value of `key` as gvar.Var. -func GetVar(key interface{}) (*gvar.Var, error) { - return defaultCache.GetVar(key) -} - -// GetOrSet returns the value of `key`, -// or sets `key`-`value` pair and returns `value` if `key` does not exist in the cache. -// The key-value pair expires after `duration`. +// Sets batch sets cache with key-value pairs by `data` map, which is expired after `duration`. // // It does not expire if `duration` == 0. -func GetOrSet(key interface{}, value interface{}, duration time.Duration) (interface{}, error) { - return defaultCache.GetOrSet(key, value, duration) +// It deletes the keys of `data` if `duration` < 0 or given `value` is nil. +func Sets(ctx context.Context, data map[interface{}]interface{}, duration time.Duration) error { + return defaultCache.Sets(ctx, data, duration) } -// GetOrSetFunc returns the value of `key`, or sets `key` with result of function `f` -// and returns its result if `key` does not exist in the cache. The key-value pair expires -// after `duration`. It does not expire if `duration` == 0. -func GetOrSetFunc(key interface{}, f func() (interface{}, error), duration time.Duration) (interface{}, error) { - return defaultCache.GetOrSetFunc(key, f, duration) -} - -// GetOrSetFuncLock returns the value of `key`, or sets `key` with result of function `f` -// and returns its result if `key` does not exist in the cache. The key-value pair expires -// after `duration`. It does not expire if `duration` == 0. +// SetIfNotExist sets cache with `key`-`value` pair which is expired after `duration` +// if `key` does not exist in the cache. It returns true the `key` does not exist in the +// cache, and it sets `value` successfully to the cache, or else it returns false. // -// Note that the function `f` is executed within writing mutex lock. -func GetOrSetFuncLock(key interface{}, f func() (interface{}, error), duration time.Duration) (interface{}, error) { - return defaultCache.GetOrSetFuncLock(key, f, duration) +// It does not expire if `duration` == 0. +// It deletes the `key` if `duration` < 0 or given `value` is nil. +func SetIfNotExist(ctx context.Context, key interface{}, value interface{}, duration time.Duration) (bool, error) { + return defaultCache.SetIfNotExist(ctx, key, value, duration) } -// Contains returns true if `key` exists in the cache, or else returns false. -func Contains(key interface{}) (bool, error) { - return defaultCache.Contains(key) +// SetIfNotExistFunc sets `key` with result of function `f` and returns true +// if `key` does not exist in the cache, or else it does nothing and returns false if `key` already exists. +// +// The parameter `value` can be type of `func() interface{}`, but it does nothing if its +// result is nil. +// +// It does not expire if `duration` == 0. +// It deletes the `key` if `duration` < 0 or given `value` is nil. +func SetIfNotExistFunc(ctx context.Context, key interface{}, f func() (interface{}, error), duration time.Duration) (bool, error) { + return defaultCache.SetIfNotExistFunc(ctx, key, f, duration) } -// Remove deletes the one or more keys from cache, and returns its value. -// If multiple keys are given, it returns the value of the deleted last item. -func Remove(keys ...interface{}) (value interface{}, err error) { - return defaultCache.Remove(keys...) +// SetIfNotExistFuncLock sets `key` with result of function `f` and returns true +// if `key` does not exist in the cache, or else it does nothing and returns false if `key` already exists. +// +// It does not expire if `duration` == 0. +// It deletes the `key` if `duration` < 0 or given `value` is nil. +// +// Note that it differs from function `SetIfNotExistFunc` is that the function `f` is executed within +// writing mutex lock for concurrent safety purpose. +func SetIfNotExistFuncLock(ctx context.Context, key interface{}, f func() (interface{}, error), duration time.Duration) (bool, error) { + return defaultCache.SetIfNotExistFuncLock(ctx, key, f, duration) +} + +// Get retrieves and returns the associated value of given `key`. +// It returns nil if it does not exist, or its value is nil, or it's expired. +// If you would like to check if the `key` exists in the cache, it's better using function Contains. +func Get(ctx context.Context, key interface{}) (*gvar.Var, error) { + return defaultCache.Get(ctx, key) +} + +// GetOrSet retrieves and returns the value of `key`, or sets `key`-`value` pair and +// returns `value` if `key` does not exist in the cache. The key-value pair expires +// after `duration`. +// +// It does not expire if `duration` == 0. +// It deletes the `key` if `duration` < 0 or given `value` is nil, but it does nothing +// if `value` is a function and the function result is nil. +func GetOrSet(ctx context.Context, key interface{}, value interface{}, duration time.Duration) (*gvar.Var, error) { + return defaultCache.GetOrSet(ctx, key, value, duration) +} + +// GetOrSetFunc retrieves and returns the value of `key`, or sets `key` with result of +// function `f` and returns its result if `key` does not exist in the cache. The key-value +// pair expires after `duration`. +// +// It does not expire if `duration` == 0. +// It deletes the `key` if `duration` < 0 or given `value` is nil, but it does nothing +// if `value` is a function and the function result is nil. +func GetOrSetFunc(ctx context.Context, key interface{}, f func() (interface{}, error), duration time.Duration) (*gvar.Var, error) { + return defaultCache.GetOrSetFunc(ctx, key, f, duration) +} + +// GetOrSetFuncLock retrieves and returns the value of `key`, or sets `key` with result of +// function `f` and returns its result if `key` does not exist in the cache. The key-value +// pair expires after `duration`. +// +// It does not expire if `duration` == 0. +// It deletes the `key` if `duration` < 0 or given `value` is nil, but it does nothing +// if `value` is a function and the function result is nil. +// +// Note that it differs from function `GetOrSetFunc` is that the function `f` is executed within +// writing mutex lock for concurrent safety purpose. +func GetOrSetFuncLock(ctx context.Context, key interface{}, f func() (interface{}, error), duration time.Duration) (*gvar.Var, error) { + return defaultCache.GetOrSetFuncLock(ctx, key, f, duration) +} + +// Contains checks and returns true if `key` exists in the cache, or else returns false. +func Contains(ctx context.Context, key interface{}) (bool, error) { + return defaultCache.Contains(ctx, key) +} + +// GetExpire retrieves and returns the expiration of `key` in the cache. +// +// Note that, +// It returns 0 if the `key` does not expire. +// It returns -1 if the `key` does not exist in the cache. +func GetExpire(ctx context.Context, key interface{}) (time.Duration, error) { + return defaultCache.GetExpire(ctx, key) +} + +// Remove deletes one or more keys from cache, and returns its value. +// If multiple keys are given, it returns the value of the last deleted item. +func Remove(ctx context.Context, keys ...interface{}) (value *gvar.Var, err error) { + return defaultCache.Remove(ctx, keys...) } // Removes deletes `keys` in the cache. -// Deprecated, use Remove instead. -func Removes(keys []interface{}) { - defaultCache.Remove(keys...) -} - -// Data returns a copy of all key-value pairs in the cache as map type. -func Data() (map[interface{}]interface{}, error) { - return defaultCache.Data() -} - -// Keys returns all keys in the cache as slice. -func Keys() ([]interface{}, error) { - return defaultCache.Keys() -} - -// KeyStrings returns all keys in the cache as string slice. -func KeyStrings() ([]string, error) { - return defaultCache.KeyStrings() -} - -// Values returns all values in the cache as slice. -func Values() ([]interface{}, error) { - return defaultCache.Values() -} - -// Size returns the size of the cache. -func Size() (int, error) { - return defaultCache.Size() -} - -// GetExpire retrieves and returns the expiration of `key`. -// It returns -1 if the `key` does not exist in the cache. -func GetExpire(key interface{}) (time.Duration, error) { - return defaultCache.GetExpire(key) +func Removes(ctx context.Context, keys []interface{}) error { + return defaultCache.Removes(ctx, keys) } // Update updates the value of `key` without changing its expiration and returns the old value. -// The returned `exist` value is false if the `key` does not exist in the cache. -func Update(key interface{}, value interface{}) (oldValue interface{}, exist bool, err error) { - return defaultCache.Update(key, value) +// The returned value `exist` is false if the `key` does not exist in the cache. +// +// It deletes the `key` if given `value` is nil. +// It does nothing if `key` does not exist in the cache. +func Update(ctx context.Context, key interface{}, value interface{}) (oldValue *gvar.Var, exist bool, err error) { + return defaultCache.Update(ctx, key, value) } // UpdateExpire updates the expiration of `key` and returns the old expiration duration value. -// It returns -1 if the `key` does not exist in the cache. -func UpdateExpire(key interface{}, duration time.Duration) (oldDuration time.Duration, err error) { - return defaultCache.UpdateExpire(key, duration) +// +// It returns -1 and does nothing if the `key` does not exist in the cache. +// It deletes the `key` if `duration` < 0. +func UpdateExpire(ctx context.Context, key interface{}, duration time.Duration) (oldDuration time.Duration, err error) { + return defaultCache.UpdateExpire(ctx, key, duration) +} + +// Size returns the number of items in the cache. +func Size(ctx context.Context) (int, error) { + return defaultCache.Size(ctx) +} + +// Data returns a copy of all key-value pairs in the cache as map type. +// Note that this function may lead lots of memory usage, you can implement this function +// if necessary. +func Data(ctx context.Context) (map[interface{}]interface{}, error) { + return defaultCache.Data(ctx) +} + +// Keys returns all keys in the cache as slice. +func Keys(ctx context.Context) ([]interface{}, error) { + return defaultCache.Keys(ctx) +} + +// KeyStrings returns all keys in the cache as string slice. +func KeyStrings(ctx context.Context) ([]string, error) { + return defaultCache.KeyStrings(ctx) +} + +// Values returns all values in the cache as slice. +func Values(ctx context.Context) ([]interface{}, error) { + return defaultCache.Values(ctx) } diff --git a/os/gcache/gcache_adapter.go b/os/gcache/gcache_adapter.go index 33f179058..af2e23b17 100644 --- a/os/gcache/gcache_adapter.go +++ b/os/gcache/gcache_adapter.go @@ -8,18 +8,23 @@ package gcache import ( "context" + "github.com/gogf/gf/container/gvar" "time" ) // Adapter is the core adapter for cache features implements. +// +// Note that the implements should guarantee the concurrent safety calling its functions. +// You can implement one or more functions if necessary, it is suggested returning gcode.CodeNotImplemented error +// for those unimplemented functions. type Adapter interface { // Set sets cache with `key`-`value` pair, which is expired after `duration`. // // It does not expire if `duration` == 0. - // It deletes the `key` if `duration` < 0. + // It deletes the keys of `data` if `duration` < 0 or given `value` is nil. Set(ctx context.Context, key interface{}, value interface{}, duration time.Duration) error - // Sets batch sets cache with key-value pairs by `data`, which is expired after `duration`. + // Sets batch sets cache with key-value pairs by `data` map, which is expired after `duration`. // // It does not expire if `duration` == 0. // It deletes the keys of `data` if `duration` < 0 or given `value` is nil. @@ -29,16 +34,34 @@ type Adapter interface { // if `key` does not exist in the cache. It returns true the `key` does not exist in the // cache, and it sets `value` successfully to the cache, or else it returns false. // + // It does not expire if `duration` == 0. + // It deletes the `key` if `duration` < 0 or given `value` is nil. + SetIfNotExist(ctx context.Context, key interface{}, value interface{}, duration time.Duration) (ok bool, err error) + + // SetIfNotExistFunc sets `key` with result of function `f` and returns true + // if `key` does not exist in the cache, or else it does nothing and returns false if `key` already exists. + // // The parameter `value` can be type of `func() interface{}`, but it does nothing if its // result is nil. // // It does not expire if `duration` == 0. // It deletes the `key` if `duration` < 0 or given `value` is nil. - SetIfNotExist(ctx context.Context, key interface{}, value interface{}, duration time.Duration) (bool, error) + SetIfNotExistFunc(ctx context.Context, key interface{}, f func() (interface{}, error), duration time.Duration) (ok bool, err error) + + // SetIfNotExistFuncLock sets `key` with result of function `f` and returns true + // if `key` does not exist in the cache, or else it does nothing and returns false if `key` already exists. + // + // It does not expire if `duration` == 0. + // It deletes the `key` if `duration` < 0 or given `value` is nil. + // + // Note that it differs from function `SetIfNotExistFunc` is that the function `f` is executed within + // writing mutex lock for concurrent safety purpose. + SetIfNotExistFuncLock(ctx context.Context, key interface{}, f func() (interface{}, error), duration time.Duration) (ok bool, err error) // Get retrieves and returns the associated value of given `key`. - // It returns nil if it does not exist, its value is nil, or it's expired. - Get(ctx context.Context, key interface{}) (interface{}, error) + // It returns nil if it does not exist, or its value is nil, or it's expired. + // If you would like to check if the `key` exists in the cache, it's better using function Contains. + Get(ctx context.Context, key interface{}) (*gvar.Var, error) // GetOrSet retrieves and returns the value of `key`, or sets `key`-`value` pair and // returns `value` if `key` does not exist in the cache. The key-value pair expires @@ -47,7 +70,7 @@ type Adapter interface { // It does not expire if `duration` == 0. // It deletes the `key` if `duration` < 0 or given `value` is nil, but it does nothing // if `value` is a function and the function result is nil. - GetOrSet(ctx context.Context, key interface{}, value interface{}, duration time.Duration) (interface{}, error) + GetOrSet(ctx context.Context, key interface{}, value interface{}, duration time.Duration) (result *gvar.Var, err error) // GetOrSetFunc retrieves and returns the value of `key`, or sets `key` with result of // function `f` and returns its result if `key` does not exist in the cache. The key-value @@ -56,58 +79,60 @@ type Adapter interface { // It does not expire if `duration` == 0. // It deletes the `key` if `duration` < 0 or given `value` is nil, but it does nothing // if `value` is a function and the function result is nil. - GetOrSetFunc(ctx context.Context, key interface{}, f func() (interface{}, error), duration time.Duration) (interface{}, error) + GetOrSetFunc(ctx context.Context, key interface{}, f func() (interface{}, error), duration time.Duration) (result *gvar.Var, err error) // GetOrSetFuncLock retrieves and returns the value of `key`, or sets `key` with result of // function `f` and returns its result if `key` does not exist in the cache. The key-value // pair expires after `duration`. // // It does not expire if `duration` == 0. - // It does nothing if function `f` returns nil. + // It deletes the `key` if `duration` < 0 or given `value` is nil, but it does nothing + // if `value` is a function and the function result is nil. // - // Note that the function `f` should be executed within writing mutex lock for concurrent - // safety purpose. - GetOrSetFuncLock(ctx context.Context, key interface{}, f func() (interface{}, error), duration time.Duration) (interface{}, error) + // Note that it differs from function `GetOrSetFunc` is that the function `f` is executed within + // writing mutex lock for concurrent safety purpose. + GetOrSetFuncLock(ctx context.Context, key interface{}, f func() (interface{}, error), duration time.Duration) (result *gvar.Var, err error) - // Contains returns true if `key` exists in the cache, or else returns false. + // Contains checks and returns true if `key` exists in the cache, or else returns false. Contains(ctx context.Context, key interface{}) (bool, error) - // GetExpire retrieves and returns the expiration of `key` in the cache. - // - // It returns 0 if the `key` does not expire. - // It returns -1 if the `key` does not exist in the cache. - GetExpire(ctx context.Context, key interface{}) (time.Duration, error) - - // Remove deletes one or more keys from cache, and returns its value. - // If multiple keys are given, it returns the value of the last deleted item. - Remove(ctx context.Context, keys ...interface{}) (value interface{}, err error) - - // Update updates the value of `key` without changing its expiration and returns the old value. - // The returned value `exist` is false if the `key` does not exist in the cache. - // - // It deletes the `key` if given `value` is nil. - // It does nothing if `key` does not exist in the cache. - Update(ctx context.Context, key interface{}, value interface{}) (oldValue interface{}, exist bool, err error) - - // UpdateExpire updates the expiration of `key` and returns the old expiration duration value. - // - // It returns -1 and does nothing if the `key` does not exist in the cache. - // It deletes the `key` if `duration` < 0. - UpdateExpire(ctx context.Context, key interface{}, duration time.Duration) (oldDuration time.Duration, err error) - // Size returns the number of items in the cache. Size(ctx context.Context) (size int, err error) // Data returns a copy of all key-value pairs in the cache as map type. // Note that this function may lead lots of memory usage, you can implement this function // if necessary. - Data(ctx context.Context) (map[interface{}]interface{}, error) + Data(ctx context.Context) (data map[interface{}]interface{}, err error) // Keys returns all keys in the cache as slice. - Keys(ctx context.Context) ([]interface{}, error) + Keys(ctx context.Context) (keys []interface{}, err error) // Values returns all values in the cache as slice. - Values(ctx context.Context) ([]interface{}, error) + Values(ctx context.Context) (values []interface{}, err error) + + // Update updates the value of `key` without changing its expiration and returns the old value. + // The returned value `exist` is false if the `key` does not exist in the cache. + // + // It deletes the `key` if given `value` is nil. + // It does nothing if `key` does not exist in the cache. + Update(ctx context.Context, key interface{}, value interface{}) (oldValue *gvar.Var, exist bool, err error) + + // UpdateExpire updates the expiration of `key` and returns the old expiration duration value. + // + // It returns -1 and does nothing if the `key` does not exist in the cache. + // It deletes the `key` if `duration` < 0. + UpdateExpire(ctx context.Context, key interface{}, duration time.Duration) (oldDuration time.Duration, err error) + + // GetExpire retrieves and returns the expiration of `key` in the cache. + // + // Note that, + // It returns 0 if the `key` does not expire. + // It returns -1 if the `key` does not exist in the cache. + GetExpire(ctx context.Context, key interface{}) (time.Duration, error) + + // Remove deletes one or more keys from cache, and returns its value. + // If multiple keys are given, it returns the value of the last deleted item. + Remove(ctx context.Context, keys ...interface{}) (lastValue *gvar.Var, err error) // Clear clears all data of the cache. // Note that this function is sensitive and should be carefully used. diff --git a/os/gcache/gcache_adapter_memory.go b/os/gcache/gcache_adapter_memory.go index c70b2b3e3..47ac9fae5 100644 --- a/os/gcache/gcache_adapter_memory.go +++ b/os/gcache/gcache_adapter_memory.go @@ -8,6 +8,7 @@ package gcache import ( "context" + "github.com/gogf/gf/container/gvar" "math" "time" @@ -18,8 +19,8 @@ import ( "github.com/gogf/gf/os/gtimer" ) -// Internal cache object. -type adapterMemory struct { +// AdapterMemory is an adapter implements using memory. +type AdapterMemory struct { // cap limits the size of the cache pool. // If the size of the cache exceeds the cap, // the cache expiration process performs according to the LRU algorithm. @@ -52,9 +53,9 @@ const ( defaultMaxExpire = 9223372036854 ) -// newAdapterMemory creates and returns a new memory cache object. -func newAdapterMemory(lruCap ...int) *adapterMemory { - c := &adapterMemory{ +// NewAdapterMemory creates and returns a new memory cache object. +func NewAdapterMemory(lruCap ...int) Adapter { + c := &AdapterMemory{ data: newAdapterMemoryData(), lruGetList: glist.New(true), expireTimes: newAdapterMemoryExpireTimes(), @@ -72,8 +73,8 @@ func newAdapterMemory(lruCap ...int) *adapterMemory { // Set sets cache with `key`-`value` pair, which is expired after `duration`. // // It does not expire if `duration` == 0. -// It deletes the `key` if `duration` < 0. -func (c *adapterMemory) Set(ctx context.Context, key interface{}, value interface{}, duration time.Duration) error { +// It deletes the keys of `data` if `duration` < 0 or given `value` is nil. +func (c *AdapterMemory) Set(ctx context.Context, key interface{}, value interface{}, duration time.Duration) error { expireTime := c.getInternalExpire(duration) c.data.Set(key, adapterMemoryItem{ v: value, @@ -86,73 +87,11 @@ func (c *adapterMemory) Set(ctx context.Context, key interface{}, value interfac return nil } -// Update updates the value of `key` without changing its expiration and returns the old value. -// The returned value `exist` is false if the `key` does not exist in the cache. -// -// It deletes the `key` if given `value` is nil. -// It does nothing if `key` does not exist in the cache. -func (c *adapterMemory) Update(ctx context.Context, key interface{}, value interface{}) (oldValue interface{}, exist bool, err error) { - return c.data.Update(key, value) -} - -// UpdateExpire updates the expiration of `key` and returns the old expiration duration value. -// -// It returns -1 and does nothing if the `key` does not exist in the cache. -// It deletes the `key` if `duration` < 0. -func (c *adapterMemory) UpdateExpire(ctx context.Context, key interface{}, duration time.Duration) (oldDuration time.Duration, err error) { - newExpireTime := c.getInternalExpire(duration) - oldDuration, err = c.data.UpdateExpire(key, newExpireTime) - if err != nil { - return - } - if oldDuration != -1 { - c.eventList.PushBack(&adapterMemoryEvent{ - k: key, - e: newExpireTime, - }) - } - return -} - -// GetExpire retrieves and returns the expiration of `key` in the cache. -// -// It returns 0 if the `key` does not expire. -// It returns -1 if the `key` does not exist in the cache. -func (c *adapterMemory) GetExpire(ctx context.Context, key interface{}) (time.Duration, error) { - if item, ok := c.data.Get(key); ok { - return time.Duration(item.e-gtime.TimestampMilli()) * time.Millisecond, nil - } - return -1, nil -} - -// SetIfNotExist sets cache with `key`-`value` pair which is expired after `duration` -// if `key` does not exist in the cache. It returns true the `key` does not exist in the -// cache, and it sets `value` successfully to the cache, or else it returns false. -// The parameter `value` can be type of <func() interface{}>, but it dose nothing if its -// result is nil. -// -// It does not expire if `duration` == 0. -// It deletes the `key` if `duration` < 0 or given `value` is nil. -func (c *adapterMemory) SetIfNotExist(ctx context.Context, key interface{}, value interface{}, duration time.Duration) (bool, error) { - isContained, err := c.Contains(ctx, key) - if err != nil { - return false, err - } - if !isContained { - _, err := c.doSetWithLockCheck(key, value, duration) - if err != nil { - return false, err - } - return true, nil - } - return false, nil -} - -// Sets batch sets cache with key-value pairs by `data`, which is expired after `duration`. +// Sets batch sets cache with key-value pairs by `data` map, which is expired after `duration`. // // It does not expire if `duration` == 0. // It deletes the keys of `data` if `duration` < 0 or given `value` is nil. -func (c *adapterMemory) Sets(ctx context.Context, data map[interface{}]interface{}, duration time.Duration) error { +func (c *AdapterMemory) Sets(ctx context.Context, data map[interface{}]interface{}, duration time.Duration) error { var ( expireTime = c.getInternalExpire(duration) err = c.data.Sets(data, expireTime) @@ -169,16 +108,85 @@ func (c *adapterMemory) Sets(ctx context.Context, data map[interface{}]interface return nil } +// SetIfNotExist sets cache with `key`-`value` pair which is expired after `duration` +// if `key` does not exist in the cache. It returns true the `key` does not exist in the +// cache, and it sets `value` successfully to the cache, or else it returns false. +// +// It does not expire if `duration` == 0. +// It deletes the `key` if `duration` < 0 or given `value` is nil. +func (c *AdapterMemory) SetIfNotExist(ctx context.Context, key interface{}, value interface{}, duration time.Duration) (bool, error) { + isContained, err := c.Contains(ctx, key) + if err != nil { + return false, err + } + if !isContained { + if _, err = c.doSetWithLockCheck(key, value, duration); err != nil { + return false, err + } + return true, nil + } + return false, nil +} + +// SetIfNotExistFunc sets `key` with result of function `f` and returns true +// if `key` does not exist in the cache, or else it does nothing and returns false if `key` already exists. +// +// The parameter `value` can be type of `func() interface{}`, but it does nothing if its +// result is nil. +// +// It does not expire if `duration` == 0. +// It deletes the `key` if `duration` < 0 or given `value` is nil. +func (c *AdapterMemory) SetIfNotExistFunc(ctx context.Context, key interface{}, f func() (interface{}, error), duration time.Duration) (bool, error) { + isContained, err := c.Contains(ctx, key) + if err != nil { + return false, err + } + if !isContained { + value, err := f() + if err != nil { + return false, err + } + if _, err = c.doSetWithLockCheck(key, value, duration); err != nil { + return false, err + } + return true, nil + } + return false, nil +} + +// SetIfNotExistFuncLock sets `key` with result of function `f` and returns true +// if `key` does not exist in the cache, or else it does nothing and returns false if `key` already exists. +// +// It does not expire if `duration` == 0. +// It deletes the `key` if `duration` < 0 or given `value` is nil. +// +// Note that it differs from function `SetIfNotExistFunc` is that the function `f` is executed within +// writing mutex lock for concurrent safety purpose. +func (c *AdapterMemory) SetIfNotExistFuncLock(ctx context.Context, key interface{}, f func() (interface{}, error), duration time.Duration) (bool, error) { + isContained, err := c.Contains(ctx, key) + if err != nil { + return false, err + } + if !isContained { + if _, err = c.doSetWithLockCheck(key, f, duration); err != nil { + return false, err + } + return true, nil + } + return false, nil +} + // Get retrieves and returns the associated value of given `key`. -// It returns nil if it does not exist or its value is nil. -func (c *adapterMemory) Get(ctx context.Context, key interface{}) (interface{}, error) { +// It returns nil if it does not exist, or its value is nil, or it's expired. +// If you would like to check if the `key` exists in the cache, it's better using function Contains. +func (c *AdapterMemory) Get(ctx context.Context, key interface{}) (*gvar.Var, error) { item, ok := c.data.Get(key) if ok && !item.IsExpired() { // Adding to LRU history if LRU feature is enabled. if c.cap > 0 { c.lruGetList.PushBack(key) } - return item.v, nil + return gvar.New(item.v), nil } return nil, nil } @@ -190,7 +198,7 @@ func (c *adapterMemory) Get(ctx context.Context, key interface{}) (interface{}, // It does not expire if `duration` == 0. // It deletes the `key` if `duration` < 0 or given `value` is nil, but it does nothing // if `value` is a function and the function result is nil. -func (c *adapterMemory) GetOrSet(ctx context.Context, key interface{}, value interface{}, duration time.Duration) (interface{}, error) { +func (c *AdapterMemory) GetOrSet(ctx context.Context, key interface{}, value interface{}, duration time.Duration) (*gvar.Var, error) { v, err := c.Get(ctx, key) if err != nil { return nil, err @@ -209,7 +217,7 @@ func (c *adapterMemory) GetOrSet(ctx context.Context, key interface{}, value int // It does not expire if `duration` == 0. // It deletes the `key` if `duration` < 0 or given `value` is nil, but it does nothing // if `value` is a function and the function result is nil. -func (c *adapterMemory) GetOrSetFunc(ctx context.Context, key interface{}, f func() (interface{}, error), duration time.Duration) (interface{}, error) { +func (c *AdapterMemory) GetOrSetFunc(ctx context.Context, key interface{}, f func() (interface{}, error), duration time.Duration) (*gvar.Var, error) { v, err := c.Get(ctx, key) if err != nil { return nil, err @@ -233,11 +241,12 @@ func (c *adapterMemory) GetOrSetFunc(ctx context.Context, key interface{}, f fun // pair expires after `duration`. // // It does not expire if `duration` == 0. -// It does nothing if function `f` returns nil. +// It deletes the `key` if `duration` < 0 or given `value` is nil, but it does nothing +// if `value` is a function and the function result is nil. // -// Note that the function `f` should be executed within writing mutex lock for concurrent -// safety purpose. -func (c *adapterMemory) GetOrSetFuncLock(ctx context.Context, key interface{}, f func() (interface{}, error), duration time.Duration) (interface{}, error) { +// Note that it differs from function `GetOrSetFunc` is that the function `f` is executed within +// writing mutex lock for concurrent safety purpose. +func (c *AdapterMemory) GetOrSetFuncLock(ctx context.Context, key interface{}, f func() (interface{}, error), duration time.Duration) (*gvar.Var, error) { v, err := c.Get(ctx, key) if err != nil { return nil, err @@ -249,8 +258,8 @@ func (c *adapterMemory) GetOrSetFuncLock(ctx context.Context, key interface{}, f } } -// Contains returns true if `key` exists in the cache, or else returns false. -func (c *adapterMemory) Contains(ctx context.Context, key interface{}) (bool, error) { +// Contains checks and returns true if `key` exists in the cache, or else returns false. +func (c *AdapterMemory) Contains(ctx context.Context, key interface{}) (bool, error) { v, err := c.Get(ctx, key) if err != nil { return false, err @@ -258,13 +267,25 @@ func (c *adapterMemory) Contains(ctx context.Context, key interface{}) (bool, er return v != nil, nil } -// Remove deletes the one or more keys from cache, and returns its value. -// If multiple keys are given, it returns the value of the deleted last item. -func (c *adapterMemory) Remove(ctx context.Context, keys ...interface{}) (value interface{}, err error) { +// GetExpire retrieves and returns the expiration of `key` in the cache. +// +// Note that, +// It returns 0 if the `key` does not expire. +// It returns -1 if the `key` does not exist in the cache. +func (c *AdapterMemory) GetExpire(ctx context.Context, key interface{}) (time.Duration, error) { + if item, ok := c.data.Get(key); ok { + return time.Duration(item.e-gtime.TimestampMilli()) * time.Millisecond, nil + } + return -1, nil +} + +// Remove deletes one or more keys from cache, and returns its value. +// If multiple keys are given, it returns the value of the last deleted item. +func (c *AdapterMemory) Remove(ctx context.Context, keys ...interface{}) (*gvar.Var, error) { var removedKeys []interface{} - removedKeys, value, err = c.data.Remove(keys...) + removedKeys, value, err := c.data.Remove(keys...) if err != nil { - return + return nil, err } for _, key := range removedKeys { c.eventList.PushBack(&adapterMemoryEvent{ @@ -272,37 +293,66 @@ func (c *adapterMemory) Remove(ctx context.Context, keys ...interface{}) (value e: gtime.TimestampMilli() - 1000000, }) } + return gvar.New(value), nil +} + +// Update updates the value of `key` without changing its expiration and returns the old value. +// The returned value `exist` is false if the `key` does not exist in the cache. +// +// It deletes the `key` if given `value` is nil. +// It does nothing if `key` does not exist in the cache. +func (c *AdapterMemory) Update(ctx context.Context, key interface{}, value interface{}) (oldValue *gvar.Var, exist bool, err error) { + v, exist, err := c.data.Update(key, value) + return gvar.New(v), exist, err +} + +// UpdateExpire updates the expiration of `key` and returns the old expiration duration value. +// +// It returns -1 and does nothing if the `key` does not exist in the cache. +// It deletes the `key` if `duration` < 0. +func (c *AdapterMemory) UpdateExpire(ctx context.Context, key interface{}, duration time.Duration) (oldDuration time.Duration, err error) { + newExpireTime := c.getInternalExpire(duration) + oldDuration, err = c.data.UpdateExpire(key, newExpireTime) + if err != nil { + return + } + if oldDuration != -1 { + c.eventList.PushBack(&adapterMemoryEvent{ + k: key, + e: newExpireTime, + }) + } return } +// Size returns the size of the cache. +func (c *AdapterMemory) Size(ctx context.Context) (size int, err error) { + return c.data.Size() +} + // Data returns a copy of all key-value pairs in the cache as map type. -func (c *adapterMemory) Data(ctx context.Context) (map[interface{}]interface{}, error) { +func (c *AdapterMemory) Data(ctx context.Context) (map[interface{}]interface{}, error) { return c.data.Data() } // Keys returns all keys in the cache as slice. -func (c *adapterMemory) Keys(ctx context.Context) ([]interface{}, error) { +func (c *AdapterMemory) Keys(ctx context.Context) ([]interface{}, error) { return c.data.Keys() } // Values returns all values in the cache as slice. -func (c *adapterMemory) Values(ctx context.Context) ([]interface{}, error) { +func (c *AdapterMemory) Values(ctx context.Context) ([]interface{}, error) { return c.data.Values() } -// Size returns the size of the cache. -func (c *adapterMemory) Size(ctx context.Context) (size int, err error) { - return c.data.Size() -} - // Clear clears all data of the cache. // Note that this function is sensitive and should be carefully used. -func (c *adapterMemory) Clear(ctx context.Context) error { +func (c *AdapterMemory) Clear(ctx context.Context) error { return c.data.Clear() } // Close closes the cache. -func (c *adapterMemory) Close(ctx context.Context) error { +func (c *AdapterMemory) Close(ctx context.Context) error { if c.cap > 0 { c.lru.Close() } @@ -314,20 +364,20 @@ func (c *adapterMemory) Close(ctx context.Context) error { // cache, which is expired after `duration`. // // It does not expire if `duration` == 0. -// The parameter `value` can be type of <func() interface{}>, but it dose nothing if the +// The parameter `value` can be type of <func() interface{}>, but it does nothing if the // function result is nil. // // It doubly checks the `key` whether exists in the cache using mutex writing lock // before setting it to the cache. -func (c *adapterMemory) doSetWithLockCheck(key interface{}, value interface{}, duration time.Duration) (result interface{}, err error) { +func (c *AdapterMemory) doSetWithLockCheck(key interface{}, value interface{}, duration time.Duration) (result *gvar.Var, err error) { expireTimestamp := c.getInternalExpire(duration) - result, err = c.data.SetWithLock(key, value, expireTimestamp) + v, err := c.data.SetWithLock(key, value, expireTimestamp) c.eventList.PushBack(&adapterMemoryEvent{k: key, e: expireTimestamp}) - return + return gvar.New(v), err } -// getInternalExpire converts and returns the expire time with given expired duration in milliseconds. -func (c *adapterMemory) getInternalExpire(duration time.Duration) int64 { +// getInternalExpire converts and returns the expiration time with given expired duration in milliseconds. +func (c *AdapterMemory) getInternalExpire(duration time.Duration) int64 { if duration == 0 { return defaultMaxExpire } else { @@ -336,7 +386,7 @@ func (c *adapterMemory) getInternalExpire(duration time.Duration) int64 { } // makeExpireKey groups the `expire` in milliseconds to its according seconds. -func (c *adapterMemory) makeExpireKey(expire int64) int64 { +func (c *AdapterMemory) makeExpireKey(expire int64) int64 { return int64(math.Ceil(float64(expire/1000)+1) * 1000) } @@ -344,7 +394,7 @@ func (c *adapterMemory) makeExpireKey(expire int64) int64 { // 1. Asynchronously process the data in the event list, // and synchronize the results to the `expireTimes` and `expireSets` properties. // 2. Clean up the expired key-value pair data. -func (c *adapterMemory) syncEventAndClearExpired() { +func (c *AdapterMemory) syncEventAndClearExpired() { if c.closed.Val() { gtimer.Exit() return @@ -365,14 +415,14 @@ func (c *adapterMemory) syncEventAndClearExpired() { event = v.(*adapterMemoryEvent) // Fetching the old expire set. oldExpireTime = c.expireTimes.Get(event.k) - // Calculating the new expire set. + // Calculating the new expiration time set. newExpireTime = c.makeExpireKey(event.e) if newExpireTime != oldExpireTime { c.expireSets.GetOrNew(newExpireTime).Add(event.k) if oldExpireTime != 0 { c.expireSets.GetOrNew(oldExpireTime).Remove(event.k) } - // Updating the expire time for <event.k>. + // Updating the expired time for <event.k>. c.expireTimes.Set(event.k, newExpireTime) } // Adding the key the LRU history by writing operations. @@ -413,11 +463,11 @@ func (c *adapterMemory) syncEventAndClearExpired() { // clearByKey deletes the key-value pair with given `key`. // The parameter `force` specifies whether doing this deleting forcibly. -func (c *adapterMemory) clearByKey(key interface{}, force ...bool) { +func (c *AdapterMemory) clearByKey(key interface{}, force ...bool) { // Doubly check before really deleting it from cache. c.data.DeleteWithDoubleCheck(key, force...) - // Deleting its expire time from `expireTimes`. + // Deleting its expiration time from `expireTimes`. c.expireTimes.Delete(key) // Deleting it from LRU. diff --git a/os/gcache/gcache_adapter_memory_lru.go b/os/gcache/gcache_adapter_memory_lru.go index c2f2a64d5..6ff25e4fd 100644 --- a/os/gcache/gcache_adapter_memory_lru.go +++ b/os/gcache/gcache_adapter_memory_lru.go @@ -18,7 +18,7 @@ import ( // LRU cache object. // It uses list.List from stdlib for its underlying doubly linked list. type adapterMemoryLru struct { - cache *adapterMemory // Parent cache object. + cache *AdapterMemory // Parent cache object. data *gmap.Map // Key mapping to the item of the list. list *glist.List // Key list. rawList *glist.List // History for key adding. @@ -26,7 +26,7 @@ type adapterMemoryLru struct { } // newMemCacheLru creates and returns a new LRU object. -func newMemCacheLru(cache *adapterMemory) *adapterMemoryLru { +func newMemCacheLru(cache *AdapterMemory) *adapterMemoryLru { lru := &adapterMemoryLru{ cache: cache, data: gmap.New(true), diff --git a/os/gcache/gcache_cache.go b/os/gcache/gcache_cache.go index 216549bd9..66bc7a9f9 100644 --- a/os/gcache/gcache_cache.go +++ b/os/gcache/gcache_cache.go @@ -8,7 +8,6 @@ package gcache import ( "context" - "github.com/gogf/gf/container/gvar" "github.com/gogf/gf/os/gtimer" "github.com/gogf/gf/util/gconv" "time" @@ -16,72 +15,50 @@ import ( // Cache struct. type Cache struct { - adapter Adapter // Adapter for cache features. - ctx context.Context // Context for operations. + localAdapter } +// localAdapter is alias of Adapter, for embedded attribute purpose only. +type localAdapter = Adapter + // New creates and returns a new cache object using default memory adapter. // Note that the LRU feature is only available using memory adapter. func New(lruCap ...int) *Cache { - memAdapter := newAdapterMemory(lruCap...) + memAdapter := NewAdapterMemory(lruCap...) c := &Cache{ - adapter: memAdapter, + localAdapter: memAdapter, } // Here may be a "timer leak" if adapter is manually changed from memory adapter. - // Do not worry about this, as adapter is less changed and it dose nothing if it's not used. - gtimer.AddSingleton(time.Second, memAdapter.syncEventAndClearExpired) + // Do not worry about this, as adapter is less changed, and it does nothing if it's not used. + gtimer.AddSingleton(time.Second, memAdapter.(*AdapterMemory).syncEventAndClearExpired) return c } -// Clone returns a shallow copy of current object. -func (c *Cache) Clone() *Cache { +// NewWithAdapter creates and returns a Cache object with given Adapter implements. +func NewWithAdapter(adapter Adapter) *Cache { return &Cache{ - adapter: c.adapter, - ctx: c.ctx, + localAdapter: adapter, } } -// Ctx is a chaining function, which shallowly clones current object and sets the context -// for next operation. -func (c *Cache) Ctx(ctx context.Context) *Cache { - newCache := c.Clone() - newCache.ctx = ctx - return newCache -} - // SetAdapter changes the adapter for this cache. // Be very note that, this setting function is not concurrent-safe, which means you should not call // this setting function concurrently in multiple goroutines. func (c *Cache) SetAdapter(adapter Adapter) { - c.adapter = adapter -} - -// GetVar retrieves and returns the value of `key` as gvar.Var. -func (c *Cache) GetVar(key interface{}) (*gvar.Var, error) { - v, err := c.Get(key) - return gvar.New(v), err + c.localAdapter = adapter } // Removes deletes `keys` in the cache. -// Deprecated, use Remove instead. -func (c *Cache) Removes(keys []interface{}) error { - _, err := c.Remove(keys...) +func (c *Cache) Removes(ctx context.Context, keys []interface{}) error { + _, err := c.Remove(ctx, keys...) return err } // KeyStrings returns all keys in the cache as string slice. -func (c *Cache) KeyStrings() ([]string, error) { - keys, err := c.Keys() +func (c *Cache) KeyStrings(ctx context.Context) ([]string, error) { + keys, err := c.Keys(ctx) if err != nil { return nil, err } return gconv.Strings(keys), nil } - -// KeyStrings returns all keys in the cache as string slice. -func (c *Cache) getCtx() context.Context { - if c.ctx == nil { - return context.Background() - } - return c.ctx -} diff --git a/os/gcache/gcache_cache_adapter.go b/os/gcache/gcache_cache_adapter.go deleted file mode 100644 index dce6b19ef..000000000 --- a/os/gcache/gcache_cache_adapter.go +++ /dev/null @@ -1,150 +0,0 @@ -// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. -// -// This Source Code Form is subject to the terms of the MIT License. -// If a copy of the MIT was not distributed with this file, -// You can obtain one at https://github.com/gogf/gf. - -package gcache - -import ( - "time" -) - -// Set sets cache with `key`-`value` pair, which is expired after `duration`. -// -// It does not expire if `duration` == 0. -// It deletes the `key` if `duration` < 0. -func (c *Cache) Set(key interface{}, value interface{}, duration time.Duration) error { - return c.adapter.Set(c.getCtx(), key, value, duration) -} - -// Sets batch sets cache with key-value pairs by `data`, which is expired after `duration`. -// -// It does not expire if `duration` == 0. -// It deletes the keys of `data` if `duration` < 0 or given `value` is nil. -func (c *Cache) Sets(data map[interface{}]interface{}, duration time.Duration) error { - return c.adapter.Sets(c.getCtx(), data, duration) -} - -// SetIfNotExist sets cache with `key`-`value` pair which is expired after `duration` -// if `key` does not exist in the cache. It returns true the `key` does not exist in the -// cache, and it sets `value` successfully to the cache, or else it returns false. -// -// The parameter `value` can be type of <func() interface{}>, but it does nothing if its -// result is nil. -// -// It does not expire if `duration` == 0. -// It deletes the `key` if `duration` < 0 or given `value` is nil. -func (c *Cache) SetIfNotExist(key interface{}, value interface{}, duration time.Duration) (bool, error) { - return c.adapter.SetIfNotExist(c.getCtx(), key, value, duration) -} - -// Get retrieves and returns the associated value of given `key`. -// It returns nil if it does not exist, its value is nil or it's expired. -func (c *Cache) Get(key interface{}) (interface{}, error) { - return c.adapter.Get(c.getCtx(), key) -} - -// GetOrSet retrieves and returns the value of `key`, or sets `key`-`value` pair and -// returns `value` if `key` does not exist in the cache. The key-value pair expires -// after `duration`. -// -// It does not expire if `duration` == 0. -// It deletes the `key` if `duration` < 0 or given `value` is nil, but it does nothing -// if `value` is a function and the function result is nil. -func (c *Cache) GetOrSet(key interface{}, value interface{}, duration time.Duration) (interface{}, error) { - return c.adapter.GetOrSet(c.getCtx(), key, value, duration) -} - -// GetOrSetFunc retrieves and returns the value of `key`, or sets `key` with result of -// function `f` and returns its result if `key` does not exist in the cache. The key-value -// pair expires after `duration`. -// -// It does not expire if `duration` == 0. -// It deletes the `key` if `duration` < 0 or given `value` is nil, but it does nothing -// if `value` is a function and the function result is nil. -func (c *Cache) GetOrSetFunc(key interface{}, f func() (interface{}, error), duration time.Duration) (interface{}, error) { - return c.adapter.GetOrSetFunc(c.getCtx(), key, f, duration) -} - -// GetOrSetFuncLock retrieves and returns the value of `key`, or sets `key` with result of -// function `f` and returns its result if `key` does not exist in the cache. The key-value -// pair expires after `duration`. -// -// It does not expire if `duration` == 0. -// It does nothing if function `f` returns nil. -// -// Note that the function `f` should be executed within writing mutex lock for concurrent -// safety purpose. -func (c *Cache) GetOrSetFuncLock(key interface{}, f func() (interface{}, error), duration time.Duration) (interface{}, error) { - return c.adapter.GetOrSetFuncLock(c.getCtx(), key, f, duration) -} - -// Contains returns true if `key` exists in the cache, or else returns false. -func (c *Cache) Contains(key interface{}) (bool, error) { - return c.adapter.Contains(c.getCtx(), key) -} - -// GetExpire retrieves and returns the expiration of `key` in the cache. -// -// It returns 0 if the `key` does not expire. -// It returns -1 if the `key` does not exist in the cache. -func (c *Cache) GetExpire(key interface{}) (time.Duration, error) { - return c.adapter.GetExpire(c.getCtx(), key) -} - -// Remove deletes one or more keys from cache, and returns its value. -// If multiple keys are given, it returns the value of the last deleted item. -func (c *Cache) Remove(keys ...interface{}) (value interface{}, err error) { - return c.adapter.Remove(c.getCtx(), keys...) -} - -// Update updates the value of `key` without changing its expiration and returns the old value. -// The returned value `exist` is false if the `key` does not exist in the cache. -// -// It deletes the `key` if given `value` is nil. -// It does nothing if `key` does not exist in the cache. -func (c *Cache) Update(key interface{}, value interface{}) (oldValue interface{}, exist bool, err error) { - return c.adapter.Update(c.getCtx(), key, value) -} - -// UpdateExpire updates the expiration of `key` and returns the old expiration duration value. -// -// It returns -1 and does nothing if the `key` does not exist in the cache. -// It deletes the `key` if `duration` < 0. -func (c *Cache) UpdateExpire(key interface{}, duration time.Duration) (oldDuration time.Duration, err error) { - return c.adapter.UpdateExpire(c.getCtx(), key, duration) -} - -// Size returns the number of items in the cache. -func (c *Cache) Size() (size int, err error) { - return c.adapter.Size(c.getCtx()) -} - -// Data returns a copy of all key-value pairs in the cache as map type. -// Note that this function may lead lots of memory usage, you can implement this function -// if necessary. -func (c *Cache) Data() (map[interface{}]interface{}, error) { - return c.adapter.Data(c.getCtx()) -} - -// Keys returns all keys in the cache as slice. -func (c *Cache) Keys() ([]interface{}, error) { - return c.adapter.Keys(c.getCtx()) -} - -// Values returns all values in the cache as slice. -func (c *Cache) Values() ([]interface{}, error) { - return c.adapter.Values(c.getCtx()) -} - -// Clear clears all data of the cache. -// Note that this function is sensitive and should be carefully used. -func (c *Cache) Clear() error { - return c.adapter.Clear(c.getCtx()) -} - -// Close closes the cache if necessary. -func (c *Cache) Close() error { - return c.adapter.Close(c.getCtx()) -} diff --git a/os/gcache/gcache_z_bench_test.go b/os/gcache/gcache_z_bench_test.go index 028c07beb..5d98b2a58 100644 --- a/os/gcache/gcache_z_bench_test.go +++ b/os/gcache/gcache_z_bench_test.go @@ -9,6 +9,7 @@ package gcache_test import ( + "context" "testing" "github.com/gogf/gf/os/gcache" @@ -23,7 +24,7 @@ func Benchmark_CacheSet(b *testing.B) { b.RunParallel(func(pb *testing.PB) { i := 0 for pb.Next() { - localCache.Set(i, i, 0) + localCache.Set(ctx, i, i, 0) i++ } }) @@ -33,7 +34,7 @@ func Benchmark_CacheGet(b *testing.B) { b.RunParallel(func(pb *testing.PB) { i := 0 for pb.Next() { - localCache.Get(i) + localCache.Get(ctx, i) i++ } }) @@ -43,7 +44,7 @@ func Benchmark_CacheRemove(b *testing.B) { b.RunParallel(func(pb *testing.PB) { i := 0 for pb.Next() { - localCache.Remove(i) + localCache.Remove(ctx, i) i++ } }) @@ -53,7 +54,7 @@ func Benchmark_CacheLruSet(b *testing.B) { b.RunParallel(func(pb *testing.PB) { i := 0 for pb.Next() { - localCacheLru.Set(i, i, 0) + localCacheLru.Set(ctx, i, i, 0) i++ } }) @@ -63,7 +64,7 @@ func Benchmark_CacheLruGet(b *testing.B) { b.RunParallel(func(pb *testing.PB) { i := 0 for pb.Next() { - localCacheLru.Get(i) + localCacheLru.Get(ctx, i) i++ } }) @@ -73,7 +74,7 @@ func Benchmark_CacheLruRemove(b *testing.B) { b.RunParallel(func(pb *testing.PB) { i := 0 for pb.Next() { - localCacheLru.Remove(i) + localCacheLru.Remove(context.TODO(), i) i++ } }) diff --git a/os/gcache/gcache_z_unit_basic_test.go b/os/gcache/gcache_z_unit_basic_test.go index 9ea748cd3..8620089a8 100644 --- a/os/gcache/gcache_z_unit_basic_test.go +++ b/os/gcache/gcache_z_unit_basic_test.go @@ -22,13 +22,17 @@ import ( "github.com/gogf/gf/test/gtest" ) +var ( + ctx = context.Background() +) + func TestCache_GCache_Set(t *testing.T) { gtest.C(t, func(t *gtest.T) { - gcache.Set(1, 11, 0) - defer gcache.Removes(g.Slice{1, 2, 3}) - v, _ := gcache.Get(1) + t.AssertNil(gcache.Set(ctx, 1, 11, 0)) + defer gcache.Remove(ctx, g.Slice{1, 2, 3}...) + v, _ := gcache.Get(ctx, 1) t.Assert(v, 11) - b, _ := gcache.Contains(1) + b, _ := gcache.Contains(ctx, 1) t.Assert(b, true) }) } @@ -36,81 +40,70 @@ func TestCache_GCache_Set(t *testing.T) { func TestCache_Set(t *testing.T) { gtest.C(t, func(t *gtest.T) { c := gcache.New() - defer c.Close() - t.Assert(c.Set(1, 11, 0), nil) - v, _ := c.Get(1) + defer c.Close(ctx) + t.Assert(c.Set(ctx, 1, 11, 0), nil) + v, _ := c.Get(ctx, 1) t.Assert(v, 11) - b, _ := c.Contains(1) + b, _ := c.Contains(ctx, 1) t.Assert(b, true) }) } -func TestCache_GetVar(t *testing.T) { - c := gcache.New() - defer c.Close() - gtest.C(t, func(t *gtest.T) { - t.Assert(c.Set(1, 11, 0), nil) - v, _ := c.Get(1) - t.Assert(v, 11) - b, _ := c.Contains(1) - t.Assert(b, true) - }) - gtest.C(t, func(t *gtest.T) { - v, _ := c.GetVar(1) - t.Assert(v.Int(), 11) - v, _ = c.GetVar(2) - t.Assert(v.Int(), 0) - t.Assert(v.IsNil(), true) - t.Assert(v.IsEmpty(), true) - }) -} - func TestCache_Set_Expire(t *testing.T) { gtest.C(t, func(t *gtest.T) { cache := gcache.New() - t.Assert(cache.Set(2, 22, 100*time.Millisecond), nil) - v, _ := cache.Get(2) + t.Assert(cache.Set(ctx, 2, 22, 100*time.Millisecond), nil) + v, _ := cache.Get(ctx, 2) t.Assert(v, 22) time.Sleep(200 * time.Millisecond) - v, _ = cache.Get(2) + v, _ = cache.Get(ctx, 2) t.Assert(v, nil) time.Sleep(3 * time.Second) - n, _ := cache.Size() + n, _ := cache.Size(ctx) t.Assert(n, 0) - t.Assert(cache.Close(), nil) + t.Assert(cache.Close(ctx), nil) }) gtest.C(t, func(t *gtest.T) { cache := gcache.New() - t.Assert(cache.Set(1, 11, 100*time.Millisecond), nil) - v, _ := cache.Get(1) + t.Assert(cache.Set(ctx, 1, 11, 100*time.Millisecond), nil) + v, _ := cache.Get(ctx, 1) t.Assert(v, 11) time.Sleep(200 * time.Millisecond) - v, _ = cache.Get(1) + v, _ = cache.Get(ctx, 1) t.Assert(v, nil) }) } -func TestCache_Update_GetExpire(t *testing.T) { +func TestCache_Update(t *testing.T) { // gcache gtest.C(t, func(t *gtest.T) { key := guid.S() - gcache.Set(key, 11, 3*time.Second) - expire1, _ := gcache.GetExpire(key) - gcache.Update(key, 12) - expire2, _ := gcache.GetExpire(key) - v, _ := gcache.GetVar(key) + t.AssertNil(gcache.Set(ctx, key, 11, 3*time.Second)) + expire1, _ := gcache.GetExpire(ctx, key) + oldValue, exist, err := gcache.Update(ctx, key, 12) + t.AssertNil(err) + t.Assert(oldValue, 11) + t.Assert(exist, true) + + expire2, _ := gcache.GetExpire(ctx, key) + v, _ := gcache.Get(ctx, key) t.Assert(v, 12) t.Assert(math.Ceil(expire1.Seconds()), math.Ceil(expire2.Seconds())) }) // gcache.Cache gtest.C(t, func(t *gtest.T) { cache := gcache.New() - cache.Set(1, 11, 3*time.Second) - expire1, _ := cache.GetExpire(1) - cache.Update(1, 12) - expire2, _ := cache.GetExpire(1) - v, _ := cache.GetVar(1) + t.AssertNil(cache.Set(ctx, 1, 11, 3*time.Second)) + + oldValue, exist, err := cache.Update(ctx, 1, 12) + t.AssertNil(err) + t.Assert(oldValue, 11) + t.Assert(exist, true) + + expire1, _ := cache.GetExpire(ctx, 1) + expire2, _ := cache.GetExpire(ctx, 1) + v, _ := cache.Get(ctx, 1) t.Assert(v, 12) t.Assert(math.Ceil(expire1.Seconds()), math.Ceil(expire2.Seconds())) }) @@ -120,27 +113,33 @@ func TestCache_UpdateExpire(t *testing.T) { // gcache gtest.C(t, func(t *gtest.T) { key := guid.S() - gcache.Set(key, 11, 3*time.Second) - defer gcache.Remove(key) - oldExpire, _ := gcache.GetExpire(key) + t.AssertNil(gcache.Set(ctx, key, 11, 3*time.Second)) + defer gcache.Remove(ctx, key) + oldExpire, _ := gcache.GetExpire(ctx, key) newExpire := 10 * time.Second - gcache.UpdateExpire(key, newExpire) - e, _ := gcache.GetExpire(key) + oldExpire2, err := gcache.UpdateExpire(ctx, key, newExpire) + t.AssertNil(err) + t.Assert(oldExpire2, oldExpire) + + e, _ := gcache.GetExpire(ctx, key) t.AssertNE(e, oldExpire) - e, _ = gcache.GetExpire(key) + e, _ = gcache.GetExpire(ctx, key) t.Assert(math.Ceil(e.Seconds()), 10) }) // gcache.Cache gtest.C(t, func(t *gtest.T) { cache := gcache.New() - cache.Set(1, 11, 3*time.Second) - oldExpire, _ := cache.GetExpire(1) + t.AssertNil(cache.Set(ctx, 1, 11, 3*time.Second)) + oldExpire, _ := cache.GetExpire(ctx, 1) newExpire := 10 * time.Second - cache.UpdateExpire(1, newExpire) - e, _ := cache.GetExpire(1) + oldExpire2, err := cache.UpdateExpire(ctx, 1, newExpire) + t.AssertNil(err) + t.Assert(oldExpire2, oldExpire) + + e, _ := cache.GetExpire(ctx, 1) t.AssertNE(e, oldExpire) - e, _ = cache.GetExpire(1) + e, _ = cache.GetExpire(ctx, 1) t.Assert(math.Ceil(e.Seconds()), 10) }) } @@ -149,11 +148,11 @@ func TestCache_Keys_Values(t *testing.T) { gtest.C(t, func(t *gtest.T) { c := gcache.New() for i := 0; i < 10; i++ { - t.Assert(c.Set(i, i*10, 0), nil) + t.Assert(c.Set(ctx, i, i*10, 0), nil) } var ( - keys, _ = c.Keys() - values, _ = c.Values() + keys, _ = c.Keys(ctx) + values, _ = c.Values(ctx) ) t.Assert(len(keys), 10) t.Assert(len(values), 10) @@ -166,30 +165,30 @@ func TestCache_LRU(t *testing.T) { gtest.C(t, func(t *gtest.T) { cache := gcache.New(2) for i := 0; i < 10; i++ { - cache.Set(i, i, 0) + t.AssertNil(cache.Set(ctx, i, i, 0)) } - n, _ := cache.Size() + n, _ := cache.Size(ctx) t.Assert(n, 10) - v, _ := cache.Get(6) + v, _ := cache.Get(ctx, 6) t.Assert(v, 6) time.Sleep(4 * time.Second) - n, _ = cache.Size() + n, _ = cache.Size(ctx) t.Assert(n, 2) - v, _ = cache.Get(6) + v, _ = cache.Get(ctx, 6) t.Assert(v, 6) - v, _ = cache.Get(1) + v, _ = cache.Get(ctx, 1) t.Assert(v, nil) - t.Assert(cache.Close(), nil) + t.Assert(cache.Close(ctx), nil) }) } func TestCache_LRU_expire(t *testing.T) { gtest.C(t, func(t *gtest.T) { cache := gcache.New(2) - t.Assert(cache.Set(1, nil, 1000), nil) - n, _ := cache.Size() + t.Assert(cache.Set(ctx, 1, nil, 1000), nil) + n, _ := cache.Size(ctx) t.Assert(n, 1) - v, _ := cache.Get(1) + v, _ := cache.Get(ctx, 1) t.Assert(v, nil) }) @@ -198,22 +197,128 @@ func TestCache_LRU_expire(t *testing.T) { func TestCache_SetIfNotExist(t *testing.T) { gtest.C(t, func(t *gtest.T) { cache := gcache.New() - cache.SetIfNotExist(1, 11, 0) - v, _ := cache.Get(1) + ok, err := cache.SetIfNotExist(ctx, 1, 11, 0) + t.AssertNil(err) + t.Assert(ok, true) + + v, _ := cache.Get(ctx, 1) t.Assert(v, 11) - cache.SetIfNotExist(1, 22, 0) - v, _ = cache.Get(1) + + ok, err = cache.SetIfNotExist(ctx, 1, 22, 0) + t.AssertNil(err) + t.Assert(ok, false) + + v, _ = cache.Get(ctx, 1) t.Assert(v, 11) - cache.SetIfNotExist(2, 22, 0) - v, _ = cache.Get(2) + + ok, err = cache.SetIfNotExist(ctx, 2, 22, 0) + t.AssertNil(err) + t.Assert(ok, true) + + v, _ = cache.Get(ctx, 2) t.Assert(v, 22) - gcache.Removes(g.Slice{1, 2, 3}) - gcache.SetIfNotExist(1, 11, 0) - v, _ = gcache.Get(1) + gcache.Remove(ctx, g.Slice{1, 2, 3}...) + ok, err = gcache.SetIfNotExist(ctx, 1, 11, 0) + t.AssertNil(err) + t.Assert(ok, true) + + v, _ = gcache.Get(ctx, 1) t.Assert(v, 11) - gcache.SetIfNotExist(1, 22, 0) - v, _ = gcache.Get(1) + + ok, err = gcache.SetIfNotExist(ctx, 1, 22, 0) + t.AssertNil(err) + t.Assert(ok, false) + + v, _ = gcache.Get(ctx, 1) + t.Assert(v, 11) + }) +} + +func TestCache_SetIfNotExistFunc(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + cache := gcache.New() + exist, err := cache.SetIfNotExistFunc(ctx, 1, func() (interface{}, error) { + return 11, nil + }, 0) + t.AssertNil(err) + t.Assert(exist, true) + + v, _ := cache.Get(ctx, 1) + t.Assert(v, 11) + + exist, err = cache.SetIfNotExistFunc(ctx, 1, func() (interface{}, error) { + return 22, nil + }, 0) + t.AssertNil(err) + t.Assert(exist, false) + + v, _ = cache.Get(ctx, 1) + t.Assert(v, 11) + }) + gtest.C(t, func(t *gtest.T) { + gcache.Remove(ctx, g.Slice{1, 2, 3}...) + + ok, err := gcache.SetIfNotExistFunc(ctx, 1, func() (interface{}, error) { + return 11, nil + }, 0) + t.AssertNil(err) + t.Assert(ok, true) + + v, _ := gcache.Get(ctx, 1) + t.Assert(v, 11) + + ok, err = gcache.SetIfNotExistFunc(ctx, 1, func() (interface{}, error) { + return 22, nil + }, 0) + t.AssertNil(err) + t.Assert(ok, false) + + v, _ = gcache.Get(ctx, 1) + t.Assert(v, 11) + }) +} + +func TestCache_SetIfNotExistFuncLock(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + cache := gcache.New() + exist, err := cache.SetIfNotExistFuncLock(ctx, 1, func() (interface{}, error) { + return 11, nil + }, 0) + t.AssertNil(err) + t.Assert(exist, true) + + v, _ := cache.Get(ctx, 1) + t.Assert(v, 11) + + exist, err = cache.SetIfNotExistFuncLock(ctx, 1, func() (interface{}, error) { + return 22, nil + }, 0) + t.AssertNil(err) + t.Assert(exist, false) + + v, _ = cache.Get(ctx, 1) + t.Assert(v, 11) + }) + gtest.C(t, func(t *gtest.T) { + gcache.Remove(ctx, g.Slice{1, 2, 3}...) + + exist, err := gcache.SetIfNotExistFuncLock(ctx, 1, func() (interface{}, error) { + return 11, nil + }, 0) + t.AssertNil(err) + t.Assert(exist, true) + + v, _ := gcache.Get(ctx, 1) + t.Assert(v, 11) + + exist, err = gcache.SetIfNotExistFuncLock(ctx, 1, func() (interface{}, error) { + return 22, nil + }, 0) + t.AssertNil(err) + t.Assert(exist, false) + + v, _ = gcache.Get(ctx, 1) t.Assert(v, 11) }) } @@ -221,13 +326,13 @@ func TestCache_SetIfNotExist(t *testing.T) { func TestCache_Sets(t *testing.T) { gtest.C(t, func(t *gtest.T) { cache := gcache.New() - cache.Sets(g.MapAnyAny{1: 11, 2: 22}, 0) - v, _ := cache.Get(1) + t.AssertNil(cache.Sets(ctx, g.MapAnyAny{1: 11, 2: 22}, 0)) + v, _ := cache.Get(ctx, 1) t.Assert(v, 11) - gcache.Removes(g.Slice{1, 2, 3}) - gcache.Sets(g.MapAnyAny{1: 11, 2: 22}, 0) - v, _ = cache.Get(1) + gcache.Remove(ctx, g.Slice{1, 2, 3}...) + t.AssertNil(gcache.Sets(ctx, g.MapAnyAny{1: 11, 2: 22}, 0)) + v, _ = cache.Get(ctx, 1) t.Assert(v, 11) }) } @@ -235,21 +340,36 @@ func TestCache_Sets(t *testing.T) { func TestCache_GetOrSet(t *testing.T) { gtest.C(t, func(t *gtest.T) { cache := gcache.New() - cache.GetOrSet(1, 11, 0) - v, _ := cache.Get(1) - t.Assert(v, 11) - cache.GetOrSet(1, 111, 0) + value, err := cache.GetOrSet(ctx, 1, 11, 0) + t.AssertNil(err) + t.Assert(value, 11) - v, _ = cache.Get(1) + v, _ := cache.Get(ctx, 1) t.Assert(v, 11) - gcache.Removes(g.Slice{1, 2, 3}) - gcache.GetOrSet(1, 11, 0) + value, err = cache.GetOrSet(ctx, 1, 111, 0) + t.AssertNil(err) + t.Assert(value, 11) - v, _ = cache.Get(1) + v, _ = cache.Get(ctx, 1) + t.Assert(v, 11) + }) + + gtest.C(t, func(t *gtest.T) { + gcache.Remove(ctx, g.Slice{1, 2, 3}...) + value, err := gcache.GetOrSet(ctx, 1, 11, 0) + t.AssertNil(err) + t.Assert(value, 11) + + v, err := gcache.Get(ctx, 1) + t.AssertNil(err) t.Assert(v, 11) - gcache.GetOrSet(1, 111, 0) - v, _ = cache.Get(1) + value, err = gcache.GetOrSet(ctx, 1, 111, 0) + t.AssertNil(err) + t.Assert(value, 11) + + v, err = gcache.Get(ctx, 1) + t.AssertNil(err) t.Assert(v, 11) }) } @@ -257,30 +377,30 @@ func TestCache_GetOrSet(t *testing.T) { func TestCache_GetOrSetFunc(t *testing.T) { gtest.C(t, func(t *gtest.T) { cache := gcache.New() - cache.GetOrSetFunc(1, func() (interface{}, error) { + cache.GetOrSetFunc(ctx, 1, func() (interface{}, error) { return 11, nil }, 0) - v, _ := cache.Get(1) + v, _ := cache.Get(ctx, 1) t.Assert(v, 11) - cache.GetOrSetFunc(1, func() (interface{}, error) { + cache.GetOrSetFunc(ctx, 1, func() (interface{}, error) { return 111, nil }, 0) - v, _ = cache.Get(1) + v, _ = cache.Get(ctx, 1) t.Assert(v, 11) - gcache.Removes(g.Slice{1, 2, 3}) + gcache.Remove(ctx, g.Slice{1, 2, 3}...) - gcache.GetOrSetFunc(1, func() (interface{}, error) { + gcache.GetOrSetFunc(ctx, 1, func() (interface{}, error) { return 11, nil }, 0) - v, _ = cache.Get(1) + v, _ = cache.Get(ctx, 1) t.Assert(v, 11) - gcache.GetOrSetFunc(1, func() (interface{}, error) { + gcache.GetOrSetFunc(ctx, 1, func() (interface{}, error) { return 111, nil }, 0) - v, _ = cache.Get(1) + v, _ = cache.Get(ctx, 1) t.Assert(v, 11) }) } @@ -288,29 +408,29 @@ func TestCache_GetOrSetFunc(t *testing.T) { func TestCache_GetOrSetFuncLock(t *testing.T) { gtest.C(t, func(t *gtest.T) { cache := gcache.New() - cache.GetOrSetFuncLock(1, func() (interface{}, error) { + cache.GetOrSetFuncLock(ctx, 1, func() (interface{}, error) { return 11, nil }, 0) - v, _ := cache.Get(1) + v, _ := cache.Get(ctx, 1) t.Assert(v, 11) - cache.GetOrSetFuncLock(1, func() (interface{}, error) { + cache.GetOrSetFuncLock(ctx, 1, func() (interface{}, error) { return 111, nil }, 0) - v, _ = cache.Get(1) + v, _ = cache.Get(ctx, 1) t.Assert(v, 11) - gcache.Removes(g.Slice{1, 2, 3}) - gcache.GetOrSetFuncLock(1, func() (interface{}, error) { + gcache.Remove(ctx, g.Slice{1, 2, 3}...) + gcache.GetOrSetFuncLock(ctx, 1, func() (interface{}, error) { return 11, nil }, 0) - v, _ = cache.Get(1) + v, _ = cache.Get(ctx, 1) t.Assert(v, 11) - gcache.GetOrSetFuncLock(1, func() (interface{}, error) { + gcache.GetOrSetFuncLock(ctx, 1, func() (interface{}, error) { return 111, nil }, 0) - v, _ = cache.Get(1) + v, _ = cache.Get(ctx, 1) t.Assert(v, 11) }) } @@ -318,9 +438,9 @@ func TestCache_GetOrSetFuncLock(t *testing.T) { func TestCache_Clear(t *testing.T) { gtest.C(t, func(t *gtest.T) { cache := gcache.New() - cache.Sets(g.MapAnyAny{1: 11, 2: 22}, 0) - cache.Clear() - n, _ := cache.Size() + cache.Sets(ctx, g.MapAnyAny{1: 11, 2: 22}, 0) + cache.Clear(ctx) + n, _ := cache.Size(ctx) t.Assert(n, 0) }) } @@ -332,7 +452,7 @@ func TestCache_SetConcurrency(t *testing.T) { go func() { for { pool.Add(func() { - cache.SetIfNotExist(1, 11, 10) + cache.SetIfNotExist(ctx, 1, 11, 10) }) } }() @@ -344,7 +464,7 @@ func TestCache_SetConcurrency(t *testing.T) { go func() { for { pool.Add(func() { - cache.SetIfNotExist(1, nil, 10) + cache.SetIfNotExist(ctx, 1, nil, 10) }) } }() @@ -359,69 +479,92 @@ func TestCache_Basic(t *testing.T) { gtest.C(t, func(t *gtest.T) { { cache := gcache.New() - cache.Sets(g.MapAnyAny{1: 11, 2: 22}, 0) - b, _ := cache.Contains(1) + cache.Sets(ctx, g.MapAnyAny{1: 11, 2: 22}, 0) + b, _ := cache.Contains(ctx, 1) t.Assert(b, true) - v, _ := cache.Get(1) + v, _ := cache.Get(ctx, 1) t.Assert(v, 11) - data, _ := cache.Data() + data, _ := cache.Data(ctx) t.Assert(data[1], 11) t.Assert(data[2], 22) t.Assert(data[3], nil) - n, _ := cache.Size() + n, _ := cache.Size(ctx) t.Assert(n, 2) - keys, _ := cache.Keys() + keys, _ := cache.Keys(ctx) t.Assert(gset.NewFrom(g.Slice{1, 2}).Equal(gset.NewFrom(keys)), true) - keyStrs, _ := cache.KeyStrings() + keyStrs, _ := cache.KeyStrings(ctx) t.Assert(gset.NewFrom(g.Slice{"1", "2"}).Equal(gset.NewFrom(keyStrs)), true) - values, _ := cache.Values() + values, _ := cache.Values(ctx) t.Assert(gset.NewFrom(g.Slice{11, 22}).Equal(gset.NewFrom(values)), true) - removeData1, _ := cache.Remove(1) + removeData1, _ := cache.Remove(ctx, 1) t.Assert(removeData1, 11) - n, _ = cache.Size() + n, _ = cache.Size(ctx) t.Assert(n, 1) - cache.Removes(g.Slice{2}) - n, _ = cache.Size() + + cache.Remove(ctx, 2) + n, _ = cache.Size(ctx) t.Assert(n, 0) } - gcache.Remove(g.Slice{1, 2, 3}...) + gcache.Remove(ctx, g.Slice{1, 2, 3}...) { - gcache.Sets(g.MapAnyAny{1: 11, 2: 22}, 0) - b, _ := gcache.Contains(1) + gcache.Sets(ctx, g.MapAnyAny{1: 11, 2: 22}, 0) + b, _ := gcache.Contains(ctx, 1) t.Assert(b, true) - v, _ := gcache.Get(1) + v, _ := gcache.Get(ctx, 1) t.Assert(v, 11) - data, _ := gcache.Data() + data, _ := gcache.Data(ctx) t.Assert(data[1], 11) t.Assert(data[2], 22) t.Assert(data[3], nil) - n, _ := gcache.Size() + n, _ := gcache.Size(ctx) t.Assert(n, 2) - keys, _ := gcache.Keys() + keys, _ := gcache.Keys(ctx) t.Assert(gset.NewFrom(g.Slice{1, 2}).Equal(gset.NewFrom(keys)), true) - keyStrs, _ := gcache.KeyStrings() + keyStrs, _ := gcache.KeyStrings(ctx) t.Assert(gset.NewFrom(g.Slice{"1", "2"}).Equal(gset.NewFrom(keyStrs)), true) - values, _ := gcache.Values() + values, _ := gcache.Values(ctx) t.Assert(gset.NewFrom(g.Slice{11, 22}).Equal(gset.NewFrom(values)), true) - removeData1, _ := gcache.Remove(1) + removeData1, _ := gcache.Remove(ctx, 1) t.Assert(removeData1, 11) - n, _ = gcache.Size() + n, _ = gcache.Size(ctx) t.Assert(n, 1) - gcache.Removes(g.Slice{2}) - n, _ = gcache.Size() + gcache.Remove(ctx, 2) + n, _ = gcache.Size(ctx) t.Assert(n, 0) } }) } -func TestCache_Ctx(t *testing.T) { +func TestCache_Removes(t *testing.T) { gtest.C(t, func(t *gtest.T) { cache := gcache.New() - cache.Ctx(context.Background()).Sets(g.MapAnyAny{1: 11, 2: 22}, 0) - b, _ := cache.Contains(1) - t.Assert(b, true) - v, _ := cache.Get(1) - t.Assert(v, 11) + t.AssertNil(cache.Set(ctx, 1, 11, 0)) + t.AssertNil(cache.Set(ctx, 2, 22, 0)) + t.AssertNil(cache.Set(ctx, 3, 33, 0)) + t.AssertNil(cache.Removes(ctx, g.Slice{2, 3})) + + ok, err := cache.Contains(ctx, 1) + t.AssertNil(err) + t.Assert(ok, true) + + ok, err = cache.Contains(ctx, 2) + t.AssertNil(err) + t.Assert(ok, false) + }) + + gtest.C(t, func(t *gtest.T) { + t.AssertNil(gcache.Set(ctx, 1, 11, 0)) + t.AssertNil(gcache.Set(ctx, 2, 22, 0)) + t.AssertNil(gcache.Set(ctx, 3, 33, 0)) + t.AssertNil(gcache.Removes(ctx, g.Slice{2, 3})) + + ok, err := gcache.Contains(ctx, 1) + t.AssertNil(err) + t.Assert(ok, true) + + ok, err = gcache.Contains(ctx, 2) + t.AssertNil(err) + t.Assert(ok, false) }) } diff --git a/os/gcfg/gcfg_config.go b/os/gcfg/gcfg_config.go index f7db8f603..14fc71f4a 100644 --- a/os/gcfg/gcfg_config.go +++ b/os/gcfg/gcfg_config.go @@ -151,7 +151,11 @@ func (c *Config) SetPath(path string) error { } // Should be a directory. if !isDir { - err := fmt.Errorf(`[gcfg] SetPath failed: path "%s" should be directory type`, path) + err := gerror.NewCodef( + gcode.CodeInvalidParameter, + `[gcfg] SetPath failed: path "%s" should be directory type`, + path, + ) if errorPrint() { glog.Error(err) } @@ -173,13 +177,13 @@ func (c *Config) SetPath(path string) error { // It is off in default. // // Note that, turning on this feature is quite expensive, and it is not recommended -// to allow separators in the key names. It is best to avoid this on the application side. +// allowing separators in the key names. It is best to avoid this on the application side. func (c *Config) SetViolenceCheck(check bool) { c.violenceCheck = check c.Clear() } -// AddPath adds a absolute or relative path to the search paths. +// AddPath adds an absolute or relative path to the search paths. func (c *Config) AddPath(path string) error { var ( isDir = false diff --git a/os/gcron/gcron_schedule.go b/os/gcron/gcron_schedule.go index 8bfb68a35..8291394c4 100644 --- a/os/gcron/gcron_schedule.go +++ b/os/gcron/gcron_schedule.go @@ -219,11 +219,11 @@ func parsePatternItemValue(value string, itemType int) (int, error) { // it converts the value to number according to predefined map. switch itemType { case patternItemTypeWeek: - if number, ok := monthMap[strings.ToLower(value)]; ok { + if number, ok := weekMap[strings.ToLower(value)]; ok { return number, nil } case patternItemTypeMonth: - if number, ok := weekMap[strings.ToLower(value)]; ok { + if number, ok := monthMap[strings.ToLower(value)]; ok { return number, nil } } diff --git a/os/gfile/gfile_cache.go b/os/gfile/gfile_cache.go index c4c28d490..1f08ba021 100644 --- a/os/gfile/gfile_cache.go +++ b/os/gfile/gfile_cache.go @@ -7,6 +7,8 @@ package gfile import ( + "context" + "github.com/gogf/gf/internal/intlog" "github.com/gogf/gf/os/gcache" "github.com/gogf/gf/os/gcmd" "github.com/gogf/gf/os/gfsnotify" @@ -37,30 +39,32 @@ func GetContentsWithCache(path string, duration ...time.Duration) string { // If there's no content in the cache, it will read it from disk file specified by <path>. // The parameter <expire> specifies the caching time for this file content in seconds. func GetBytesWithCache(path string, duration ...time.Duration) []byte { - key := cacheKey(path) - expire := cacheExpire + var ( + ctx = context.Background() + expire = cacheExpire + cacheKey = commandEnvKeyForCache + path + ) + if len(duration) > 0 { expire = duration[0] } - r, _ := internalCache.GetOrSetFuncLock(key, func() (interface{}, error) { + r, _ := internalCache.GetOrSetFuncLock(ctx, cacheKey, func() (interface{}, error) { b := GetBytes(path) if b != nil { // Adding this <path> to gfsnotify, // it will clear its cache if there's any changes of the file. _, _ = gfsnotify.Add(path, func(event *gfsnotify.Event) { - internalCache.Remove(key) + _, err := internalCache.Remove(ctx, cacheKey) + if err != nil { + intlog.Error(ctx, err) + } gfsnotify.Exit() }) } return b, nil }, expire) if r != nil { - return r.([]byte) + return r.Bytes() } return nil } - -// cacheKey produces the cache key for gcache. -func cacheKey(path string) string { - return commandEnvKeyForCache + path -} diff --git a/os/gfile/gfile_contents.go b/os/gfile/gfile_contents.go index 048e15d76..29057ddaa 100644 --- a/os/gfile/gfile_contents.go +++ b/os/gfile/gfile_contents.go @@ -11,8 +11,6 @@ import ( "io" "io/ioutil" "os" - - "github.com/gogf/gf/util/gconv" ) var ( @@ -23,7 +21,7 @@ var ( // GetContents returns the file content of <path> as string. // It returns en empty string if it fails reading. func GetContents(path string) string { - return gconv.UnsafeBytesToStr(GetBytes(path)) + return string(GetBytes(path)) } // GetBytes returns the file content of <path> as []byte. diff --git a/os/gfile/gfile_copy.go b/os/gfile/gfile_copy.go index 26ace7bcf..554c6cd9f 100644 --- a/os/gfile/gfile_copy.go +++ b/os/gfile/gfile_copy.go @@ -7,7 +7,6 @@ package gfile import ( - "fmt" "github.com/gogf/gf/errors/gcode" "github.com/gogf/gf/errors/gerror" "io" @@ -104,7 +103,7 @@ func CopyDir(src string, dst string) (err error) { return err } if !si.IsDir() { - return fmt.Errorf("source is not a directory") + return gerror.NewCode(gcode.CodeInvalidParameter, "source is not a directory") } if !Exists(dst) { err = os.MkdirAll(dst, DefaultPermCopy) diff --git a/os/gfsnotify/gfsnotify_watcher_loop.go b/os/gfsnotify/gfsnotify_watcher_loop.go index 3c47a7f0a..a26578e7f 100644 --- a/os/gfsnotify/gfsnotify_watcher_loop.go +++ b/os/gfsnotify/gfsnotify_watcher_loop.go @@ -24,7 +24,7 @@ func (w *Watcher) watchLoop() { // Event listening. case ev := <-w.watcher.Events: // Filter the repeated event in custom duration. - w.cache.SetIfNotExist(ev.String(), func() (interface{}, error) { + w.cache.SetIfNotExist(context.Background(), ev.String(), func() (interface{}, error) { w.events.Push(&Event{ event: ev, Path: ev.Name, diff --git a/os/gproc/gproc.go b/os/gproc/gproc.go index 33fe32f00..4fc36b25f 100644 --- a/os/gproc/gproc.go +++ b/os/gproc/gproc.go @@ -80,9 +80,9 @@ func Uptime() time.Duration { return time.Now().Sub(processStartTime) } -// Shell executes command <cmd> synchronizingly with given input pipe <in> and output pipe <out>. -// The command <cmd> reads the input parameters from input pipe <in>, and writes its output automatically -// to output pipe <out>. +// Shell executes command <cmd> synchronously with given input pipe <in> and output pipe `out`. +// The command <cmd> reads the input parameters from input pipe `in`, and writes its output automatically +// to output pipe `out`. func Shell(cmd string, out io.Writer, in io.Reader) error { p := NewProcess(getShell(), append([]string{getShellOption()}, parseCommand(cmd)...)) p.Stdin = in @@ -90,13 +90,13 @@ func Shell(cmd string, out io.Writer, in io.Reader) error { return p.Run() } -// ShellRun executes given command <cmd> synchronizingly and outputs the command result to the stdout. +// ShellRun executes given command `cmd` synchronously and outputs the command result to the stdout. func ShellRun(cmd string) error { p := NewProcess(getShell(), append([]string{getShellOption()}, parseCommand(cmd)...)) return p.Run() } -// ShellExec executes given command <cmd> synchronizingly and returns the command result. +// ShellExec executes given command `cmd` synchronously and returns the command result. func ShellExec(cmd string, environment ...[]string) (string, error) { buf := bytes.NewBuffer(nil) p := NewProcess(getShell(), append([]string{getShellOption()}, parseCommand(cmd)...), environment...) @@ -106,10 +106,10 @@ func ShellExec(cmd string, environment ...[]string) (string, error) { return buf.String(), err } -// parseCommand parses command <cmd> into slice arguments. +// parseCommand parses command `cmd` into slice arguments. // -// Note that it just parses the <cmd> for "cmd.exe" binary in windows, but it is not necessary -// parsing the <cmd> for other systems using "bash"/"sh" binary. +// Note that it just parses the `cmd` for "cmd.exe" binary in windows, but it is not necessary +// parsing the `cmd` for other systems using "bash"/"sh" binary. func parseCommand(cmd string) (args []string) { if runtime.GOOS != "windows" { return []string{cmd} @@ -170,7 +170,7 @@ func getShell() string { } } -// getShellOption returns the shell option depending on current working operation system. +// getShellOption returns the shell option depending on current working operating system. // It returns "/c" for windows, and "-c" for others. func getShellOption() string { switch runtime.GOOS { @@ -181,7 +181,7 @@ func getShellOption() string { } } -// SearchBinary searches the binary <file> in current working folder and PATH environment. +// SearchBinary searches the binary `file` in current working folder and PATH environment. func SearchBinary(file string) string { // Check if it's absolute path of exists at current working directory. if gfile.Exists(file) { @@ -190,7 +190,7 @@ func SearchBinary(file string) string { return SearchBinaryPath(file) } -// SearchBinaryPath searches the binary <file> in PATH environment. +// SearchBinaryPath searches the binary `file` in PATH environment. func SearchBinaryPath(file string) string { array := ([]string)(nil) switch runtime.GOOS { diff --git a/os/gproc/gproc_process.go b/os/gproc/gproc_process.go index a560c0eb8..51249e5d6 100644 --- a/os/gproc/gproc_process.go +++ b/os/gproc/gproc_process.go @@ -29,9 +29,7 @@ type Process struct { func NewProcess(path string, args []string, environment ...[]string) *Process { env := os.Environ() if len(environment) > 0 { - for k, v := range environment[0] { - env[k] = v - } + env = append(env, environment[0]...) } process := &Process{ Manager: nil, diff --git a/os/gres/gres_func.go b/os/gres/gres_func.go index 4995fbc29..cf45d7a8c 100644 --- a/os/gres/gres_func.go +++ b/os/gres/gres_func.go @@ -13,10 +13,8 @@ import ( "fmt" "github.com/gogf/gf/encoding/gbase64" "github.com/gogf/gf/encoding/gcompress" - "github.com/gogf/gf/text/gstr" - "github.com/gogf/gf/util/gconv" - "github.com/gogf/gf/os/gfile" + "github.com/gogf/gf/text/gstr" ) const ( @@ -116,7 +114,7 @@ func UnpackContent(content string) ([]*File, error) { return nil, err } } else { - data, err = gcompress.UnGzip(gconv.UnsafeStrToBytes(content)) + data, err = gcompress.UnGzip([]byte(content)) if err != nil { return nil, err } @@ -166,7 +164,7 @@ func isHexStr(s string) bool { // hexStrToBytes converts hex string content to []byte. func hexStrToBytes(s string) []byte { - src := gconv.UnsafeStrToBytes(s) + src := []byte(s) dst := make([]byte, hex.DecodedLen(len(src))) hex.Decode(dst, src) return dst diff --git a/os/grpool/grpool.go b/os/grpool/grpool.go index f9c19c356..5eb0c3bab 100644 --- a/os/grpool/grpool.go +++ b/os/grpool/grpool.go @@ -99,10 +99,10 @@ func (p *Pool) AddWithRecover(userFunc func(), recoverFunc ...func(err error)) e defer func() { if exception := recover(); exception != nil { if len(recoverFunc) > 0 && recoverFunc[0] != nil { - if err, ok := exception.(error); ok { - recoverFunc[0](err) + if v, ok := exception.(error); ok && gerror.HasStack(v) { + recoverFunc[0](v) } else { - recoverFunc[0](gerror.NewCodef(gcode.CodeInternalError, `%v`, exception)) + recoverFunc[0](gerror.NewCodef(gcode.CodeInternalError, `%+v`, exception)) } } } diff --git a/os/gsession/gsession_manager.go b/os/gsession/gsession_manager.go index 81b308d52..ed9f7dfcc 100644 --- a/os/gsession/gsession_manager.go +++ b/os/gsession/gsession_manager.go @@ -9,6 +9,7 @@ package gsession import ( "context" "github.com/gogf/gf/container/gmap" + "github.com/gogf/gf/internal/intlog" "time" "github.com/gogf/gf/os/gcache" @@ -20,7 +21,7 @@ type Manager struct { storage Storage // Storage interface for session storage. // sessionData is the memory data cache for session TTL, - // which is available only if the Storage does not stores any session data in synchronizing. + // which is available only if the Storage does not store any session data in synchronizing. // Please refer to the implements of StorageFile, StorageMemory and StorageRedis. sessionData *gcache.Cache } @@ -71,5 +72,9 @@ func (m *Manager) TTL() time.Duration { // UpdateSessionTTL updates the ttl for given session. func (m *Manager) UpdateSessionTTL(sessionId string, data *gmap.StrAnyMap) { - m.sessionData.Set(sessionId, data, m.ttl) + ctx := context.Background() + err := m.sessionData.Set(ctx, sessionId, data, m.ttl) + if err != nil { + intlog.Error(ctx, err) + } } diff --git a/os/gsession/gsession_session.go b/os/gsession/gsession_session.go index edc70ff9d..dc79606f4 100644 --- a/os/gsession/gsession_session.go +++ b/os/gsession/gsession_session.go @@ -15,7 +15,6 @@ import ( "github.com/gogf/gf/container/gmap" "github.com/gogf/gf/container/gvar" - "github.com/gogf/gf/os/gtime" ) // Session struct for storing single session data, which is bound to a single request. @@ -23,7 +22,7 @@ import ( // for functionality implements. type Session struct { id string // Session id. - ctx context.Context // Context for current session, note that: one session one context. + ctx context.Context // Context for current session. Please note that, session live along with context. data *gmap.StrAnyMap // Session data. dirty bool // Used to mark session is modified. start bool // Used to mark session is started. @@ -43,8 +42,8 @@ func (s *Session) init() { var err error if s.id != "" { // Retrieve memory session data from manager. - if r, _ := s.manager.sessionData.Get(s.id); r != nil { - s.data = r.(*gmap.StrAnyMap) + if r, _ := s.manager.sessionData.Get(s.ctx, s.id); r != nil { + s.data = r.Val().(*gmap.StrAnyMap) intlog.Print(s.ctx, "session init data:", s.data) } // Retrieve stored session data from storage. @@ -251,7 +250,7 @@ func (s *Session) IsDirty() bool { // Get retrieves session value with given key. // It returns `def` if the key does not exist in the session if `def` is given, // or else it returns nil. -func (s *Session) Get(key string, def ...interface{}) interface{} { +func (s *Session) Get(key string, def ...interface{}) *gvar.Var { if s.id == "" { return nil } @@ -261,129 +260,13 @@ func (s *Session) Get(key string, def ...interface{}) interface{} { intlog.Error(s.ctx, err) } if v != nil { - return v + return gvar.New(v) } if v := s.data.Get(key); v != nil { - return v + return gvar.New(v) } if len(def) > 0 { - return def[0] + return gvar.New(def[0]) } return nil } - -func (s *Session) GetVar(key string, def ...interface{}) *gvar.Var { - return gvar.New(s.Get(key, def...), true) -} - -func (s *Session) GetString(key string, def ...interface{}) string { - return s.GetVar(key, def...).String() -} - -func (s *Session) GetBool(key string, def ...interface{}) bool { - return s.GetVar(key, def...).Bool() -} - -func (s *Session) GetInt(key string, def ...interface{}) int { - return s.GetVar(key, def...).Int() -} - -func (s *Session) GetInt8(key string, def ...interface{}) int8 { - return s.GetVar(key, def...).Int8() -} - -func (s *Session) GetInt16(key string, def ...interface{}) int16 { - return s.GetVar(key, def...).Int16() -} - -func (s *Session) GetInt32(key string, def ...interface{}) int32 { - return s.GetVar(key, def...).Int32() -} - -func (s *Session) GetInt64(key string, def ...interface{}) int64 { - return s.GetVar(key, def...).Int64() -} - -func (s *Session) GetUint(key string, def ...interface{}) uint { - return s.GetVar(key, def...).Uint() -} - -func (s *Session) GetUint8(key string, def ...interface{}) uint8 { - return s.GetVar(key, def...).Uint8() -} - -func (s *Session) GetUint16(key string, def ...interface{}) uint16 { - return s.GetVar(key, def...).Uint16() -} - -func (s *Session) GetUint32(key string, def ...interface{}) uint32 { - return s.GetVar(key, def...).Uint32() -} - -func (s *Session) GetUint64(key string, def ...interface{}) uint64 { - return s.GetVar(key, def...).Uint64() -} - -func (s *Session) GetFloat32(key string, def ...interface{}) float32 { - return s.GetVar(key, def...).Float32() -} - -func (s *Session) GetFloat64(key string, def ...interface{}) float64 { - return s.GetVar(key, def...).Float64() -} - -func (s *Session) GetBytes(key string, def ...interface{}) []byte { - return s.GetVar(key, def...).Bytes() -} - -func (s *Session) GetInts(key string, def ...interface{}) []int { - return s.GetVar(key, def...).Ints() -} - -func (s *Session) GetFloats(key string, def ...interface{}) []float64 { - return s.GetVar(key, def...).Floats() -} - -func (s *Session) GetStrings(key string, def ...interface{}) []string { - return s.GetVar(key, def...).Strings() -} - -func (s *Session) GetInterfaces(key string, def ...interface{}) []interface{} { - return s.GetVar(key, def...).Interfaces() -} - -func (s *Session) GetTime(key string, format ...string) time.Time { - return s.GetVar(key).Time(format...) -} - -func (s *Session) GetGTime(key string, format ...string) *gtime.Time { - return s.GetVar(key).GTime(format...) -} - -func (s *Session) GetDuration(key string, def ...interface{}) time.Duration { - return s.GetVar(key, def...).Duration() -} - -func (s *Session) GetMap(key string, tags ...string) map[string]interface{} { - return s.GetVar(key).Map(tags...) -} - -func (s *Session) GetMapDeep(key string, tags ...string) map[string]interface{} { - return s.GetVar(key).MapDeep(tags...) -} - -func (s *Session) GetMaps(key string, tags ...string) []map[string]interface{} { - return s.GetVar(key).Maps(tags...) -} - -func (s *Session) GetMapsDeep(key string, tags ...string) []map[string]interface{} { - return s.GetVar(key).MapsDeep(tags...) -} - -func (s *Session) GetStruct(key string, pointer interface{}, mapping ...map[string]string) error { - return s.GetVar(key).Struct(pointer, mapping...) -} - -func (s *Session) GetStructs(key string, pointer interface{}, mapping ...map[string]string) error { - return s.GetVar(key).Structs(pointer, mapping...) -} diff --git a/os/gspath/gspath_cache.go b/os/gspath/gspath_cache.go index 324be56c1..3e0f47b8b 100644 --- a/os/gspath/gspath_cache.go +++ b/os/gspath/gspath_cache.go @@ -75,8 +75,6 @@ func (sp *SPath) addToCache(filePath, rootPath string) { for _, path := range files { sp.cache.SetIfNotExist(sp.nameFromPath(path, rootPath), sp.makeCacheValue(path, gfile.IsDir(path))) } - } else { - //fmt.Errorf(err.Error()) } } } diff --git a/os/gtime/gtime_time.go b/os/gtime/gtime_time.go index 33e0de5e4..54f55ace9 100644 --- a/os/gtime/gtime_time.go +++ b/os/gtime/gtime_time.go @@ -19,8 +19,8 @@ type Time struct { wrapper } -// apiUnixNano is an interface definition commonly for custom time.Time wrapper. -type apiUnixNano interface { +// iUnixNano is an interface definition commonly for custom time.Time wrapper. +type iUnixNano interface { UnixNano() int64 } @@ -69,7 +69,7 @@ func New(param ...interface{}) *Time { return NewFromTimeStamp(r) default: - if v, ok := r.(apiUnixNano); ok { + if v, ok := r.(iUnixNano); ok { return NewFromTimeStamp(v.UnixNano()) } } diff --git a/os/gview/gview_buildin.go b/os/gview/gview_buildin.go index da22f78fa..281e15515 100644 --- a/os/gview/gview_buildin.go +++ b/os/gview/gview_buildin.go @@ -222,7 +222,7 @@ func (view *View) buildInFuncNl2Br(str interface{}) string { // which encodes and returns `value` as JSON string. func (view *View) buildInFuncJson(value interface{}) (string, error) { b, err := json.Marshal(value) - return gconv.UnsafeBytesToStr(b), err + return string(b), err } // buildInFuncPlus implements build-in template function: plus , diff --git a/os/gview/gview_parse.go b/os/gview/gview_parse.go index c8a4811ee..0fd3a095a 100644 --- a/os/gview/gview_parse.go +++ b/os/gview/gview_parse.go @@ -10,26 +10,23 @@ import ( "bytes" "context" "fmt" + "github.com/gogf/gf/container/gmap" "github.com/gogf/gf/encoding/ghash" "github.com/gogf/gf/errors/gcode" "github.com/gogf/gf/errors/gerror" "github.com/gogf/gf/internal/intlog" + "github.com/gogf/gf/os/gfile" "github.com/gogf/gf/os/gfsnotify" + "github.com/gogf/gf/os/glog" "github.com/gogf/gf/os/gmlock" + "github.com/gogf/gf/os/gres" + "github.com/gogf/gf/os/gspath" "github.com/gogf/gf/text/gstr" - "github.com/gogf/gf/util/gconv" "github.com/gogf/gf/util/gutil" htmltpl "html/template" "strconv" "strings" texttpl "text/template" - - "github.com/gogf/gf/os/gres" - - "github.com/gogf/gf/container/gmap" - "github.com/gogf/gf/os/gfile" - "github.com/gogf/gf/os/glog" - "github.com/gogf/gf/os/gspath" ) const ( @@ -71,7 +68,7 @@ func (view *View) Parse(ctx context.Context, file string, params ...Params) (res return nil } if resource != nil { - content = gconv.UnsafeBytesToStr(resource.Content()) + content = string(resource.Content()) } else { content = gfile.GetContentsWithCache(path) } diff --git a/test/gtest/gtest_util.go b/test/gtest/gtest_util.go index a1644afa2..2b525b647 100644 --- a/test/gtest/gtest_util.go +++ b/test/gtest/gtest_util.go @@ -9,7 +9,9 @@ package gtest import ( "fmt" "github.com/gogf/gf/internal/empty" + "io/ioutil" "os" + "path/filepath" "reflect" "testing" @@ -22,7 +24,7 @@ const ( pathFilterKey = "/test/gtest/gtest" ) -// C creates an unit testing case. +// C creates a unit testing case. // The parameter `t` is the pointer to testing.T of stdlib (*testing.T). // The parameter `f` is the closure function for unit testing case. func C(t *testing.T, f func(t *T)) { @@ -35,7 +37,7 @@ func C(t *testing.T, f func(t *T)) { f(&T{t}) } -// Case creates an unit testing case. +// Case creates a unit testing case. // The parameter `t` is the pointer to testing.T of stdlib (*testing.T). // The parameter `f` is the closure function for unit testing case. // Deprecated. @@ -357,3 +359,28 @@ func AssertNil(value interface{}) { } AssertNE(value, nil) } + +// TestDataPath retrieves and returns the testdata path of current package, +// which is used for unit testing cases only. +// The optional parameter `names` specifies the sub-folders/sub-files, +// which will be joined with current system separator and returned with the path. +func TestDataPath(names ...string) string { + _, path, _ := gdebug.CallerWithFilter(pathFilterKey) + path = filepath.Dir(path) + string(filepath.Separator) + "testdata" + for _, name := range names { + path += string(filepath.Separator) + name + } + return path +} + +// TestDataContent retrieves and returns the file content for specified testdata path of current package +func TestDataContent(names ...string) string { + path := TestDataPath(names...) + if path != "" { + data, err := ioutil.ReadFile(path) + if err == nil { + return string(data) + } + } + return "" +} diff --git a/text/gstr/gstr_parse.go b/text/gstr/gstr_parse.go index a41267403..84f36177d 100644 --- a/text/gstr/gstr_parse.go +++ b/text/gstr/gstr_parse.go @@ -7,7 +7,8 @@ package gstr import ( - "fmt" + "github.com/gogf/gf/errors/gcode" + "github.com/gogf/gf/errors/gerror" "net/url" "strings" ) @@ -116,7 +117,11 @@ func build(result map[string]interface{}, keys []string, value interface{}) erro } children, ok := val.([]interface{}) if !ok { - return fmt.Errorf("expected type '[]interface{}' for key '%s', but got '%T'", key, val) + return gerror.NewCodef( + gcode.CodeInvalidParameter, + "expected type '[]interface{}' for key '%s', but got '%T'", + key, val, + ) } result[key] = append(children, value) return nil @@ -131,7 +136,11 @@ func build(result map[string]interface{}, keys []string, value interface{}) erro } children, ok := val.([]interface{}) if !ok { - return fmt.Errorf("expected type '[]interface{}' for key '%s', but got '%T'", key, val) + return gerror.NewCodef( + gcode.CodeInvalidParameter, + "expected type '[]interface{}' for key '%s', but got '%T'", + key, val, + ) } if l := len(children); l > 0 { if child, ok := children[l-1].(map[string]interface{}); ok { @@ -155,7 +164,11 @@ func build(result map[string]interface{}, keys []string, value interface{}) erro } children, ok := val.(map[string]interface{}) if !ok { - return fmt.Errorf("expected type 'map[string]interface{}' for key '%s', but got '%T'", key, val) + return gerror.NewCodef( + gcode.CodeInvalidParameter, + "expected type 'map[string]interface{}' for key '%s', but got '%T'", + key, val, + ) } if err := build(children, keys[1:], value); err != nil { return err diff --git a/util/gconv/gconv.go b/util/gconv/gconv.go index 0a72171f8..934849431 100644 --- a/util/gconv/gconv.go +++ b/util/gconv/gconv.go @@ -22,14 +22,6 @@ import ( "github.com/gogf/gf/encoding/gbinary" ) -type ( - // errorStack is the interface for Stack feature. - errorStack interface { - Error() string - Stack() string - } -) - var ( // Empty strings. emptyStringMap = map[string]struct{}{ @@ -53,235 +45,235 @@ type doConvertInput struct { Extra []interface{} // Extra values for implementing the converting. } -// doConvert does commonly used types converting. -func doConvert(input doConvertInput) interface{} { - switch input.ToTypeName { +// doConvert does commonly use types converting. +func doConvert(in doConvertInput) interface{} { + switch in.ToTypeName { case "int": - return Int(input.FromValue) + return Int(in.FromValue) case "*int": - if _, ok := input.FromValue.(*int); ok { - return input.FromValue + if _, ok := in.FromValue.(*int); ok { + return in.FromValue } - v := Int(input.FromValue) + v := Int(in.FromValue) return &v case "int8": - return Int8(input.FromValue) + return Int8(in.FromValue) case "*int8": - if _, ok := input.FromValue.(*int8); ok { - return input.FromValue + if _, ok := in.FromValue.(*int8); ok { + return in.FromValue } - v := Int8(input.FromValue) + v := Int8(in.FromValue) return &v case "int16": - return Int16(input.FromValue) + return Int16(in.FromValue) case "*int16": - if _, ok := input.FromValue.(*int16); ok { - return input.FromValue + if _, ok := in.FromValue.(*int16); ok { + return in.FromValue } - v := Int16(input.FromValue) + v := Int16(in.FromValue) return &v case "int32": - return Int32(input.FromValue) + return Int32(in.FromValue) case "*int32": - if _, ok := input.FromValue.(*int32); ok { - return input.FromValue + if _, ok := in.FromValue.(*int32); ok { + return in.FromValue } - v := Int32(input.FromValue) + v := Int32(in.FromValue) return &v case "int64": - return Int64(input.FromValue) + return Int64(in.FromValue) case "*int64": - if _, ok := input.FromValue.(*int64); ok { - return input.FromValue + if _, ok := in.FromValue.(*int64); ok { + return in.FromValue } - v := Int64(input.FromValue) + v := Int64(in.FromValue) return &v case "uint": - return Uint(input.FromValue) + return Uint(in.FromValue) case "*uint": - if _, ok := input.FromValue.(*uint); ok { - return input.FromValue + if _, ok := in.FromValue.(*uint); ok { + return in.FromValue } - v := Uint(input.FromValue) + v := Uint(in.FromValue) return &v case "uint8": - return Uint8(input.FromValue) + return Uint8(in.FromValue) case "*uint8": - if _, ok := input.FromValue.(*uint8); ok { - return input.FromValue + if _, ok := in.FromValue.(*uint8); ok { + return in.FromValue } - v := Uint8(input.FromValue) + v := Uint8(in.FromValue) return &v case "uint16": - return Uint16(input.FromValue) + return Uint16(in.FromValue) case "*uint16": - if _, ok := input.FromValue.(*uint16); ok { - return input.FromValue + if _, ok := in.FromValue.(*uint16); ok { + return in.FromValue } - v := Uint16(input.FromValue) + v := Uint16(in.FromValue) return &v case "uint32": - return Uint32(input.FromValue) + return Uint32(in.FromValue) case "*uint32": - if _, ok := input.FromValue.(*uint32); ok { - return input.FromValue + if _, ok := in.FromValue.(*uint32); ok { + return in.FromValue } - v := Uint32(input.FromValue) + v := Uint32(in.FromValue) return &v case "uint64": - return Uint64(input.FromValue) + return Uint64(in.FromValue) case "*uint64": - if _, ok := input.FromValue.(*uint64); ok { - return input.FromValue + if _, ok := in.FromValue.(*uint64); ok { + return in.FromValue } - v := Uint64(input.FromValue) + v := Uint64(in.FromValue) return &v case "float32": - return Float32(input.FromValue) + return Float32(in.FromValue) case "*float32": - if _, ok := input.FromValue.(*float32); ok { - return input.FromValue + if _, ok := in.FromValue.(*float32); ok { + return in.FromValue } - v := Float32(input.FromValue) + v := Float32(in.FromValue) return &v case "float64": - return Float64(input.FromValue) + return Float64(in.FromValue) case "*float64": - if _, ok := input.FromValue.(*float64); ok { - return input.FromValue + if _, ok := in.FromValue.(*float64); ok { + return in.FromValue } - v := Float64(input.FromValue) + v := Float64(in.FromValue) return &v case "bool": - return Bool(input.FromValue) + return Bool(in.FromValue) case "*bool": - if _, ok := input.FromValue.(*bool); ok { - return input.FromValue + if _, ok := in.FromValue.(*bool); ok { + return in.FromValue } - v := Bool(input.FromValue) + v := Bool(in.FromValue) return &v case "string": - return String(input.FromValue) + return String(in.FromValue) case "*string": - if _, ok := input.FromValue.(*string); ok { - return input.FromValue + if _, ok := in.FromValue.(*string); ok { + return in.FromValue } - v := String(input.FromValue) + v := String(in.FromValue) return &v case "[]byte": - return Bytes(input.FromValue) + return Bytes(in.FromValue) case "[]int": - return Ints(input.FromValue) + return Ints(in.FromValue) case "[]int32": - return Int32s(input.FromValue) + return Int32s(in.FromValue) case "[]int64": - return Int64s(input.FromValue) + return Int64s(in.FromValue) case "[]uint": - return Uints(input.FromValue) + return Uints(in.FromValue) case "[]uint8": - return Bytes(input.FromValue) + return Bytes(in.FromValue) case "[]uint32": - return Uint32s(input.FromValue) + return Uint32s(in.FromValue) case "[]uint64": - return Uint64s(input.FromValue) + return Uint64s(in.FromValue) case "[]float32": - return Float32s(input.FromValue) + return Float32s(in.FromValue) case "[]float64": - return Float64s(input.FromValue) + return Float64s(in.FromValue) case "[]string": - return Strings(input.FromValue) + return Strings(in.FromValue) case "Time", "time.Time": - if len(input.Extra) > 0 { - return Time(input.FromValue, String(input.Extra[0])) + if len(in.Extra) > 0 { + return Time(in.FromValue, String(in.Extra[0])) } - return Time(input.FromValue) + return Time(in.FromValue) case "*time.Time": var v interface{} - if len(input.Extra) > 0 { - v = Time(input.FromValue, String(input.Extra[0])) + if len(in.Extra) > 0 { + v = Time(in.FromValue, String(in.Extra[0])) } else { - if _, ok := input.FromValue.(*time.Time); ok { - return input.FromValue + if _, ok := in.FromValue.(*time.Time); ok { + return in.FromValue } - v = Time(input.FromValue) + v = Time(in.FromValue) } return &v case "GTime", "gtime.Time": - if len(input.Extra) > 0 { - if v := GTime(input.FromValue, String(input.Extra[0])); v != nil { + if len(in.Extra) > 0 { + if v := GTime(in.FromValue, String(in.Extra[0])); v != nil { return *v } else { return *gtime.New() } } - if v := GTime(input.FromValue); v != nil { + if v := GTime(in.FromValue); v != nil { return *v } else { return *gtime.New() } case "*gtime.Time": - if len(input.Extra) > 0 { - if v := GTime(input.FromValue, String(input.Extra[0])); v != nil { + if len(in.Extra) > 0 { + if v := GTime(in.FromValue, String(in.Extra[0])); v != nil { return v } else { return gtime.New() } } - if v := GTime(input.FromValue); v != nil { + if v := GTime(in.FromValue); v != nil { return v } else { return gtime.New() } case "Duration", "time.Duration": - return Duration(input.FromValue) + return Duration(in.FromValue) case "*time.Duration": - if _, ok := input.FromValue.(*time.Duration); ok { - return input.FromValue + if _, ok := in.FromValue.(*time.Duration); ok { + return in.FromValue } - v := Duration(input.FromValue) + v := Duration(in.FromValue) return &v case "map[string]string": - return MapStrStr(input.FromValue) + return MapStrStr(in.FromValue) case "map[string]interface{}": - return Map(input.FromValue) + return Map(in.FromValue) case "[]map[string]interface{}": - return Maps(input.FromValue) + return Maps(in.FromValue) default: - if input.ReferValue != nil { + if in.ReferValue != nil { var ( referReflectValue reflect.Value ) - if v, ok := input.ReferValue.(reflect.Value); ok { + if v, ok := in.ReferValue.(reflect.Value); ok { referReflectValue = v } else { - referReflectValue = reflect.ValueOf(input.ReferValue) + referReflectValue = reflect.ValueOf(in.ReferValue) } - input.ToTypeName = referReflectValue.Kind().String() - input.ReferValue = nil - return reflect.ValueOf(doConvert(input)).Convert(referReflectValue.Type()).Interface() + in.ToTypeName = referReflectValue.Kind().String() + in.ReferValue = nil + return reflect.ValueOf(doConvert(in)).Convert(referReflectValue.Type()).Interface() } - return input.FromValue + return in.FromValue } } @@ -316,7 +308,7 @@ func Bytes(any interface{}) []byte { case []byte: return value default: - if f, ok := value.(apiBytes); ok { + if f, ok := value.(iBytes); ok { return f.Bytes() } var ( @@ -427,12 +419,12 @@ func String(any interface{}) string { if value == nil { return "" } - if f, ok := value.(apiString); ok { + if f, ok := value.(iString); ok { // If the variable implements the String() interface, // then use that interface to perform the conversion return f.String() } - if f, ok := value.(apiError); ok { + if f, ok := value.(iError); ok { // If the variable implements the Error() interface, // then use that interface to perform the conversion return f.Error() @@ -488,7 +480,7 @@ func Bool(any interface{}) bool { } return true default: - if f, ok := value.(apiBool); ok { + if f, ok := value.(iBool); ok { return f.Bool() } rv := reflect.ValueOf(any) @@ -595,7 +587,7 @@ func Int64(any interface{}) int64 { case []byte: return gbinary.DecodeToInt64(value) default: - if f, ok := value.(apiInt64); ok { + if f, ok := value.(iInt64); ok { return f.Int64() } s := String(value) @@ -720,7 +712,7 @@ func Uint64(any interface{}) uint64 { case []byte: return gbinary.DecodeToUint64(value) default: - if f, ok := value.(apiUint64); ok { + if f, ok := value.(iUint64); ok { return f.Uint64() } s := String(value) @@ -758,7 +750,7 @@ func Float32(any interface{}) float32 { case []byte: return gbinary.DecodeToFloat32(value) default: - if f, ok := value.(apiFloat32); ok { + if f, ok := value.(iFloat32); ok { return f.Float32() } v, _ := strconv.ParseFloat(String(any), 64) @@ -779,10 +771,29 @@ func Float64(any interface{}) float64 { case []byte: return gbinary.DecodeToFloat64(value) default: - if f, ok := value.(apiFloat64); ok { + if f, ok := value.(iFloat64); ok { return f.Float64() } v, _ := strconv.ParseFloat(String(any), 64) return v } } + +// checkJsonAndUnmarshalUseNumber checks if given `any` is JSON formatted string value and does converting using `json.UnmarshalUseNumber`. +func checkJsonAndUnmarshalUseNumber(any interface{}, target interface{}) bool { + switch r := any.(type) { + case []byte: + if json.Valid(r) { + _ = json.UnmarshalUseNumber(r, &target) + return true + } + + case string: + anyAsBytes := []byte(r) + if json.Valid(anyAsBytes) { + _ = json.UnmarshalUseNumber(anyAsBytes, &target) + return true + } + } + return false +} diff --git a/util/gconv/gconv_interface.go b/util/gconv/gconv_interface.go index 9c23f9425..18b91350c 100644 --- a/util/gconv/gconv_interface.go +++ b/util/gconv/gconv_interface.go @@ -8,100 +8,105 @@ package gconv import "github.com/gogf/gf/os/gtime" -// apiString is used for type assert api for String(). -type apiString interface { +// iString is used for type assert api for String(). +type iString interface { String() string } -// apiBool is used for type assert api for Bool(). -type apiBool interface { +// iBool is used for type assert api for Bool(). +type iBool interface { Bool() bool } -// apiInt64 is used for type assert api for Int64(). -type apiInt64 interface { +// iInt64 is used for type assert api for Int64(). +type iInt64 interface { Int64() int64 } -// apiUint64 is used for type assert api for Uint64(). -type apiUint64 interface { +// iUint64 is used for type assert api for Uint64(). +type iUint64 interface { Uint64() uint64 } -// apiFloat32 is used for type assert api for Float32(). -type apiFloat32 interface { +// iFloat32 is used for type assert api for Float32(). +type iFloat32 interface { Float32() float32 } -// apiFloat64 is used for type assert api for Float64(). -type apiFloat64 interface { +// iFloat64 is used for type assert api for Float64(). +type iFloat64 interface { Float64() float64 } -// apiError is used for type assert api for Error(). -type apiError interface { +// iError is used for type assert api for Error(). +type iError interface { Error() string } -// apiBytes is used for type assert api for Bytes(). -type apiBytes interface { +// iBytes is used for type assert api for Bytes(). +type iBytes interface { Bytes() []byte } -// apiInterfaces is used for type assert api for Interfaces(). -type apiInterfaces interface { +// iInterface is used for type assert api for Interface(). +type iInterface interface { + Interface() interface{} +} + +// iInterfaces is used for type assert api for Interfaces(). +type iInterfaces interface { Interfaces() []interface{} } -// apiFloats is used for type assert api for Floats(). -type apiFloats interface { +// iFloats is used for type assert api for Floats(). +type iFloats interface { Floats() []float64 } -// apiInts is used for type assert api for Ints(). -type apiInts interface { +// iInts is used for type assert api for Ints(). +type iInts interface { Ints() []int } -// apiStrings is used for type assert api for Strings(). -type apiStrings interface { +// iStrings is used for type assert api for Strings(). +type iStrings interface { Strings() []string } -// apiUints is used for type assert api for Uints(). -type apiUints interface { +// iUints is used for type assert api for Uints(). +type iUints interface { Uints() []uint } -// apiMapStrAny is the interface support for converting struct parameter to map. -type apiMapStrAny interface { +// iMapStrAny is the interface support for converting struct parameter to map. +type iMapStrAny interface { MapStrAny() map[string]interface{} } -// apiUnmarshalValue is the interface for custom defined types customizing value assignment. -// Note that only pointer can implement interface apiUnmarshalValue. -type apiUnmarshalValue interface { +// iUnmarshalValue is the interface for custom defined types customizing value assignment. +// Note that only pointer can implement interface iUnmarshalValue. +type iUnmarshalValue interface { UnmarshalValue(interface{}) error } -// apiUnmarshalText is the interface for custom defined types customizing value assignment. -// Note that only pointer can implement interface apiUnmarshalText. -type apiUnmarshalText interface { +// iUnmarshalText is the interface for custom defined types customizing value assignment. +// Note that only pointer can implement interface iUnmarshalText. +type iUnmarshalText interface { UnmarshalText(text []byte) error } -// apiUnmarshalText is the interface for custom defined types customizing value assignment. -// Note that only pointer can implement interface apiUnmarshalJSON. -type apiUnmarshalJSON interface { +// iUnmarshalText is the interface for custom defined types customizing value assignment. +// Note that only pointer can implement interface iUnmarshalJSON. +type iUnmarshalJSON interface { UnmarshalJSON(b []byte) error } -// apiSet is the interface for custom value assignment. -type apiSet interface { +// iSet is the interface for custom value assignment. +type iSet interface { Set(value interface{}) (old interface{}) } -// apiGTime is the interface for gtime.Time converting. -type apiGTime interface { +// iGTime is the interface for gtime.Time converting. +type iGTime interface { GTime(format ...string) *gtime.Time } diff --git a/util/gconv/gconv_map.go b/util/gconv/gconv_map.go index 0650f0c5c..25358edb6 100644 --- a/util/gconv/gconv_map.go +++ b/util/gconv/gconv_map.go @@ -216,7 +216,7 @@ func doMapConvertForMapOrStructValue(isRoot bool, value interface{}, recursive b return dataMap case reflect.Struct: // Map converting interface check. - if v, ok := value.(apiMapStrAny); ok { + if v, ok := value.(iMapStrAny); ok { m := v.MapStrAny() if recursive { for k, v := range m { diff --git a/util/gconv/gconv_maptomap.go b/util/gconv/gconv_maptomap.go index 973f12e52..ae0df0054 100644 --- a/util/gconv/gconv_maptomap.go +++ b/util/gconv/gconv_maptomap.go @@ -96,10 +96,10 @@ func doMapToMap(params interface{}, pointer interface{}, mapping ...map[string]s defer func() { // Catch the panic, especially the reflect operation panics. if exception := recover(); exception != nil { - if e, ok := exception.(errorStack); ok { - err = e + if v, ok := exception.(error); ok && gerror.HasStack(v) { + err = v } else { - err = gerror.NewCodeSkipf(gcode.CodeInternalError, 1, "%v", exception) + err = gerror.NewCodeSkipf(gcode.CodeInternalError, 1, "%+v", exception) } } }() diff --git a/util/gconv/gconv_maptomaps.go b/util/gconv/gconv_maptomaps.go index a3c0928b5..33fe9520a 100644 --- a/util/gconv/gconv_maptomaps.go +++ b/util/gconv/gconv_maptomaps.go @@ -114,12 +114,12 @@ func doMapToMaps(params interface{}, pointer interface{}, mapping ...map[string] return gerror.NewCode(gcode.CodeInvalidParameter, "pointer element should be type of map/*map") } defer func() { - // Catch the panic, especially the reflect operation panics. + // Catch the panic, especially the reflection operation panics. if exception := recover(); exception != nil { - if e, ok := exception.(errorStack); ok { - err = e + if v, ok := exception.(error); ok && gerror.HasStack(v) { + err = v } else { - err = gerror.NewCodeSkipf(gcode.CodeInternalError, 1, "%v", exception) + err = gerror.NewCodeSkipf(gcode.CodeInternalError, 1, "%+v", exception) } } }() diff --git a/util/gconv/gconv_slice_any.go b/util/gconv/gconv_slice_any.go index 90b5b372b..a33942877 100644 --- a/util/gconv/gconv_slice_any.go +++ b/util/gconv/gconv_slice_any.go @@ -22,7 +22,7 @@ func Interfaces(any interface{}) []interface{} { } if r, ok := any.([]interface{}); ok { return r - } else if r, ok := any.(apiInterfaces); ok { + } else if r, ok := any.(iInterfaces); ok { return r.Interfaces() } else { var array []interface{} diff --git a/util/gconv/gconv_slice_float.go b/util/gconv/gconv_slice_float.go index 86dd7ebe9..8b0f9f101 100644 --- a/util/gconv/gconv_slice_float.go +++ b/util/gconv/gconv_slice_float.go @@ -112,12 +112,17 @@ func Float32s(any interface{}) []float32 { array[k] = Float32(v) } default: - if v, ok := any.(apiFloats); ok { + if v, ok := any.(iFloats); ok { return Float32s(v.Floats()) } - if v, ok := any.(apiInterfaces); ok { + if v, ok := any.(iInterfaces); ok { return Float32s(v.Interfaces()) } + // JSON format string value converting. + var result []float32 + if checkJsonAndUnmarshalUseNumber(any, &result) { + return result + } // Not a common type, it then uses reflection for conversion. var reflectValue reflect.Value if v, ok := value.(reflect.Value); ok { @@ -142,6 +147,9 @@ func Float32s(any interface{}) []float32 { return slice default: + if reflectValue.IsZero() { + return []float32{} + } return []float32{Float32(any)} } } @@ -232,12 +240,17 @@ func Float64s(any interface{}) []float64 { array[k] = Float64(v) } default: - if v, ok := any.(apiFloats); ok { + if v, ok := any.(iFloats); ok { return v.Floats() } - if v, ok := any.(apiInterfaces); ok { + if v, ok := any.(iInterfaces); ok { return Floats(v.Interfaces()) } + // JSON format string value converting. + var result []float64 + if checkJsonAndUnmarshalUseNumber(any, &result) { + return result + } // Not a common type, it then uses reflection for conversion. var reflectValue reflect.Value if v, ok := value.(reflect.Value); ok { @@ -262,6 +275,9 @@ func Float64s(any interface{}) []float64 { return slice default: + if reflectValue.IsZero() { + return []float64{} + } return []float64{Float64(any)} } } diff --git a/util/gconv/gconv_slice_int.go b/util/gconv/gconv_slice_int.go index 1195d2053..17371dad4 100644 --- a/util/gconv/gconv_slice_int.go +++ b/util/gconv/gconv_slice_int.go @@ -6,7 +6,9 @@ package gconv -import "reflect" +import ( + "reflect" +) // SliceInt is alias of Ints. func SliceInt(any interface{}) []int { @@ -18,7 +20,7 @@ func SliceInt32(any interface{}) []int32 { return Int32s(any) } -// SliceInt is alias of Int64s. +// SliceInt64 is alias of Int64s. func SliceInt64(any interface{}) []int64 { return Int64s(any) } @@ -30,11 +32,6 @@ func Ints(any interface{}) []int { } var array []int switch value := any.(type) { - case string: - if value == "" { - return []int{} - } - return []int{Int(value)} case []string: array = make([]int, len(value)) for k, v := range value { @@ -117,12 +114,17 @@ func Ints(any interface{}) []int { array[k] = Int(v) } default: - if v, ok := any.(apiInts); ok { + if v, ok := any.(iInts); ok { return v.Ints() } - if v, ok := any.(apiInterfaces); ok { + if v, ok := any.(iInterfaces); ok { return Ints(v.Interfaces()) } + // JSON format string value converting. + var result []int + if checkJsonAndUnmarshalUseNumber(any, &result) { + return result + } // Not a common type, it then uses reflection for conversion. var reflectValue reflect.Value if v, ok := value.(reflect.Value); ok { @@ -147,6 +149,9 @@ func Ints(any interface{}) []int { return slice default: + if reflectValue.IsZero() { + return []int{} + } return []int{Int(any)} } } @@ -160,11 +165,6 @@ func Int32s(any interface{}) []int32 { } var array []int32 switch value := any.(type) { - case string: - if value == "" { - return []int32{} - } - return []int32{Int32(value)} case []string: array = make([]int32, len(value)) for k, v := range value { @@ -247,12 +247,17 @@ func Int32s(any interface{}) []int32 { array[k] = Int32(v) } default: - if v, ok := any.(apiInts); ok { + if v, ok := any.(iInts); ok { return Int32s(v.Ints()) } - if v, ok := any.(apiInterfaces); ok { + if v, ok := any.(iInterfaces); ok { return Int32s(v.Interfaces()) } + // JSON format string value converting. + var result []int32 + if checkJsonAndUnmarshalUseNumber(any, &result) { + return result + } // Not a common type, it then uses reflection for conversion. var reflectValue reflect.Value if v, ok := value.(reflect.Value); ok { @@ -277,6 +282,9 @@ func Int32s(any interface{}) []int32 { return slice default: + if reflectValue.IsZero() { + return []int32{} + } return []int32{Int32(any)} } } @@ -290,11 +298,6 @@ func Int64s(any interface{}) []int64 { } var array []int64 switch value := any.(type) { - case string: - if value == "" { - return []int64{} - } - return []int64{Int64(value)} case []string: array = make([]int64, len(value)) for k, v := range value { @@ -377,12 +380,17 @@ func Int64s(any interface{}) []int64 { array[k] = Int64(v) } default: - if v, ok := any.(apiInts); ok { + if v, ok := any.(iInts); ok { return Int64s(v.Ints()) } - if v, ok := any.(apiInterfaces); ok { + if v, ok := any.(iInterfaces); ok { return Int64s(v.Interfaces()) } + // JSON format string value converting. + var result []int64 + if checkJsonAndUnmarshalUseNumber(any, &result) { + return result + } // Not a common type, it then uses reflection for conversion. var reflectValue reflect.Value if v, ok := value.(reflect.Value); ok { @@ -407,6 +415,9 @@ func Int64s(any interface{}) []int64 { return slice default: + if reflectValue.IsZero() { + return []int64{} + } return []int64{Int64(any)} } } diff --git a/util/gconv/gconv_slice_str.go b/util/gconv/gconv_slice_str.go index 0d235d529..070546fc7 100644 --- a/util/gconv/gconv_slice_str.go +++ b/util/gconv/gconv_slice_str.go @@ -6,7 +6,9 @@ package gconv -import "reflect" +import ( + "reflect" +) // SliceStr is alias of Strings. func SliceStr(any interface{}) []string { @@ -98,12 +100,17 @@ func Strings(any interface{}) []string { array[k] = String(v) } default: - if v, ok := any.(apiStrings); ok { + if v, ok := any.(iStrings); ok { return v.Strings() } - if v, ok := any.(apiInterfaces); ok { + if v, ok := any.(iInterfaces); ok { return Strings(v.Interfaces()) } + // JSON format string value converting. + var result []string + if checkJsonAndUnmarshalUseNumber(any, &result) { + return result + } // Not a common type, it then uses reflection for conversion. var reflectValue reflect.Value if v, ok := value.(reflect.Value); ok { @@ -128,6 +135,9 @@ func Strings(any interface{}) []string { return slice default: + if reflectValue.IsZero() { + return []string{} + } return []string{String(any)} } } diff --git a/util/gconv/gconv_slice_uint.go b/util/gconv/gconv_slice_uint.go index 2cb3321d9..863ac33a8 100644 --- a/util/gconv/gconv_slice_uint.go +++ b/util/gconv/gconv_slice_uint.go @@ -113,12 +113,17 @@ func Uints(any interface{}) []uint { array[k] = Uint(v) } default: - if v, ok := any.(apiUints); ok { + if v, ok := any.(iUints); ok { return v.Uints() } - if v, ok := any.(apiInterfaces); ok { + if v, ok := any.(iInterfaces); ok { return Uints(v.Interfaces()) } + // JSON format string value converting. + var result []uint + if checkJsonAndUnmarshalUseNumber(any, &result) { + return result + } // Not a common type, it then uses reflection for conversion. var reflectValue reflect.Value if v, ok := value.(reflect.Value); ok { @@ -143,6 +148,9 @@ func Uints(any interface{}) []uint { return slice default: + if reflectValue.IsZero() { + return []uint{} + } return []uint{Uint(any)} } } @@ -238,12 +246,17 @@ func Uint32s(any interface{}) []uint32 { array[k] = Uint32(v) } default: - if v, ok := any.(apiUints); ok { + if v, ok := any.(iUints); ok { return Uint32s(v.Uints()) } - if v, ok := any.(apiInterfaces); ok { + if v, ok := any.(iInterfaces); ok { return Uint32s(v.Interfaces()) } + // JSON format string value converting. + var result []uint32 + if checkJsonAndUnmarshalUseNumber(any, &result) { + return result + } // Not a common type, it then uses reflection for conversion. var reflectValue reflect.Value if v, ok := value.(reflect.Value); ok { @@ -268,6 +281,9 @@ func Uint32s(any interface{}) []uint32 { return slice default: + if reflectValue.IsZero() { + return []uint32{} + } return []uint32{Uint32(any)} } } @@ -363,12 +379,17 @@ func Uint64s(any interface{}) []uint64 { array[k] = Uint64(v) } default: - if v, ok := any.(apiUints); ok { + if v, ok := any.(iUints); ok { return Uint64s(v.Uints()) } - if v, ok := any.(apiInterfaces); ok { + if v, ok := any.(iInterfaces); ok { return Uint64s(v.Interfaces()) } + // JSON format string value converting. + var result []uint64 + if checkJsonAndUnmarshalUseNumber(any, &result) { + return result + } // Not a common type, it then uses reflection for conversion. var reflectValue reflect.Value if v, ok := value.(reflect.Value); ok { @@ -393,6 +414,9 @@ func Uint64s(any interface{}) []uint64 { return slice default: + if reflectValue.IsZero() { + return []uint64{} + } return []uint64{Uint64(any)} } } diff --git a/util/gconv/gconv_struct.go b/util/gconv/gconv_struct.go index bb959daa1..3c2c1a34b 100644 --- a/util/gconv/gconv_struct.go +++ b/util/gconv/gconv_struct.go @@ -52,6 +52,48 @@ func StructDeep(params interface{}, pointer interface{}, mapping ...map[string]s return doStruct(params, pointer, keyToAttributeNameMapping, "") } +// doStructWithJsonCheck checks if given `params` is JSON, it then uses json.Unmarshal doing the converting. +func doStructWithJsonCheck(params interface{}, pointer interface{}) (err error, ok bool) { + switch r := params.(type) { + case []byte: + if json.Valid(r) { + if rv, ok := pointer.(reflect.Value); ok { + if rv.Kind() == reflect.Ptr { + if rv.IsNil() { + return nil, false + } + return json.UnmarshalUseNumber(r, rv.Interface()), true + } else if rv.CanAddr() { + return json.UnmarshalUseNumber(r, rv.Addr().Interface()), true + } + } else { + return json.UnmarshalUseNumber(r, pointer), true + } + } + case string: + if paramsBytes := []byte(r); json.Valid(paramsBytes) { + if rv, ok := pointer.(reflect.Value); ok { + if rv.Kind() == reflect.Ptr { + if rv.IsNil() { + return nil, false + } + return json.UnmarshalUseNumber(paramsBytes, rv.Interface()), true + } else if rv.CanAddr() { + return json.UnmarshalUseNumber(paramsBytes, rv.Addr().Interface()), true + } + } else { + return json.UnmarshalUseNumber(paramsBytes, pointer), true + } + } + default: + // The `params` might be struct that implements interface function Interface, eg: gvar.Var. + if v, ok := params.(iInterface); ok { + return doStructWithJsonCheck(v.Interface(), pointer) + } + } + return nil, false +} + // doStruct is the core internal converting function for any data to struct. func doStruct(params interface{}, pointer interface{}, mapping map[string]string, priorityTag string) (err error) { if params == nil { @@ -63,47 +105,28 @@ func doStruct(params interface{}, pointer interface{}, mapping map[string]string } defer func() { - // Catch the panic, especially the reflect operation panics. + // Catch the panic, especially the reflection operation panics. if exception := recover(); exception != nil { - if e, ok := exception.(errorStack); ok { - err = e + if v, ok := exception.(error); ok && gerror.HasStack(v) { + err = v } else { - err = gerror.NewCodeSkipf(gcode.CodeInternalError, 1, "%v", exception) + err = gerror.NewCodeSkipf(gcode.CodeInternalError, 1, "%+v", exception) } } }() - // If given `params` is JSON, it then uses json.Unmarshal doing the converting. - switch r := params.(type) { - case []byte: - if json.Valid(r) { - if rv, ok := pointer.(reflect.Value); ok { - if rv.Kind() == reflect.Ptr { - return json.UnmarshalUseNumber(r, rv.Interface()) - } else if rv.CanAddr() { - return json.UnmarshalUseNumber(r, rv.Addr().Interface()) - } - } else { - return json.UnmarshalUseNumber(r, pointer) - } - } - case string: - if paramsBytes := []byte(r); json.Valid(paramsBytes) { - if rv, ok := pointer.(reflect.Value); ok { - if rv.Kind() == reflect.Ptr { - return json.UnmarshalUseNumber(paramsBytes, rv.Interface()) - } else if rv.CanAddr() { - return json.UnmarshalUseNumber(paramsBytes, rv.Addr().Interface()) - } - } else { - return json.UnmarshalUseNumber(paramsBytes, pointer) - } - } + // JSON content converting. + err, ok := doStructWithJsonCheck(params, pointer) + if err != nil { + return err + } + if ok { + return nil } var ( paramsReflectValue reflect.Value - paramsInterface interface{} // DO NOT use `params` directly as it might be type of `reflect.Value` + paramsInterface interface{} // DO NOT use `params` directly as it might be type `reflect.Value` pointerReflectValue reflect.Value pointerReflectKind reflect.Kind pointerElemReflectValue reflect.Value // The pointed element. @@ -129,6 +152,7 @@ func doStruct(params interface{}, pointer interface{}, mapping map[string]string } pointerElemReflectValue = pointerReflectValue.Elem() } + // If `params` and `pointer` are the same type, the do directly assignment. // For performance enhancement purpose. if pointerElemReflectValue.IsValid() && pointerElemReflectValue.Type() == paramsReflectValue.Type() { @@ -148,7 +172,7 @@ func doStruct(params interface{}, pointer interface{}, mapping map[string]string e := reflect.New(pointerElemReflectValue.Type().Elem()).Elem() pointerElemReflectValue.Set(e.Addr()) } - //if v, ok := pointerElemReflectValue.Interface().(apiUnmarshalValue); ok { + //if v, ok := pointerElemReflectValue.Interface().(iUnmarshalValue); ok { // return v.UnmarshalValue(params) //} // Note that it's `pointerElemReflectValue` here not `pointerReflectValue`. @@ -284,7 +308,7 @@ func doStruct(params interface{}, pointer interface{}, mapping map[string]string } // Mark it done. doneMap[attrName] = struct{}{} - if err := bindVarToStructAttr(pointerElemReflectValue, attrName, mapV, mapping, priorityTag); err != nil { + if err := bindVarToStructAttr(pointerElemReflectValue, attrName, mapV, mapping); err != nil { return err } } @@ -292,7 +316,7 @@ func doStruct(params interface{}, pointer interface{}, mapping map[string]string } // bindVarToStructAttr sets value to struct object attribute by name. -func bindVarToStructAttr(elem reflect.Value, name string, value interface{}, mapping map[string]string, priorityTag string) (err error) { +func bindVarToStructAttr(elem reflect.Value, name string, value interface{}, mapping map[string]string) (err error) { structFieldValue := elem.FieldByName(name) if !structFieldValue.IsValid() { return nil @@ -303,7 +327,7 @@ func bindVarToStructAttr(elem reflect.Value, name string, value interface{}, map } defer func() { if exception := recover(); exception != nil { - if err = bindVarToReflectValue(structFieldValue, value, mapping, priorityTag); err != nil { + if err = bindVarToReflectValue(structFieldValue, value, mapping); err != nil { err = gerror.WrapCodef(gcode.CodeInternalError, err, `error binding value to attribute "%s"`, name) } } @@ -323,7 +347,7 @@ func bindVarToStructAttr(elem reflect.Value, name string, value interface{}, map return nil } -// bindVarToReflectValueWithInterfaceCheck does binding using common interfaces checks. +// bindVarToReflectValueWithInterfaceCheck does bind using common interfaces checks. func bindVarToReflectValueWithInterfaceCheck(reflectValue reflect.Value, value interface{}) (err error, ok bool) { var pointer interface{} if reflectValue.Kind() != reflect.Ptr && reflectValue.CanAddr() { @@ -340,11 +364,11 @@ func bindVarToReflectValueWithInterfaceCheck(reflectValue reflect.Value, value i pointer = reflectValue.Interface() } // UnmarshalValue. - if v, ok := pointer.(apiUnmarshalValue); ok { + if v, ok := pointer.(iUnmarshalValue); ok { return v.UnmarshalValue(value), ok } // UnmarshalText. - if v, ok := pointer.(apiUnmarshalText); ok { + if v, ok := pointer.(iUnmarshalText); ok { var valueBytes []byte if b, ok := value.([]byte); ok { valueBytes = b @@ -356,7 +380,7 @@ func bindVarToReflectValueWithInterfaceCheck(reflectValue reflect.Value, value i } } // UnmarshalJSON. - if v, ok := pointer.(apiUnmarshalJSON); ok { + if v, ok := pointer.(iUnmarshalJSON); ok { var valueBytes []byte if b, ok := value.([]byte); ok { valueBytes = b @@ -376,7 +400,7 @@ func bindVarToReflectValueWithInterfaceCheck(reflectValue reflect.Value, value i return v.UnmarshalJSON(valueBytes), ok } } - if v, ok := pointer.(apiSet); ok { + if v, ok := pointer.(iSet); ok { v.Set(value) return nil, ok } @@ -384,16 +408,27 @@ func bindVarToReflectValueWithInterfaceCheck(reflectValue reflect.Value, value i } // bindVarToReflectValue sets `value` to reflect value object `structFieldValue`. -func bindVarToReflectValue(structFieldValue reflect.Value, value interface{}, mapping map[string]string, priorityTag string) (err error) { +func bindVarToReflectValue(structFieldValue reflect.Value, value interface{}, mapping map[string]string) (err error) { + // JSON content converting. + err, ok := doStructWithJsonCheck(value, structFieldValue) + if err != nil { + return err + } + if ok { + return nil + } + + // Common interface check. if err, ok := bindVarToReflectValueWithInterfaceCheck(structFieldValue, value); ok { return err } + kind := structFieldValue.Kind() // Converting using interface, for some kinds. switch kind { case reflect.Slice, reflect.Array, reflect.Ptr, reflect.Interface: if !structFieldValue.IsNil() { - if v, ok := structFieldValue.Interface().(apiSet); ok { + if v, ok := structFieldValue.Interface().(iSet); ok { v.Set(value) return nil } @@ -407,7 +442,7 @@ func bindVarToReflectValue(structFieldValue reflect.Value, value interface{}, ma case reflect.Struct: // Recursively converting for struct attribute. - if err := doStruct(value, structFieldValue, nil, ""); err != nil { + if err = doStruct(value, structFieldValue, nil, ""); err != nil { // Note there's reflect conversion mechanism here. structFieldValue.Set(reflect.ValueOf(value).Convert(structFieldValue.Type())) } @@ -424,14 +459,14 @@ func bindVarToReflectValue(structFieldValue reflect.Value, value interface{}, ma for i := 0; i < v.Len(); i++ { if t.Kind() == reflect.Ptr { e := reflect.New(t.Elem()).Elem() - if err := doStruct(v.Index(i).Interface(), e, nil, ""); err != nil { + if err = doStruct(v.Index(i).Interface(), e, nil, ""); err != nil { // Note there's reflect conversion mechanism here. e.Set(reflect.ValueOf(v.Index(i).Interface()).Convert(t)) } a.Index(i).Set(e.Addr()) } else { e := reflect.New(t).Elem() - if err := doStruct(v.Index(i).Interface(), e, nil, ""); err != nil { + if err = doStruct(v.Index(i).Interface(), e, nil, ""); err != nil { // Note there's reflect conversion mechanism here. e.Set(reflect.ValueOf(v.Index(i).Interface()).Convert(t)) } @@ -443,17 +478,18 @@ func bindVarToReflectValue(structFieldValue reflect.Value, value interface{}, ma a = reflect.MakeSlice(structFieldValue.Type(), 1, 1) t := a.Index(0).Type() if t.Kind() == reflect.Ptr { + // Pointer element. e := reflect.New(t.Elem()).Elem() - if err := doStruct(value, e, nil, ""); err != nil { + if err = doStruct(value, e, nil, ""); err != nil { // Note there's reflect conversion mechanism here. e.Set(reflect.ValueOf(value).Convert(t)) } a.Index(0).Set(e.Addr()) } else { + // Just consider it as struct element. (Although it might be other types but not basic types, eg: map) e := reflect.New(t).Elem() - if err := doStruct(value, e, nil, ""); err != nil { - // Note there's reflect conversion mechanism here. - e.Set(reflect.ValueOf(value).Convert(t)) + if err = doStruct(value, e, nil, ""); err != nil { + return err } a.Index(0).Set(e) } @@ -467,7 +503,7 @@ func bindVarToReflectValue(structFieldValue reflect.Value, value interface{}, ma return err } elem := item.Elem() - if err = bindVarToReflectValue(elem, value, mapping, priorityTag); err == nil { + if err = bindVarToReflectValue(elem, value, mapping); err == nil { structFieldValue.Set(elem.Addr()) } diff --git a/util/gconv/gconv_structs.go b/util/gconv/gconv_structs.go index 2bb370af8..70209b2bd 100644 --- a/util/gconv/gconv_structs.go +++ b/util/gconv/gconv_structs.go @@ -59,10 +59,10 @@ func doStructs(params interface{}, pointer interface{}, mapping map[string]strin defer func() { // Catch the panic, especially the reflect operation panics. if exception := recover(); exception != nil { - if e, ok := exception.(errorStack); ok { - err = e + if v, ok := exception.(error); ok && gerror.HasStack(v) { + err = v } else { - err = gerror.NewCodeSkipf(gcode.CodeInternalError, 1, "%v", exception) + err = gerror.NewCodeSkipf(gcode.CodeInternalError, 1, "%+v", exception) } } }() diff --git a/util/gconv/gconv_time.go b/util/gconv/gconv_time.go index 20d9b77b7..fbb2a1d79 100644 --- a/util/gconv/gconv_time.go +++ b/util/gconv/gconv_time.go @@ -51,7 +51,7 @@ func GTime(any interface{}, format ...string) *gtime.Time { if any == nil { return nil } - if v, ok := any.(apiGTime); ok { + if v, ok := any.(iGTime); ok { return v.GTime(format...) } // It's already this type. diff --git a/util/gconv/gconv_z_unit_all_test.go b/util/gconv/gconv_z_unit_all_test.go index a358c2362..d444ba560 100644 --- a/util/gconv/gconv_z_unit_all_test.go +++ b/util/gconv/gconv_z_unit_all_test.go @@ -16,7 +16,7 @@ import ( "github.com/gogf/gf/util/gconv" ) -type apiString interface { +type iString interface { String() string } type S struct { @@ -26,7 +26,7 @@ func (s S) String() string { return "22222" } -type apiError interface { +type iError interface { Error() string } type S1 struct { @@ -570,12 +570,12 @@ func Test_String_All(t *testing.T) { t.AssertEQ(gconv.String(boolStruct{}), "{}") t.AssertEQ(gconv.String(&boolStruct{}), "{}") - var info apiString + var info iString info = new(S) t.AssertEQ(gconv.String(info), "22222") - var errinfo apiError - errinfo = new(S1) - t.AssertEQ(gconv.String(errinfo), "22222") + var errInfo iError + errInfo = new(S1) + t.AssertEQ(gconv.String(errInfo), "22222") }) } diff --git a/util/gconv/gconv_z_unit_scan_test.go b/util/gconv/gconv_z_unit_scan_test.go index 541baf7dc..281566d72 100644 --- a/util/gconv/gconv_z_unit_scan_test.go +++ b/util/gconv/gconv_z_unit_scan_test.go @@ -7,6 +7,7 @@ package gconv_test import ( + "github.com/gogf/gf/container/gvar" "github.com/gogf/gf/frame/g" "github.com/gogf/gf/test/gtest" "github.com/gogf/gf/util/gconv" @@ -193,3 +194,84 @@ func Test_Scan_Maps(t *testing.T) { }) }) } + +func Test_Scan_JsonAttributes(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + type Sku struct { + GiftId int64 `json:"gift_id"` + Name string `json:"name"` + ScorePrice int `json:"score_price"` + MarketPrice int `json:"market_price"` + CostPrice int `json:"cost_price"` + Stock int `json:"stock"` + } + v := gvar.New(` +[ +{"name": "red", "stock": 10, "gift_id": 1, "cost_price": 80, "score_price": 188, "market_price": 188}, +{"name": "blue", "stock": 100, "gift_id": 2, "cost_price": 81, "score_price": 200, "market_price": 288} +]`) + type Product struct { + Skus []Sku + } + var p *Product + err := gconv.Scan(g.Map{ + "Skus": v, + }, &p) + t.AssertNil(err) + t.Assert(len(p.Skus), 2) + + t.Assert(p.Skus[0].Name, "red") + t.Assert(p.Skus[0].Stock, 10) + t.Assert(p.Skus[0].GiftId, 1) + t.Assert(p.Skus[0].CostPrice, 80) + t.Assert(p.Skus[0].ScorePrice, 188) + t.Assert(p.Skus[0].MarketPrice, 188) + + t.Assert(p.Skus[1].Name, "blue") + t.Assert(p.Skus[1].Stock, 100) + t.Assert(p.Skus[1].GiftId, 2) + t.Assert(p.Skus[1].CostPrice, 81) + t.Assert(p.Skus[1].ScorePrice, 200) + t.Assert(p.Skus[1].MarketPrice, 288) + }) +} + +func Test_Scan_JsonAttributes_StringArray(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + type S struct { + Array []string + } + var s *S + err := gconv.Scan(g.Map{ + "Array": `["a", "b"]`, + }, &s) + t.AssertNil(err) + t.Assert(len(s.Array), 2) + t.Assert(s.Array[0], "a") + t.Assert(s.Array[1], "b") + }) + + gtest.C(t, func(t *gtest.T) { + type S struct { + Array []string + } + var s *S + err := gconv.Scan(g.Map{ + "Array": `[]`, + }, &s) + t.AssertNil(err) + t.Assert(len(s.Array), 0) + }) + + gtest.C(t, func(t *gtest.T) { + type S struct { + Array []int64 + } + var s *S + err := gconv.Scan(g.Map{ + "Array": `[]`, + }, &s) + t.AssertNil(err) + t.Assert(len(s.Array), 0) + }) +} diff --git a/util/guid/guid_string.go b/util/guid/guid_string.go index 666d0ec8d..e8386aeb8 100644 --- a/util/guid/guid_string.go +++ b/util/guid/guid_string.go @@ -10,7 +10,6 @@ import ( "github.com/gogf/gf/container/gtype" "github.com/gogf/gf/encoding/ghash" "github.com/gogf/gf/net/gipv4" - "github.com/gogf/gf/util/gconv" "github.com/gogf/gf/util/grand" "os" "strconv" @@ -94,7 +93,7 @@ func S(data ...[]byte) string { } else { panic("too many data parts, it should be no more than 2 parts") } - return gconv.UnsafeBytesToStr(b) + return string(b) } // getSequence increases and returns the sequence string in 3 bytes. diff --git a/util/gutil/gutil.go b/util/gutil/gutil.go index 38716cdf9..547a6369d 100644 --- a/util/gutil/gutil.go +++ b/util/gutil/gutil.go @@ -9,6 +9,8 @@ package gutil import ( "fmt" + "github.com/gogf/gf/errors/gcode" + "github.com/gogf/gf/errors/gerror" "github.com/gogf/gf/internal/empty" "github.com/gogf/gf/util/gconv" "reflect" @@ -23,8 +25,12 @@ func Throw(exception interface{}) { // It returns error if any exception occurs, or else it returns nil. func Try(try func()) (err error) { defer func() { - if e := recover(); e != nil { - err = fmt.Errorf(`%v`, e) + if exception := recover(); exception != nil { + if v, ok := exception.(error); ok && gerror.HasStack(v) { + err = v + } else { + err = gerror.NewCodef(gcode.CodeInternalError, `%+v`, exception) + } } }() try() @@ -36,10 +42,10 @@ func Try(try func()) (err error) { func TryCatch(try func(), catch ...func(exception error)) { defer func() { if exception := recover(); exception != nil && len(catch) > 0 { - if err, ok := exception.(error); ok { - catch[0](err) + if v, ok := exception.(error); ok && gerror.HasStack(v) { + catch[0](v) } else { - catch[0](fmt.Errorf(`%v`, exception)) + catch[0](fmt.Errorf(`%+v`, exception)) } } }() diff --git a/util/gutil/gutil_dump.go b/util/gutil/gutil_dump.go index e499b4886..2a58d0c5e 100644 --- a/util/gutil/gutil_dump.go +++ b/util/gutil/gutil_dump.go @@ -15,18 +15,18 @@ import ( "reflect" ) -// apiVal is used for type assert api for Val(). -type apiVal interface { +// iVal is used for type assert api for Val(). +type iVal interface { Val() interface{} } -// apiString is used for type assert api for String(). -type apiString interface { +// iString is used for type assert api for String(). +type iString interface { String() string } -// apiMapStrAny is the interface support for converting struct parameter to map. -type apiMapStrAny interface { +// iMapStrAny is the interface support for converting struct parameter to map. +type iMapStrAny interface { MapStrAny() map[string]interface{} } @@ -63,14 +63,14 @@ func Export(i ...interface{}) string { value = gconv.Map(value) case reflect.Struct: converted := false - if r, ok := value.(apiVal); ok { + if r, ok := value.(iVal); ok { if result := r.Val(); result != nil { value = result converted = true } } if !converted { - if r, ok := value.(apiMapStrAny); ok { + if r, ok := value.(iMapStrAny); ok { if result := r.MapStrAny(); result != nil { value = result converted = true @@ -78,7 +78,7 @@ func Export(i ...interface{}) string { } } if !converted { - if r, ok := value.(apiString); ok { + if r, ok := value.(iString); ok { value = r.String() } } diff --git a/util/gvalid/gvalid.go b/util/gvalid/gvalid.go index a035b9337..e15cc39c7 100644 --- a/util/gvalid/gvalid.go +++ b/util/gvalid/gvalid.go @@ -74,8 +74,8 @@ type fieldRule struct { Rule string // Rule string like: "max:6" } -// apiNoValidation is an interface that marks current struct not validated by package `gvalid`. -type apiNoValidation interface { +// iNoValidation is an interface that marks current struct not validated by package `gvalid`. +type iNoValidation interface { NoValidation() } diff --git a/util/gvalid/gvalid_validator_check_struct.go b/util/gvalid/gvalid_validator_check_struct.go index 78c4f9847..c70a8f077 100644 --- a/util/gvalid/gvalid_validator_check_struct.go +++ b/util/gvalid/gvalid_validator_check_struct.go @@ -37,7 +37,7 @@ func (v *Validator) doCheckStruct(object interface{}) Error { for _, field := range fieldMap { if field.IsEmbedded() { // No validation interface implements check. - if _, ok := field.Value.Interface().(apiNoValidation); ok { + if _, ok := field.Value.Interface().(iNoValidation); ok { continue } if _, ok := field.TagLookup(noValidationTagName); ok { diff --git a/util/gvalid/gvalid_validator_check_value.go b/util/gvalid/gvalid_validator_check_value.go index f02fff8a2..4519877ba 100644 --- a/util/gvalid/gvalid_validator_check_value.go +++ b/util/gvalid/gvalid_validator_check_value.go @@ -22,7 +22,7 @@ import ( "github.com/gogf/gf/util/gutil" ) -type apiTime interface { +type iTime interface { Date() (year int, month time.Month, day int) IsZero() bool } @@ -244,7 +244,7 @@ func (v *Validator) doCheckBuildInRules(input doCheckBuildInRulesInput) (match b // Date rules. case "date": // support for time value, eg: gtime.Time/*gtime.Time, time.Time/*time.Time. - if v, ok := input.Value.(apiTime); ok { + if v, ok := input.Value.(iTime); ok { return !v.IsZero(), nil } match = gregex.IsMatchString(`\d{4}[\.\-\_/]{0,1}\d{2}[\.\-\_/]{0,1}\d{2}`, valueStr) @@ -252,7 +252,7 @@ func (v *Validator) doCheckBuildInRules(input doCheckBuildInRulesInput) (match b // Date rule with specified format. case "date-format": // support for time value, eg: gtime.Time/*gtime.Time, time.Time/*time.Time. - if v, ok := input.Value.(apiTime); ok { + if v, ok := input.Value.(iTime); ok { return !v.IsZero(), nil } if _, err := gtime.StrToTimeFormat(valueStr, input.RulePattern); err == nil {