1
0
mirror of https://github.com/duke-git/lancet.git synced 2026-02-04 12:52:28 +08:00

Compare commits

..

6 Commits

Author SHA1 Message Date
Javen
0851b68b83 Feat/encryption for sm2 sm3 sm4 (#343)
* feat: add ContainAny

* feat:encryption adds support for SM2, SM3, and SM4 #131

* doc: add docment for SM2, SM3, and SM4 #131

---------

Co-authored-by: Jiawen <im@linjiawen.com>
2025-11-07 19:17:55 +08:00
Javen
5c13fd4f2f Fix/339 (#344)
* feat: add ContainAny

* fix: fix issue #339

---------

Co-authored-by: Jiawen <im@linjiawen.com>
2025-11-07 19:17:09 +08:00
dudaodong
889d0cc3d6 doc: update readme file 2025-11-01 21:45:56 +08:00
dudaodong
aa05027cab doc: update readme file 2025-11-01 21:44:03 +08:00
dudaodong
fabc3483ed doc: update readme file 2025-11-01 21:37:15 +08:00
dudaodong
30363242bb doc: update document for version v2.3.8 2025-11-01 21:25:10 +08:00
26 changed files with 2210 additions and 180 deletions

144
README.md
View File

@@ -84,6 +84,8 @@ func main() {
- [Cryptor](#user-content-cryptor)
- [Datetime](#user-content-datetime)
- [Datastructure](#user-content-datastructure)
- [EventBus](#user-content-eventbus)
- [Enum](#user-content-enum)
- [Fileutil](#user-content-fileutil)
- [Formatter](#user-content-formatter)
- [Function](#user-content-function)
@@ -313,6 +315,15 @@ import "github.com/duke-git/lancet/v2/convertor"
- **<big>ToPointer</big>** : return a pointer of passed value.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/convertor.md#ToPointer)]
[[play](https://go.dev/play/p/ASf_etHNlw1)]
- **<big>ToPointers</big>** : convert a slice of values to a slice of pointers.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/convertor.md#ToPointers)]
[[play](https://go.dev/play/p/ZUoXd2i5ZkV)]
- **<big>FromPointer</big>** : returns the value pointed to by the pointer.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/convertor.md#FromPointer)]
[[play](https://go.dev/play/p/wAp90V7Zu6g)]
- **<big>FromPointers</big>** : convert a slice of pointers to a slice of values.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/convertor.md#FromPointers)]
[[play](https://go.dev/play/p/qIPsyYtNy3Q)]
- **<big>ToString</big>** : convert value to string.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/convertor.md#ToString)]
[[play](https://go.dev/play/p/nF1zOOslpQq)]
@@ -512,6 +523,30 @@ import "github.com/duke-git/lancet/v2/cryptor"
- **<big>RsaVerifySign</big>** : verifies the signature of the data with RSA.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/cryptor.md#RsaVerifySign)]
[[play](https://go.dev/play/p/qhsbf8BJ6Mf)]
- **<big>GenerateSm2Key</big>** : generate SM2 private and public key.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/cryptor.md#GenerateSm2Key)]
[[play](https://go.dev/play/p/bKYMqRLvIx3)]
- **<big>Sm2Encrypt</big>** : encrypt data with SM2 public key.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/cryptor.md#Sm2Encrypt)]
[[play](https://go.dev/play/p/bKYMqRLvIx3)]
- **<big>Sm2Decrypt</big>** : decrypt data with SM2 private key.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/cryptor.md#Sm2Decrypt)]
[[play](https://go.dev/play/p/bKYMqRLvIx3)]
- **<big>Sm3</big>** : return the SM3 hash value (256-bit) of data.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/cryptor.md#Sm3)]
[[play](https://go.dev/play/p/zDAQpteAiOc)]
- **<big>Sm4EcbEncrypt</big>** : encrypt data with SM4 ECB mode.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/cryptor.md#Sm4EcbEncrypt)]
[[play](https://go.dev/play/p/l5IQxYuuaED)]
- **<big>Sm4EcbDecrypt</big>** : decrypt data with SM4 ECB mode.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/cryptor.md#Sm4EcbDecrypt)]
[[play](https://go.dev/play/p/l5IQxYuuaED)]
- **<big>Sm4CbcEncrypt</big>** : encrypt data with SM4 CBC mode.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/cryptor.md#Sm4CbcEncrypt)]
[[play](https://go.dev/play/p/65Q6iYhLRTa)]
- **<big>Sm4CbcDecrypt</big>** : decrypt data with SM4 CBC mode.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/cryptor.md#Sm4CbcDecrypt)]
[[play](https://go.dev/play/p/65Q6iYhLRTa)]
<h3 id="datetime"> 7. Datetime package supports date and time format and compare. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
@@ -724,7 +759,7 @@ import optional "github.com/duke-git/lancet/v2/datastructure/optional"
import "github.com/duke-git/lancet/v2/eventbus"
```
#### 函数列表:
#### Function list:
- **<big>NewEventBus</big>** : Create an EventBus instance.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/eventbus.md#NewEventBus)]
@@ -757,7 +792,70 @@ import "github.com/duke-git/lancet/v2/eventbus"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/eventbus.md#SetErrorHandler)]
[[play](https://go.dev/play/p/gmB0gnFe5mc)]
<h3 id="fileutil"> 9. Fileutil package implements some basic functions for file operations. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
<h3 id="enum"> 10. Package enum provides a simple enum implementation. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">Index</a></h3>
```go
import "github.com/duke-git/lancet/v2/enum"
```
#### Function list:
- **<big>NewItem</big>** : Creates a new enum item.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/enum.md#NewEventBus)]
[[play](https://go.dev/play/p/8qNsLw01HD5)]
- **<big>NewItemsFromPairs</big>** : Creates enum items from a slice of Pair structs.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/enum.md#NewItemsFromPairs)]
[[play](https://go.dev/play/p/xKnoGa7gnev)]
- **<big>Value</big>** : Returns the value of the enum item.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/enum.md#Value)]
[[play](https://go.dev/play/p/xKnoGa7gnev)]
- **<big>Name</big>** : Returns the name of the enum item.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/enum.md#Name)]
[[play](https://go.dev/play/p/xKnoGa7gnev)]
- **<big>Valid</big>** : Checks if the enum item is valid. If a custom check function is provided, it will be used to validate the value.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/enum.md#Valid)]
[[play](https://go.dev/play/p/pA3lYY2VSm3)]
- **<big>MarshalJSON</big>** : Implementation of json.Marshaler interface.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/enum.md#MarshalJSON)]
[[play](https://go.dev/play/p/zIZEdAnneB5)]
- **<big>NewRegistry</big>** : Creates a new enum registry.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/enum.md#NewRegistry)]
[[play](https://go.dev/play/p/ABEXsYfJKMo)]
- **<big>Add</big>** : Adds enum items to the registry.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/enum.md#Add)]
[[play](https://go.dev/play/p/ABEXsYfJKMo)]
- **<big>Remove</big>** : Removes an enum item from the registry by its value.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/enum.md#Remove)]
[[play](https://go.dev/play/p/dSG84wQ3TuC)]
- **<big>Update</big>** : Updates the name of an enum item in the registry by its value.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/enum.md#Update)]
[[play](https://go.dev/play/p/Ol0moT1J9Xl)]
- **<big>GetByValue</big>** : Retrieves an enum item by its value.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/enum.md#GetByValue)]
[[play](https://go.dev/play/p/niJ1U2KlE_m)]
- **<big>GetByName</big>** : Retrieves an enum item by its name.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/enum.md#GetByName)]
[[play](https://go.dev/play/p/49ie_gpqH0m)]
- **<big>Items</big>** : Returns a slice of all enum items in the registry.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/enum.md#Items)]
[[play](https://go.dev/play/p/lAJFAradbvQ)]
- **<big>Contains</big>** : Checks if an enum item with the given value exists in the registry.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/enum.md#Contains)]
[[play](https://go.dev/play/p/_T-lPYkZn2j)]
- **<big>Size</big>** : Returns the number of enum items in the registry.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/enum.md#Size)]
[[play](https://go.dev/play/p/TeDArWhlQe2)]
- **<big>Range</big>** : Iterates over all enum items in the registry and applies the given function.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/enum.md#Range)]
[[play](https://go.dev/play/p/GPsZbQbefWN)]
- **<big>SortedItems</big>** : Returns a slice of all enum items sorted by the given less function.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/enum.md#SortedItems)]
[[play](https://go.dev/play/p/tN9RE_m_WEI)]
- **<big>Filter</big>** : Returns a slice of enum items that satisfy the given predicate function.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/enum.md#Filter)]
[[play](https://go.dev/play/p/uTUpTdcyoCU)]
<h3 id="fileutil"> 11. Fileutil package implements some basic functions for file operations. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
```go
import "github.com/duke-git/lancet/v2/fileutil"
@@ -859,7 +957,7 @@ import "github.com/duke-git/lancet/v2/fileutil"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/fileutil.md#GetExeOrDllVersion)]
[[play](https://go.dev/play/p/iLRrDBhE38E)]
<h3 id="formatter"> 10. Formatter contains some functions for data formatting. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
<h3 id="formatter"> 12. Formatter contains some functions for data formatting. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
```go
import "github.com/duke-git/lancet/v2/formatter"
@@ -889,7 +987,7 @@ import "github.com/duke-git/lancet/v2/formatter"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/formatter.md#ParseBinaryBytes)]
[[play](https://go.dev/play/p/69v1tTT62x8)]
<h3 id="function"> 11. Function package can control the flow of function execution and support part of functional programming.&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
<h3 id="function"> 13. Function package can control the flow of function execution and support part of functional programming.&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
```go
import "github.com/duke-git/lancet/v2/function"
@@ -952,7 +1050,7 @@ import "github.com/duke-git/lancet/v2/function"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/function.md#Watcher)]
[[play](https://go.dev/play/p/l2yrOpCLd1I)]
<h3 id="maputil"> 12. Maputil package includes some functions to manipulate map.&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
<h3 id="maputil"> 14. Maputil package includes some functions to manipulate map.&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
```go
import "github.com/duke-git/lancet/v2/maputil"
@@ -1127,9 +1225,9 @@ import "github.com/duke-git/lancet/v2/maputil"
[[play](https://go.dev/play/p/bvNwNBZDm6v)]
- **<big>ToMarkdownTable</big>** : Convert a map slice data to a Markdown table string. It supports custom header display names and column display order.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/maputil.md#ToMarkdownTable)]
[[play](https://go.dev/play/p/todo)]
[[play](https://go.dev/play/p/w_pSLfeyEB5)]
<h3 id="mathutil"> 13. Mathutil package implements some functions for math calculation. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
<h3 id="mathutil"> 15. Mathutil package implements some functions for math calculation. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
```go
import "github.com/duke-git/lancet/v2/mathutil"
@@ -1240,7 +1338,7 @@ import "github.com/duke-git/lancet/v2/mathutil"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/mathutil.md#Combination)]
[[play](https://go.dev/play/p/ENFQRDQUFi9)]
<h3 id="netutil"> 14. Netutil package contains functions to get net information and send http request. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
<h3 id="netutil"> 16. Netutil package contains functions to get net information and send http request. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
```go
import "github.com/duke-git/lancet/v2/netutil"
@@ -1319,7 +1417,7 @@ import "github.com/duke-git/lancet/v2/netutil"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/netutil.md#AddQueryParams)]
[[play](https://go.dev/play/p/JLXl1hZK7l4)]
<h3 id="pointer"> 15. Pointer package contains some util functions to operate go pointer. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
<h3 id="pointer"> 17. Pointer package contains some util functions to operate go pointer. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
```go
import "github.com/duke-git/lancet/v2/pointer"
@@ -1343,7 +1441,7 @@ import "github.com/duke-git/lancet/v2/pointer"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/pointer.md#UnwrapOrDefault)]
[[play](https://go.dev/play/p/ZnGIHf8_o4E)]
<h3 id="random"> 16. Random package implements some basic functions to generate random int and string. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
<h3 id="random"> 18. Random package implements some basic functions to generate random int and string. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
```go
import "github.com/duke-git/lancet/v2/random"
@@ -1409,7 +1507,7 @@ import "github.com/duke-git/lancet/v2/random"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/random.md#RandNumberOfLength)]
[[play](https://go.dev/play/p/oyZbuV7bu7b)]
<h3 id="retry"> 17. Retry package is for executing a function repeatedly until it was successful or canceled by the context. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
<h3 id="retry"> 19. Retry package is for executing a function repeatedly until it was successful or canceled by the context. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
```go
import "github.com/duke-git/lancet/v2/retry"
@@ -1444,7 +1542,7 @@ import "github.com/duke-git/lancet/v2/retry"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/retry.md#RetryWithExponentialWithJitterBackoff)]
[[play](https://go.dev/play/p/xp1avQmn16X)]
<h3 id="slice"> 18. Slice contains some functions to manipulate slice. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
<h3 id="slice"> 20. Slice contains some functions to manipulate slice. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
```go
import "github.com/duke-git/lancet/v2/slice"
@@ -1716,7 +1814,7 @@ import "github.com/duke-git/lancet/v2/slice"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/slice.md#ConcatBy)]
[[play](https://go.dev/play/p/6QcUpcY4UMW)]
<h3 id="stream"> 19. Stream package implements a sequence of elements supporting sequential and operations. this package is an experiment to explore if stream in go can work as the way java does. its function is very limited. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
<h3 id="stream"> 21. Stream package implements a sequence of elements supporting sequential and operations. this package is an experiment to explore if stream in go can work as the way java does. its function is very limited. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
```go
import "github.com/duke-git/lancet/v2/stream"
@@ -1815,7 +1913,7 @@ import "github.com/duke-git/lancet/v2/stream"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/stream.md#LastIndexOf)]
[[play](https://go.dev/play/p/CjeoNw2eac_G)]
<h3 id="structs"> 20. Structs package provides several high level functions to manipulate struct, tag, and field. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
<h3 id="structs"> 22. Structs package provides several high level functions to manipulate struct, tag, and field. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
```go
import "github.com/duke-git/lancet/v2/structs"
@@ -1867,9 +1965,9 @@ import "github.com/duke-git/lancet/v2/structs"
[[play](https://go.dev/play/p/Ig75P-agN39)]
- **<big>TypeName</big>** : Return struct type name.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/struct.md#TypeName)]
[[play](https://go.dev/play/p/todo)]
[[play](https://go.dev/play/p/SWLWd0XBaBb)]
<h3 id="strutil"> 21. Strutil package contains some functions to manipulate string. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
<h3 id="strutil"> 23. Strutil package contains some functions to manipulate string. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
```go
import "github.com/duke-git/lancet/v2/strutil"
@@ -2021,7 +2119,7 @@ import "github.com/duke-git/lancet/v2/strutil"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/strutil.md#FindAllOccurrences)]
[[play](https://go.dev/play/p/uvyA6azGLB1)]
<h3 id="system"> 22. System package contain some functions about os, runtime, shell command. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
<h3 id="system"> 24. System package contain some functions about os, runtime, shell command. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
```go
import "github.com/duke-git/lancet/v2/system"
@@ -2069,7 +2167,7 @@ import "github.com/duke-git/lancet/v2/system"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/system.md#GetProcessInfo)]
[[play](https://go.dev/play/p/NQDVywEYYx7)]
<h3 id="tuple"> 23. Tuple package implements tuple data type and some operations on it. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
<h3 id="tuple"> 25. Tuple package implements tuple data type and some operations on it. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
```go
import "github.com/duke-git/lancet/v2/tuple"
@@ -2186,7 +2284,7 @@ import "github.com/duke-git/lancet/v2/tuple"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/tuple.md#Unzip10)]
[[play](https://go.dev/play/p/-taQB6Wfre_z)]
<h3 id="validator"> 24. Validator package contains some functions for data validation. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
<h3 id="validator"> 26. Validator package contains some functions for data validation. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
```go
import "github.com/duke-git/lancet/v2/validator"
@@ -2235,7 +2333,7 @@ import "github.com/duke-git/lancet/v2/validator"
[[play](https://go.dev/play/p/jlYApVLLGTZ)]
- **<big>IsEmail</big>** : check if the string is a email address.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/validator.md#IsEmail)]
[[play](https://go.dev/play/p/Os9VaFlT33G)]
[[play](https://go.dev/play/p/HVQ5LAe-vFz)]
- **<big>IsEmptyString</big>** : check if the string is empty.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/validator.md#IsEmptyString)]
[[play](https://go.dev/play/p/dpzgUjFnBCX)]
@@ -2328,12 +2426,12 @@ import "github.com/duke-git/lancet/v2/validator"
[[play](https://go.dev/play/p/yafpdxLiymu)]
- **<big>IsPassport</big>** : Passport validation(using regex).
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/validator.md#IsPassport)]
[[play](https://go.dev/play/p/todo)]
[[play](https://go.dev/play/p/dvOiV2BW7Aw)]
- **<big>IsChineseHMPassport</big>** : Mainland travel permit for Hong Kong, Macao validation (using regex).
[[doc](https://github.com/duke-git/lancet/blob/main/docs/en/api/packages/validator.md#IsChineseHMPassport)]
[[play](https://go.dev/play/p/todo)]
[[play](https://go.dev/play/p/xKG6spQTcY0)]
<h3 id="xerror"> 25. Xerror package implements helpers for errors. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
<h3 id="xerror"> 27. Xerror package implements helpers for errors. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">index</a></h3>
```go
import "github.com/duke-git/lancet/v2/xerror"

View File

@@ -83,6 +83,8 @@ func main() {
- [Cryptor](#user-content-cryptor)
- [Datetime](#user-content-datetime)
- [Datastructure](#user-content-datastructure)
- [EventBus](#user-content-eventbus)
- [Enum](#user-content-enum)
- [Fileutil](#user-content-fileutil)
- [Formatter](#user-content-formatter)
- [Function](#user-content-function)
@@ -312,6 +314,15 @@ import "github.com/duke-git/lancet/v2/convertor"
- **<big>ToPointer</big>** : 返回传入值的指针。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/convertor.md#ToPointer)]
[[play](https://go.dev/play/p/ASf_etHNlw1)]
- **<big>ToPointers</big>** : 将值的切片转换为指针的切片。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/convertor.md#ToPointers)]
[[play](https://go.dev/play/p/ZUoXd2i5ZkV)]
- **<big>FromPointer</big>** : 返回指针所指向的值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/convertor.md#FromPointer)]
[[play](https://go.dev/play/p/wAp90V7Zu6g)]
- **<big>FromPointers</big>** : 将指针的切片转换为值的切片。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/convertor.md#FromPointers)]
[[play](https://go.dev/play/p/qIPsyYtNy3Q)]
- **<big>ToString</big>** : 将值转换为字符串,对于数字、字符串、[]byte将转换为字符串。 对于其他类型(切片、映射、数组、结构)将调用 json.Marshal。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/convertor.md#ToString)]
[[play](https://go.dev/play/p/nF1zOOslpQq)]
@@ -524,6 +535,30 @@ import "github.com/duke-git/lancet/v2/cryptor"
- **<big>RsaVerifySign</big>** : 验证数据的签名是否符合 RSA 算法。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/cryptor.md#RsaVerifySign)]
[[play](https://go.dev/play/p/qhsbf8BJ6Mf)]
- **<big>GenerateSm2Key</big>** : 生成 SM2 公钥和私钥。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/cryptor.md#GenerateSm2Key)]
[[play](https://go.dev/play/p/bKYMqRLvIx3)]
- **<big>Sm2Encrypt</big>** : 使用 SM2 公钥加密数据。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/cryptor.md#Sm2Encrypt)]
[[play](https://go.dev/play/p/bKYMqRLvIx3)]
- **<big>Sm2Decrypt</big>** : 使用 SM2 私钥解密数据。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/cryptor.md#Sm2Decrypt)]
[[play](https://go.dev/play/p/bKYMqRLvIx3)]
- **<big>Sm3</big>** : 返回数据的 SM3 哈希值256 位)。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/cryptor.md#Sm3)]
[[play](https://go.dev/play/p/zDAQpteAiOc)]
- **<big>Sm4EcbEncrypt</big>** : 使用 SM4 ECB 模式加密数据。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/cryptor.md#Sm4EcbEncrypt)]
[[play](https://go.dev/play/p/l5IQxYuuaED)]
- **<big>Sm4EcbDecrypt</big>** : 使用 SM4 ECB 模式解密数据。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/cryptor.md#Sm4EcbDecrypt)]
[[play](https://go.dev/play/p/l5IQxYuuaED)]
- **<big>Sm4CbcEncrypt</big>** : 使用 SM4 CBC 模式加密数据。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/cryptor.md#Sm4CbcEncrypt)]
[[play](https://go.dev/play/p/65Q6iYhLRTa)]
- **<big>Sm4CbcDecrypt</big>** : 使用 SM4 CBC 模式解密数据。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/cryptor.md#Sm4CbcDecrypt)]
[[play](https://go.dev/play/p/65Q6iYhLRTa)]
<h3 id="datetime"> 7. datetime日期时间处理包格式化日期比较日期。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
@@ -767,7 +802,70 @@ import "github.com/duke-git/lancet/v2/eventbus"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/eventbus.md#SetErrorHandler)]
[[play](https://go.dev/play/p/gmB0gnFe5mc)]
<h3 id="fileutil"> 10. fileutil 包含文件基本操作。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
<h3 id="enum"> 10. Enum实现一个简单枚举工具包。. &nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">Index</a></h3>
```go
import "github.com/duke-git/lancet/v2/enum"
```
#### Function list:
- **<big>NewItem</big>** : 创建枚举项。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/enum.md#NewItem)]
[[play](https://go.dev/play/p/8qNsLw01HD5)]
- **<big>NewItemsFromPairs</big>** : 从 Pair 结构体的切片创建枚举项。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/enum.md#NewItemsFromPairs)]
[[play](https://go.dev/play/p/xKnoGa7gnev)]
- **<big>Value</big>** : 返回枚举项的值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/enum.md#Value)]
[[play](https://go.dev/play/p/xKnoGa7gnev)]
- **<big>Name</big>** : 返回枚举项的名称。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/enum.md#Name)]
[[play](https://go.dev/play/p/xKnoGa7gnev)]
- **<big>Valid</big>** : 检查枚举项是否有效。如果提供了自定义检查函数,将使用该函数验证值。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/enum.md#Valid)]
[[play](https://go.dev/play/p/pA3lYY2VSm3)]
- **<big>MarshalJSON</big>** : 枚举项实现 json.Marshaler 接口。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/enum.md#MarshalJSON)]
[[play](https://go.dev/play/p/zIZEdAnneB5)]
- **<big>NewRegistry</big>** : Registry 定义了一个通用的枚举注册表结构体。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/enum.md#NewRegistry)]
[[play](https://go.dev/play/p/ABEXsYfJKMo)]
- **<big>Add</big>** : 向枚举注册表添加枚举项。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/enum.md#Add)]
[[play](https://go.dev/play/p/ABEXsYfJKMo)]
- **<big>Remove</big>** : 在枚举注册表中删除枚举项。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/enum.md#Remove)]
[[play](https://go.dev/play/p/dSG84wQ3TuC)]
- **<big>Update</big>** : 在枚举注册表中更新枚举项。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/enum.md#Update)]
[[play](https://go.dev/play/p/Ol0moT1J9Xl)]
- **<big>GetByValue</big>** : 在枚举注册表中通过值获取枚举项。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/enum.md#GetByValue)]
[[play](https://go.dev/play/p/niJ1U2KlE_m)]
- **<big>GetByName</big>** : 在枚举注册表中通过名称获取枚举项。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/enum.md#GetByName)]
[[play](https://go.dev/play/p/49ie_gpqH0m)]
- **<big>Items</big>** : 返回枚举注册表中的枚举项。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/enum.md#Items)]
[[play](https://go.dev/play/p/lAJFAradbvQ)]
- **<big>Contains</big>** : 检查注册表中是否存在具有给定值的枚举项。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/enum.md#Contains)]
[[play](https://go.dev/play/p/_T-lPYkZn2j)]
- **<big>Size</big>** : 返回注册表中枚举项的数目。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/enum.md#Size)]
[[play](https://go.dev/play/p/TeDArWhlQe2)]
- **<big>Range</big>** : 遍历注册表中的所有枚举项,并应用给定的函数。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/enum.md#Range)]
[[play](https://go.dev/play/p/GPsZbQbefWN)]
- **<big>SortedItems</big>** : 返回按给定比较函数排序的所有枚举项的切片。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/enum.md#SortedItems)]
[[play](https://go.dev/play/p/tN9RE_m_WEI)]
- **<big>Filter</big>** : 返回满足给定谓词函数的枚举项切片。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/enum.md#Filter)]
[[play](https://go.dev/play/p/uTUpTdcyoCU)]
<h3 id="fileutil"> 11. fileutil 包含文件基本操作。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
```go
import "github.com/duke-git/lancet/v2/fileutil"
@@ -869,7 +967,7 @@ import "github.com/duke-git/lancet/v2/fileutil"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/fileutil.md#GetExeOrDllVersion)]
[[play](https://go.dev/play/p/iLRrDBhE38E)]
<h3 id="formatter"> 11. formatter 格式化器包含一些数据格式化处理方法。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
<h3 id="formatter"> 12. formatter 格式化器包含一些数据格式化处理方法。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
```go
import "github.com/duke-git/lancet/v2/formatter"
@@ -899,7 +997,7 @@ import "github.com/duke-git/lancet/v2/formatter"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/formatter.md#ParseBinaryBytes)]
[[play](https://go.dev/play/p/69v1tTT62x8)]
<h3 id="function"> 12. function 函数包控制函数执行流程,包含部分函数式编程。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
<h3 id="function"> 13. function 函数包控制函数执行流程,包含部分函数式编程。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
```go
import "github.com/duke-git/lancet/v2/function"
@@ -962,7 +1060,7 @@ import "github.com/duke-git/lancet/v2/function"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/function.md#Watcher)]
[[play](https://go.dev/play/p/l2yrOpCLd1I)]
<h3 id="maputil"> 13. maputil 包括一些操作 map 的函数。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
<h3 id="maputil"> 14. maputil 包括一些操作 map 的函数。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
```go
import "github.com/duke-git/lancet/v2/maputil"
@@ -1137,9 +1235,9 @@ import "github.com/duke-git/lancet/v2/maputil"
[[play](https://go.dev/play/p/bvNwNBZDm6v)]
- **<big>ToMarkdownTable</big>** : 将一个 map 切片数据转换为 Markdown 表格字符串。支持自定义表头显示名称和列的显示顺序。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/maputil.md#ToMarkdownTable)]
[[play](https://go.dev/play/p/todo)]
[[play](https://go.dev/play/p/w_pSLfeyEB5)]
<h3 id="mathutil"> 14. mathutil 包实现了一些数学计算的函数。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
<h3 id="mathutil"> 15. mathutil 包实现了一些数学计算的函数。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
```go
import "github.com/duke-git/lancet/v2/mathutil"
@@ -1250,7 +1348,7 @@ import "github.com/duke-git/lancet/v2/mathutil"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/mathutil.md#Combination)]
[[play](https://go.dev/play/p/ENFQRDQUFi9)]
<h3 id="netutil"> 15. netutil 网络包支持获取 ip 地址,发送 http 请求。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
<h3 id="netutil"> 16. netutil 网络包支持获取 ip 地址,发送 http 请求。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
```go
import "github.com/duke-git/lancet/v2/netutil"
@@ -1329,7 +1427,7 @@ import "github.com/duke-git/lancet/v2/netutil"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/netutil.md#AddQueryParams)]
[[play](https://go.dev/play/p/JLXl1hZK7l4)]
<h3 id="pointer"> 16. pointer 包支持一些指针类型的操作。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
<h3 id="pointer"> 17. pointer 包支持一些指针类型的操作。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
```go
import "github.com/duke-git/lancet/v2/pointer"
@@ -1353,7 +1451,7 @@ import "github.com/duke-git/lancet/v2/pointer"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/pointer.md#UnwrapOrDefault)]
[[play](https://go.dev/play/p/ZnGIHf8_o4E)]
<h3 id="random"> 17. random 随机数生成器包,可以生成随机[]bytes, int, string。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
<h3 id="random"> 18. random 随机数生成器包,可以生成随机[]bytes, int, string。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
```go
import "github.com/duke-git/lancet/v2/random"
@@ -1419,7 +1517,7 @@ import "github.com/duke-git/lancet/v2/random"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/random.md#RandNumberOfLength)]
[[play](https://go.dev/play/p/oyZbuV7bu7b)]
<h3 id="retry"> 18. retry 重试执行函数直到函数运行成功或被 context cancel。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
<h3 id="retry"> 19. retry 重试执行函数直到函数运行成功或被 context cancel。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
```go
import "github.com/duke-git/lancet/v2/retry"
@@ -1451,7 +1549,7 @@ import "github.com/duke-git/lancet/v2/retry"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/retry.md#RetryWithExponentialWithJitterBackoff)]
[[play](https://go.dev/play/p/xp1avQmn16X)]
<h3 id="slice"> 19. slice 包含操作切片的方法集合。&nbsp; &nbsp; &nbsp; &nbsp; <a href="#index">回到目录</a></h3>
<h3 id="slice"> 20. slice 包含操作切片的方法集合。&nbsp; &nbsp; &nbsp; &nbsp; <a href="#index">回到目录</a></h3>
```go
import "github.com/duke-git/lancet/v2/slice"
@@ -1725,7 +1823,7 @@ import "github.com/duke-git/lancet/v2/slice"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/slice.md#ConcatBy)]
[[play](https://go.dev/play/p/6QcUpcY4UMW)]
<h3 id="stream"> 20. stream 流,该包仅验证简单的 stream 实现,功能有限。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
<h3 id="stream"> 21. stream 流,该包仅验证简单的 stream 实现,功能有限。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
```go
import "github.com/duke-git/lancet/v2/stream"
@@ -1821,7 +1919,7 @@ import "github.com/duke-git/lancet/v2/stream"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/stream.md#LastIndexOf)]
[[play](https://go.dev/play/p/CjeoNw2eac_G)]
<h3 id="structs"> 21. structs 提供操作 struct, tag, field 的相关函数。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
<h3 id="structs"> 22. structs 提供操作 struct, tag, field 的相关函数。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
```go
import "github.com/duke-git/lancet/v2/structs"
@@ -1873,9 +1971,9 @@ import "github.com/duke-git/lancet/v2/structs"
[[play](https://go.dev/play/p/Ig75P-agN39)]
- **<big>TypeName</big>** : 获取结构体类型名。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/struct.md#TypeName)]
[[play](https://go.dev/play/p/todo)]
[[play](https://go.dev/play/p/SWLWd0XBaBb)]
<h3 id="strutil"> 22. strutil 包含字符串处理的相关函数。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
<h3 id="strutil"> 23. strutil 包含字符串处理的相关函数。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
```go
import "github.com/duke-git/lancet/v2/strutil"
@@ -2028,7 +2126,7 @@ import "github.com/duke-git/lancet/v2/strutil"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/strutil.md#FindAllOccurrences)]
[[play](https://go.dev/play/p/uvyA6azGLB1)]
<h3 id="system"> 23. system 包含 os, runtime, shell command 的相关函数。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
<h3 id="system"> 24. system 包含 os, runtime, shell command 的相关函数。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
```go
import "github.com/duke-git/lancet/v2/system"
@@ -2076,7 +2174,7 @@ import "github.com/duke-git/lancet/v2/system"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/system.md#GetProcessInfo)]
[[play](https://go.dev/play/p/NQDVywEYYx7)]
<h3 id="tuple"> 24. Tuple 包实现一个元组数据类型。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
<h3 id="tuple"> 25. Tuple 包实现一个元组数据类型。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
```go
import "github.com/duke-git/lancet/v2/tuple"
@@ -2193,7 +2291,7 @@ import "github.com/duke-git/lancet/v2/tuple"
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/tuple.md#Unzip10)]
[[play](https://go.dev/play/p/-taQB6Wfre_z)]
<h3 id="validator"> 25. validator 验证器包,包含常用字符串格式验证函数。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
<h3 id="validator"> 26. validator 验证器包,包含常用字符串格式验证函数。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
```go
import "github.com/duke-git/lancet/v2/validator"
@@ -2242,7 +2340,7 @@ import "github.com/duke-git/lancet/v2/validator"
[[play](https://go.dev/play/p/jlYApVLLGTZ)]
- **<big>IsEmail</big>** : 验证字符串是否是有效电子邮件地址。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/validator.md#IsEmail)]
[[play](https://go.dev/play/p/Os9VaFlT33G)]
[[play](https://go.dev/play/p/HVQ5LAe-vFz)]
- **<big>IsEmptyString</big>** : 验证字符串是否是空字符串。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/validator.md#IsEmptyString)]
[[play](https://go.dev/play/p/dpzgUjFnBCX)]
@@ -2335,11 +2433,12 @@ import "github.com/duke-git/lancet/v2/validator"
[[play](https://go.dev/play/p/yafpdxLiymu)]
- **<big>IsPassport</big>** : 判断护照(正则判断)。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/validator.md#IsPassport)]
[[play](https://go.dev/play/p/todo)]
[[play](https://go.dev/play/p/dvOiV2BW7Aw)]
- **<big>IsChineseHMPassport</big>** : 判断港澳台通行证(正则判断)。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/validator.md#IsChineseHMPassport)]
[[play](https://go.dev/play/p/todo)]
<h3 id="xerror"> 26. xerror 包实现一些错误处理函数。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
[[doc](https://github.com/duke-git/lancet/blob/main/docs/api/packages/validator.md#IsChineseHMPassport)]
[[play](https://go.dev/play/p/xKG6spQTcY0)]
<h3 id="xerror"> 27. xerror 包实现一些错误处理函数。&nbsp; &nbsp; &nbsp; &nbsp;<a href="#index">回到目录</a></h3>
```go
import "github.com/duke-git/lancet/v2/xerror"

View File

@@ -229,7 +229,7 @@ func ToPointer[T any](value T) *T {
}
// ToPointers convert a slice of values to a slice of pointers.
// Play: todo
// Play: https://go.dev/play/p/ZUoXd2i5ZkV
func ToPointers[T any](values []T) []*T {
result := make([]*T, len(values))
for i := range values {
@@ -239,7 +239,7 @@ func ToPointers[T any](values []T) []*T {
}
// FromPointer returns the value pointed to by the pointer.
// Play: todo
// Play: https://go.dev/play/p/wAp90V7Zu6g
func FromPointer[T any](ptr *T) T {
if ptr == nil {
var zeroValue T
@@ -250,7 +250,7 @@ func FromPointer[T any](ptr *T) T {
}
// FromPointers convert a slice of pointers to a slice of values.
// Play: todo
// Play: https://go.dev/play/p/qIPsyYtNy3Q
func FromPointers[T any](pointers []*T) []T {
result := make([]T, len(pointers))
for i, ptr := range pointers {

View File

@@ -169,6 +169,45 @@ func ExampleToPointer() {
// 123
}
func ExampleToPointers() {
strs := []string{"a", "b", "c"}
pointerStrs := ToPointers(strs)
fmt.Println(*pointerStrs[0])
fmt.Println(*pointerStrs[1])
fmt.Println(*pointerStrs[2])
// Output:
// a
// b
// c
}
func ExampleFromPointer() {
str := "abc"
strPtr := &str
result := FromPointer(strPtr)
fmt.Println(result)
// Output:
// abc
}
func ExampleFromPointers() {
strs := []string{"a", "b", "c"}
strPtr := []*string{&strs[0], &strs[1], &strs[2]}
result := FromPointers(strPtr)
fmt.Println(result[0])
fmt.Println(result[1])
fmt.Println(result[2])
// Output:
// a
// b
// c
}
func ExampleToMap() {
type Message struct {
name string

View File

@@ -0,0 +1,71 @@
package cryptor_test
import (
"encoding/hex"
"fmt"
"github.com/duke-git/lancet/v2/cryptor"
)
func ExampleSm3() {
data := []byte("hello world")
hash := cryptor.Sm3(data)
fmt.Println(hex.EncodeToString(hash))
// Output:
// 44f0061e69fa6fdfc290c494654a05dc0c053da7e5c52b84ef93a9d67d3fff88
}
func ExampleSm4EcbEncrypt() {
key := []byte("1234567890abcdef") // 16 bytes key
plaintext := []byte("hello world")
encrypted := cryptor.Sm4EcbEncrypt(plaintext, key)
decrypted := cryptor.Sm4EcbDecrypt(encrypted, key)
fmt.Println(string(decrypted))
// Output:
// hello world
}
func ExampleSm4CbcEncrypt() {
key := []byte("1234567890abcdef") // 16 bytes key
plaintext := []byte("hello world")
encrypted := cryptor.Sm4CbcEncrypt(plaintext, key)
decrypted := cryptor.Sm4CbcDecrypt(encrypted, key)
fmt.Println(string(decrypted))
// Output:
// hello world
}
func ExampleGenerateSm2Key() {
// Generate SM2 key pair
privateKey, err := cryptor.GenerateSm2Key()
if err != nil {
return
}
plaintext := []byte("hello world")
// Encrypt with public key
ciphertext, err := cryptor.Sm2Encrypt(&privateKey.PublicKey, plaintext)
if err != nil {
return
}
// Decrypt with private key
decrypted, err := cryptor.Sm2Decrypt(privateKey, ciphertext)
if err != nil {
return
}
fmt.Println(string(decrypted))
// Output:
// hello world
}

251
cryptor/gm_sm2.go Normal file
View File

@@ -0,0 +1,251 @@
package cryptor
import (
"crypto/elliptic"
"crypto/rand"
"encoding/binary"
"errors"
"io"
"math/big"
)
// SM2 implements the Chinese SM2 elliptic curve public key algorithm.
// SM2 is based on elliptic curve cryptography and provides encryption, decryption, signing and verification.
//
// Note: This implementation uses crypto/elliptic package methods (GenerateKey, ScalarBaseMult, ScalarMult, IsOnCurve)
// which are marked as deprecated in Go 1.20+. These methods still work correctly and are widely used.
// The //nolint:staticcheck directive suppresses deprecation warnings.
// A future version may replace these with a custom elliptic curve implementation.
var (
sm2P256 *sm2Curve
sm2P256Params = &elliptic.CurveParams{Name: "sm2p256v1"}
)
func init() {
// SM2 curve parameters
sm2P256Params.P, _ = new(big.Int).SetString("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF", 16)
sm2P256Params.N, _ = new(big.Int).SetString("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123", 16)
sm2P256Params.B, _ = new(big.Int).SetString("28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93", 16)
sm2P256Params.Gx, _ = new(big.Int).SetString("32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7", 16)
sm2P256Params.Gy, _ = new(big.Int).SetString("BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0", 16)
sm2P256Params.BitSize = 256
sm2P256 = &sm2Curve{sm2P256Params}
}
type sm2Curve struct {
*elliptic.CurveParams
}
// Sm2PrivateKey represents an SM2 private key.
type Sm2PrivateKey struct {
D *big.Int
PublicKey Sm2PublicKey
}
// Sm2PublicKey represents an SM2 public key.
type Sm2PublicKey struct {
X, Y *big.Int
}
// GenerateSm2Key generates a new SM2 private/public key pair.
// Play: https://go.dev/play/p/bKYMqRLvIx3
func GenerateSm2Key() (*Sm2PrivateKey, error) {
priv, x, y, err := elliptic.GenerateKey(sm2P256, rand.Reader)
if err != nil {
return nil, err
}
privateKey := &Sm2PrivateKey{
D: new(big.Int).SetBytes(priv),
PublicKey: Sm2PublicKey{
X: x,
Y: y,
},
}
return privateKey, nil
}
// Sm2Encrypt encrypts plaintext using SM2 public key.
// Returns ciphertext in the format: C1 || C3 || C2
// C1 = kG (65 bytes in uncompressed format)
// C3 = Hash(x2 || M || y2) (32 bytes for SM3)
// C2 = M xor t (same length as plaintext)
// Play: https://go.dev/play/p/bKYMqRLvIx3
func Sm2Encrypt(pub *Sm2PublicKey, plaintext []byte) ([]byte, error) {
if pub == nil || pub.X == nil || pub.Y == nil {
return nil, errors.New("sm2: invalid public key")
}
for {
// Generate random k
k, err := randFieldElement(sm2P256, rand.Reader)
if err != nil {
return nil, err
}
// C1 = kG
c1x, c1y := sm2P256.ScalarBaseMult(k.Bytes())
// kP = (x2, y2)
x2, y2 := sm2P256.ScalarMult(pub.X, pub.Y, k.Bytes())
// Derive key using KDF
kdfLen := len(plaintext)
t := sm2KDF(append(toBytes(sm2P256, x2), toBytes(sm2P256, y2)...), kdfLen)
// Check if t is all zeros
allZero := true
for _, b := range t {
if b != 0 {
allZero = false
break
}
}
if allZero {
continue
}
// C2 = M xor t
c2 := make([]byte, len(plaintext))
for i := 0; i < len(plaintext); i++ {
c2[i] = plaintext[i] ^ t[i]
}
// C3 = Hash(x2 || M || y2)
c3Input := append(toBytes(sm2P256, x2), plaintext...)
c3Input = append(c3Input, toBytes(sm2P256, y2)...)
c3 := Sm3(c3Input)
// Return C1 || C3 || C2
c1 := sm2MarshalUncompressed(sm2P256, c1x, c1y)
result := append(c1, c3...)
result = append(result, c2...)
return result, nil
}
}
// Sm2Decrypt decrypts ciphertext using SM2 private key.
// Expects ciphertext in the format: C1 || C3 || C2
// Play: https://go.dev/play/p/bKYMqRLvIx3
func Sm2Decrypt(priv *Sm2PrivateKey, ciphertext []byte) ([]byte, error) {
if priv == nil || priv.D == nil {
return nil, errors.New("sm2: invalid private key")
}
// Parse C1 (65 bytes), C3 (32 bytes), C2 (remaining)
if len(ciphertext) < 97 {
return nil, errors.New("sm2: ciphertext too short")
}
c1 := ciphertext[:65]
c3 := ciphertext[65:97]
c2 := ciphertext[97:]
// Parse C1
c1x, c1y := sm2UnmarshalUncompressed(sm2P256, c1)
if c1x == nil {
return nil, errors.New("sm2: invalid C1 point")
}
// Verify C1 is on curve
if !sm2P256.IsOnCurve(c1x, c1y) {
return nil, errors.New("sm2: C1 not on curve")
}
// dC1 = (x2, y2)
x2, y2 := sm2P256.ScalarMult(c1x, c1y, priv.D.Bytes())
// Derive key using KDF
kdfLen := len(c2)
t := sm2KDF(append(toBytes(sm2P256, x2), toBytes(sm2P256, y2)...), kdfLen)
// M = C2 xor t
plaintext := make([]byte, len(c2))
for i := 0; i < len(c2); i++ {
plaintext[i] = c2[i] ^ t[i]
}
// Verify C3 = Hash(x2 || M || y2)
u := append(toBytes(sm2P256, x2), plaintext...)
u = append(u, toBytes(sm2P256, y2)...)
hash := Sm3(u)
for i := 0; i < len(c3); i++ {
if c3[i] != hash[i] {
return nil, errors.New("sm2: hash verification failed")
}
}
return plaintext, nil
}
// SM2 KDF (Key Derivation Function)
func sm2KDF(z []byte, klen int) []byte {
limit := (klen + 31) / 32
result := make([]byte, 0, limit*32)
for i := 1; i <= limit; i++ {
counter := make([]byte, 4)
binary.BigEndian.PutUint32(counter, uint32(i))
hash := Sm3(append(z, counter...))
result = append(result, hash...)
}
return result[:klen]
}
func toBytes(curve elliptic.Curve, value *big.Int) []byte {
byteLen := (curve.Params().BitSize + 7) / 8
buf := make([]byte, byteLen)
b := value.Bytes()
copy(buf[byteLen-len(b):], b)
return buf
}
func sm2MarshalUncompressed(curve *sm2Curve, x, y *big.Int) []byte {
byteLen := (curve.BitSize + 7) / 8
ret := make([]byte, 1+2*byteLen)
ret[0] = 4 // uncompressed point
xBytes := x.Bytes()
copy(ret[1+byteLen-len(xBytes):], xBytes)
yBytes := y.Bytes()
copy(ret[1+2*byteLen-len(yBytes):], yBytes)
return ret
}
func sm2UnmarshalUncompressed(curve *sm2Curve, data []byte) (*big.Int, *big.Int) {
byteLen := (curve.BitSize + 7) / 8
if len(data) != 1+2*byteLen {
return nil, nil
}
if data[0] != 4 {
return nil, nil
}
x := new(big.Int).SetBytes(data[1 : 1+byteLen])
y := new(big.Int).SetBytes(data[1+byteLen:])
return x, y
}
func randFieldElement(c elliptic.Curve, rand io.Reader) (*big.Int, error) {
params := c.Params()
b := make([]byte, params.BitSize/8+8)
_, err := io.ReadFull(rand, b)
if err != nil {
return nil, err
}
k := new(big.Int).SetBytes(b)
n := new(big.Int).Sub(params.N, big.NewInt(1))
k.Mod(k, n)
k.Add(k, big.NewInt(1))
return k, nil
}

211
cryptor/gm_sm3.go Normal file
View File

@@ -0,0 +1,211 @@
package cryptor
import (
"encoding/binary"
"hash"
)
// SM3 implements the Chinese SM3 cryptographic hash algorithm.
// SM3 produces a 256-bit (32-byte) hash value.
const (
sm3BlockSize = 64
sm3Size = 32
sm3T1 = 0x79cc4519
sm3T2 = 0x7a879d8a
)
var sm3IV = [8]uint32{
0x7380166f, 0x4914b2b9, 0x172442d7, 0xda8a0600,
0xa96f30bc, 0x163138aa, 0xe38dee4d, 0xb0fb0e4e,
}
type sm3Digest struct {
h [8]uint32
x [sm3BlockSize]byte
nx int
len uint64
}
// Sm3 returns a new hash.Hash computing the SM3 checksum.
// Play: https://go.dev/play/p/zDAQpteAiOc
func Sm3(data []byte) []byte {
h := newSm3()
h.Write(data)
return h.Sum(nil)
}
func newSm3() hash.Hash {
d := new(sm3Digest)
d.Reset()
return d
}
func (d *sm3Digest) Reset() {
d.h = sm3IV
d.nx = 0
d.len = 0
}
func (d *sm3Digest) Size() int {
return sm3Size
}
func (d *sm3Digest) BlockSize() int {
return sm3BlockSize
}
func (d *sm3Digest) Write(p []byte) (nn int, err error) {
nn = len(p)
d.len += uint64(nn)
if d.nx > 0 {
n := copy(d.x[d.nx:], p)
d.nx += n
if d.nx == sm3BlockSize {
sm3Block(d, d.x[:])
d.nx = 0
}
p = p[n:]
}
if len(p) >= sm3BlockSize {
n := len(p) &^ (sm3BlockSize - 1)
sm3Block(d, p[:n])
p = p[n:]
}
if len(p) > 0 {
d.nx = copy(d.x[:], p)
}
return
}
func (d *sm3Digest) Sum(in []byte) []byte {
d0 := *d
hash := d0.checkSum()
return append(in, hash[:]...)
}
func (d *sm3Digest) checkSum() [sm3Size]byte {
len := d.len
var tmp [64]byte
tmp[0] = 0x80
if len%64 < 56 {
d.Write(tmp[0 : 56-len%64])
} else {
d.Write(tmp[0 : 64+56-len%64])
}
len <<= 3
binary.BigEndian.PutUint64(tmp[:], len)
d.Write(tmp[0:8])
if d.nx != 0 {
panic("d.nx != 0")
}
var digest [sm3Size]byte
for i := 0; i < 8; i++ {
binary.BigEndian.PutUint32(digest[i*4:], d.h[i])
}
return digest
}
func sm3Block(dig *sm3Digest, p []byte) {
var w [68]uint32
var w1 [64]uint32
h0, h1, h2, h3, h4, h5, h6, h7 := dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4], dig.h[5], dig.h[6], dig.h[7]
for len(p) >= sm3BlockSize {
for i := 0; i < 16; i++ {
j := i * 4
w[i] = binary.BigEndian.Uint32(p[j : j+4])
}
for i := 16; i < 68; i++ {
w[i] = sm3P1(w[i-16]^w[i-9]^sm3RotateLeft(w[i-3], 15)) ^ sm3RotateLeft(w[i-13], 7) ^ w[i-6]
}
for i := 0; i < 64; i++ {
w1[i] = w[i] ^ w[i+4]
}
A, B, C, D, E, F, G, H := h0, h1, h2, h3, h4, h5, h6, h7
for j := 0; j < 64; j++ {
var ss1, ss2, tt1, tt2, t uint32
if j < 16 {
t = sm3T1
} else {
t = sm3T2
}
ss1 = sm3RotateLeft(sm3RotateLeft(A, 12)+E+sm3RotateLeft(t, uint32(j%32)), 7)
ss2 = ss1 ^ sm3RotateLeft(A, 12)
if j < 16 {
tt1 = sm3FF0(A, B, C) + D + ss2 + w1[j]
tt2 = sm3GG0(E, F, G) + H + ss1 + w[j]
} else {
tt1 = sm3FF1(A, B, C) + D + ss2 + w1[j]
tt2 = sm3GG1(E, F, G) + H + ss1 + w[j]
}
D = C
C = sm3RotateLeft(B, 9)
B = A
A = tt1
H = G
G = sm3RotateLeft(F, 19)
F = E
E = sm3P0(tt2)
}
h0 ^= A
h1 ^= B
h2 ^= C
h3 ^= D
h4 ^= E
h5 ^= F
h6 ^= G
h7 ^= H
p = p[sm3BlockSize:]
}
dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4], dig.h[5], dig.h[6], dig.h[7] = h0, h1, h2, h3, h4, h5, h6, h7
}
func sm3RotateLeft(x, n uint32) uint32 {
return (x << n) | (x >> (32 - n))
}
func sm3P0(x uint32) uint32 {
return x ^ sm3RotateLeft(x, 9) ^ sm3RotateLeft(x, 17)
}
func sm3P1(x uint32) uint32 {
return x ^ sm3RotateLeft(x, 15) ^ sm3RotateLeft(x, 23)
}
func sm3FF0(x, y, z uint32) uint32 {
return x ^ y ^ z
}
func sm3FF1(x, y, z uint32) uint32 {
return (x & y) | (x & z) | (y & z)
}
func sm3GG0(x, y, z uint32) uint32 {
return x ^ y ^ z
}
func sm3GG1(x, y, z uint32) uint32 {
return (x & y) | (^x & z)
}

270
cryptor/gm_sm4.go Normal file
View File

@@ -0,0 +1,270 @@
package cryptor
import (
"crypto/cipher"
"crypto/rand"
"encoding/binary"
"io"
)
// SM4 implements the Chinese SM4 block cipher.
// SM4 is a 128-bit block cipher with 128-bit keys.
// This implementation uses pre-computed lookup tables for optimal performance.
const sm4BlockSize = 16
// Pre-computed T-transformation lookup tables for performance optimization
var sm4T1Table [256][4]uint32 // S-box + L1 transformation
var sm4T2Table [256][4]uint32 // S-box + L2 transformation
var sm4Sbox = [256]byte{
0xd6, 0x90, 0xe9, 0xfe, 0xcc, 0xe1, 0x3d, 0xb7, 0x16, 0xb6, 0x14, 0xc2, 0x28, 0xfb, 0x2c, 0x05,
0x2b, 0x67, 0x9a, 0x76, 0x2a, 0xbe, 0x04, 0xc3, 0xaa, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99,
0x9c, 0x42, 0x50, 0xf4, 0x91, 0xef, 0x98, 0x7a, 0x33, 0x54, 0x0b, 0x43, 0xed, 0xcf, 0xac, 0x62,
0xe4, 0xb3, 0x1c, 0xa9, 0xc9, 0x08, 0xe8, 0x95, 0x80, 0xdf, 0x94, 0xfa, 0x75, 0x8f, 0x3f, 0xa6,
0x47, 0x07, 0xa7, 0xfc, 0xf3, 0x73, 0x17, 0xba, 0x83, 0x59, 0x3c, 0x19, 0xe6, 0x85, 0x4f, 0xa8,
0x68, 0x6b, 0x81, 0xb2, 0x71, 0x64, 0xda, 0x8b, 0xf8, 0xeb, 0x0f, 0x4b, 0x70, 0x56, 0x9d, 0x35,
0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, 0xd1, 0xa2, 0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, 0x87,
0xd4, 0x00, 0x46, 0x57, 0x9f, 0xd3, 0x27, 0x52, 0x4c, 0x36, 0x02, 0xe7, 0xa0, 0xc4, 0xc8, 0x9e,
0xea, 0xbf, 0x8a, 0xd2, 0x40, 0xc7, 0x38, 0xb5, 0xa3, 0xf7, 0xf2, 0xce, 0xf9, 0x61, 0x15, 0xa1,
0xe0, 0xae, 0x5d, 0xa4, 0x9b, 0x34, 0x1a, 0x55, 0xad, 0x93, 0x32, 0x30, 0xf5, 0x8c, 0xb1, 0xe3,
0x1d, 0xf6, 0xe2, 0x2e, 0x82, 0x66, 0xca, 0x60, 0xc0, 0x29, 0x23, 0xab, 0x0d, 0x53, 0x4e, 0x6f,
0xd5, 0xdb, 0x37, 0x45, 0xde, 0xfd, 0x8e, 0x2f, 0x03, 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b, 0x51,
0x8d, 0x1b, 0xaf, 0x92, 0xbb, 0xdd, 0xbc, 0x7f, 0x11, 0xd9, 0x5c, 0x41, 0x1f, 0x10, 0x5a, 0xd8,
0x0a, 0xc1, 0x31, 0x88, 0xa5, 0xcd, 0x7b, 0xbd, 0x2d, 0x74, 0xd0, 0x12, 0xb8, 0xe5, 0xb4, 0xb0,
0x89, 0x69, 0x97, 0x4a, 0x0c, 0x96, 0x77, 0x7e, 0x65, 0xb9, 0xf1, 0x09, 0xc5, 0x6e, 0xc6, 0x84,
0x18, 0xf0, 0x7d, 0xec, 0x3a, 0xdc, 0x4d, 0x20, 0x79, 0xee, 0x5f, 0x3e, 0xd7, 0xcb, 0x39, 0x48,
}
var sm4FK = [4]uint32{0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc}
var sm4CK = [32]uint32{
0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269,
0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9,
0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249,
0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9,
0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229,
0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299,
0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209,
0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279,
}
// 初始化预计算查找表
func init() {
// Pre-compute all possible T1 and T2 transformations
for pos := 0; pos < 4; pos++ {
for i := 0; i < 256; i++ {
// S-box 替换
sboxVal := sm4Sbox[i]
// 根据字节位置计算偏移
shift := uint32((3 - pos) * 8)
b := uint32(sboxVal) << shift
// L1 变换b ^ ROL(b,2) ^ ROL(b,10) ^ ROL(b,18) ^ ROL(b,24)
sm4T1Table[i][pos] = b ^ sm4RotateLeft(b, 2) ^ sm4RotateLeft(b, 10) ^ sm4RotateLeft(b, 18) ^ sm4RotateLeft(b, 24)
// L2 变换b ^ ROL(b,13) ^ ROL(b,23)
sm4T2Table[i][pos] = b ^ sm4RotateLeft(b, 13) ^ sm4RotateLeft(b, 23)
}
}
}
type sm4Cipher struct {
enc [32]uint32
dec [32]uint32
}
// Sm4EcbEncrypt encrypts data using SM4 in ECB mode.
// key must be 16 bytes.
// Play: https://go.dev/play/p/l5IQxYuuaED
func Sm4EcbEncrypt(data, key []byte) []byte {
if len(key) != 16 {
panic("sm4: key length must be 16 bytes")
}
c := newSm4Cipher(key)
padded := pkcs7Padding(data, sm4BlockSize)
encrypted := make([]byte, len(padded))
for i := 0; i < len(padded); i += sm4BlockSize {
c.Encrypt(encrypted[i:i+sm4BlockSize], padded[i:i+sm4BlockSize])
}
return encrypted
}
// Sm4EcbDecrypt decrypts data using SM4 in ECB mode.
// key must be 16 bytes.
// Play: https://go.dev/play/p/l5IQxYuuaED
func Sm4EcbDecrypt(encrypted, key []byte) []byte {
if len(key) != 16 {
panic("sm4: key length must be 16 bytes")
}
if len(encrypted)%sm4BlockSize != 0 {
panic("sm4: encrypted data length must be multiple of block size")
}
c := newSm4Cipher(key)
decrypted := make([]byte, len(encrypted))
for i := 0; i < len(encrypted); i += sm4BlockSize {
c.Decrypt(decrypted[i:i+sm4BlockSize], encrypted[i:i+sm4BlockSize])
}
return pkcs7UnPadding(decrypted)
}
// Sm4CbcEncrypt encrypts data using SM4 in CBC mode.
// key must be 16 bytes.
// Play: https://go.dev/play/p/65Q6iYhLRTa
func Sm4CbcEncrypt(data, key []byte) []byte {
if len(key) != 16 {
panic("sm4: key length must be 16 bytes")
}
c := newSm4Cipher(key)
padded := pkcs7Padding(data, sm4BlockSize)
iv := make([]byte, sm4BlockSize)
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
panic("sm4: failed to generate IV: " + err.Error())
}
encrypted := make([]byte, len(padded))
mode := cipher.NewCBCEncrypter(c, iv)
mode.CryptBlocks(encrypted, padded)
return append(iv, encrypted...)
}
// Sm4CbcDecrypt decrypts data using SM4 in CBC mode.
// key must be 16 bytes.
// Play: https://go.dev/play/p/65Q6iYhLRTa
func Sm4CbcDecrypt(encrypted, key []byte) []byte {
if len(key) != 16 {
panic("sm4: key length must be 16 bytes")
}
if len(encrypted) < sm4BlockSize {
panic("sm4: encrypted data too short")
}
if len(encrypted)%sm4BlockSize != 0 {
panic("sm4: encrypted data length must be multiple of block size")
}
c := newSm4Cipher(key)
iv := encrypted[:sm4BlockSize]
ciphertext := encrypted[sm4BlockSize:]
decrypted := make([]byte, len(ciphertext))
mode := cipher.NewCBCDecrypter(c, iv)
mode.CryptBlocks(decrypted, ciphertext)
return pkcs7UnPadding(decrypted)
}
func newSm4Cipher(key []byte) *sm4Cipher {
c := &sm4Cipher{}
var mk [4]uint32
for i := 0; i < 4; i++ {
mk[i] = binary.BigEndian.Uint32(key[i*4 : (i+1)*4])
}
var k [36]uint32
k[0] = mk[0] ^ sm4FK[0]
k[1] = mk[1] ^ sm4FK[1]
k[2] = mk[2] ^ sm4FK[2]
k[3] = mk[3] ^ sm4FK[3]
for i := 0; i < 32; i++ {
k[i+4] = k[i] ^ sm4T2Fast(k[i+1]^k[i+2]^k[i+3]^sm4CK[i])
c.enc[i] = k[i+4]
}
for i := 0; i < 32; i++ {
c.dec[i] = c.enc[31-i]
}
return c
}
func (c *sm4Cipher) BlockSize() int {
return sm4BlockSize
}
func (c *sm4Cipher) Encrypt(dst, src []byte) {
if len(src) < sm4BlockSize {
panic("sm4: input not full block")
}
if len(dst) < sm4BlockSize {
panic("sm4: output not full block")
}
// 使用局部变量避免数组分配,提升性能
x0 := binary.BigEndian.Uint32(src[0:4])
x1 := binary.BigEndian.Uint32(src[4:8])
x2 := binary.BigEndian.Uint32(src[8:12])
x3 := binary.BigEndian.Uint32(src[12:16])
// 32 轮加密
for i := 0; i < 32; i++ {
t := x1 ^ x2 ^ x3 ^ c.enc[i]
x0 ^= sm4T1Fast(t)
x0, x1, x2, x3 = x1, x2, x3, x0
}
binary.BigEndian.PutUint32(dst[0:4], x3)
binary.BigEndian.PutUint32(dst[4:8], x2)
binary.BigEndian.PutUint32(dst[8:12], x1)
binary.BigEndian.PutUint32(dst[12:16], x0)
}
func (c *sm4Cipher) Decrypt(dst, src []byte) {
if len(src) < sm4BlockSize {
panic("sm4: input not full block")
}
if len(dst) < sm4BlockSize {
panic("sm4: output not full block")
}
x0 := binary.BigEndian.Uint32(src[0:4])
x1 := binary.BigEndian.Uint32(src[4:8])
x2 := binary.BigEndian.Uint32(src[8:12])
x3 := binary.BigEndian.Uint32(src[12:16])
// 32 轮解密
for i := 0; i < 32; i++ {
t := x1 ^ x2 ^ x3 ^ c.dec[i]
x0 ^= sm4T1Fast(t)
x0, x1, x2, x3 = x1, x2, x3, x0
}
binary.BigEndian.PutUint32(dst[0:4], x3)
binary.BigEndian.PutUint32(dst[4:8], x2)
binary.BigEndian.PutUint32(dst[8:12], x1)
binary.BigEndian.PutUint32(dst[12:16], x0)
}
// 使用预计算查找表的快速 T1 变换(用于加密轮函数)
func sm4T1Fast(a uint32) uint32 {
return sm4T1Table[byte(a>>24)][0] ^
sm4T1Table[byte(a>>16)][1] ^
sm4T1Table[byte(a>>8)][2] ^
sm4T1Table[byte(a)][3]
}
// 使用预计算查找表的快速 T2 变换(用于密钥扩展)
func sm4T2Fast(a uint32) uint32 {
return sm4T2Table[byte(a>>24)][0] ^
sm4T2Table[byte(a>>16)][1] ^
sm4T2Table[byte(a>>8)][2] ^
sm4T2Table[byte(a)][3]
}
func sm4RotateLeft(x uint32, n uint32) uint32 {
return (x << n) | (x >> (32 - n))
}

163
cryptor/gm_test.go Normal file
View File

@@ -0,0 +1,163 @@
package cryptor
import (
"encoding/hex"
"testing"
"github.com/duke-git/lancet/v2/internal"
)
func TestSm3(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSm3")
tests := []struct {
input string
expected string
}{
{
input: "abc",
expected: "66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0",
},
{
input: "abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd",
expected: "debe9ff92275b8a138604889c18e5a4d6fdb70e5387e5765293dcba39c0c5732",
},
{
input: "",
expected: "1ab21d8355cfa17f8e61194831e81a8f22bec8c728fefb747ed035eb5082aa2b",
},
}
for _, tt := range tests {
result := Sm3([]byte(tt.input))
resultHex := hex.EncodeToString(result)
assert.Equal(tt.expected, resultHex)
}
}
func TestSm4EcbEncryptDecrypt(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSm4EcbEncryptDecrypt")
key := []byte("1234567890abcdef") // 16 bytes
plaintext := []byte("Hello, SM4!")
// Encrypt
encrypted := Sm4EcbEncrypt(plaintext, key)
assert.IsNotNil(encrypted)
// Decrypt
decrypted := Sm4EcbDecrypt(encrypted, key)
assert.Equal(plaintext, decrypted)
}
func TestSm4CbcEncryptDecrypt(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSm4CbcEncryptDecrypt")
key := []byte("1234567890abcdef") // 16 bytes
plaintext := []byte("Hello, SM4 CBC mode!")
// Encrypt
encrypted := Sm4CbcEncrypt(plaintext, key)
assert.IsNotNil(encrypted)
// Decrypt
decrypted := Sm4CbcDecrypt(encrypted, key)
assert.Equal(plaintext, decrypted)
}
func TestSm4EcbWithLongData(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSm4EcbWithLongData")
key := []byte("1234567890abcdef")
plaintext := []byte("This is a longer message that spans multiple blocks for SM4 encryption testing.")
encrypted := Sm4EcbEncrypt(plaintext, key)
decrypted := Sm4EcbDecrypt(encrypted, key)
assert.Equal(plaintext, decrypted)
}
func TestSm2EncryptDecrypt(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSm2EncryptDecrypt")
// Generate key pair
privateKey, err := GenerateSm2Key()
assert.IsNil(err)
assert.IsNotNil(privateKey)
plaintext := []byte("Hello, SM2!")
// Encrypt with public key
ciphertext, err := Sm2Encrypt(&privateKey.PublicKey, plaintext)
assert.IsNil(err)
assert.IsNotNil(ciphertext)
// Decrypt with private key
decrypted, err := Sm2Decrypt(privateKey, ciphertext)
assert.IsNil(err)
assert.Equal(plaintext, decrypted)
}
func TestSm2WithLongData(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSm2WithLongData")
privateKey, err := GenerateSm2Key()
assert.IsNil(err)
plaintext := []byte("This is a longer message for SM2 encryption testing. " +
"SM2 is an elliptic curve public key cryptography algorithm.")
ciphertext, err := Sm2Encrypt(&privateKey.PublicKey, plaintext)
assert.IsNil(err)
decrypted, err := Sm2Decrypt(privateKey, ciphertext)
assert.IsNil(err)
assert.Equal(plaintext, decrypted)
}
func TestSm4InvalidKeyLength(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSm4InvalidKeyLength")
defer func() {
if r := recover(); r != nil {
assert.IsNotNil(r)
}
}()
key := []byte("short")
plaintext := []byte("test")
Sm4EcbEncrypt(plaintext, key) // Should panic
}
func TestSm2InvalidInput(t *testing.T) {
t.Parallel()
assert := internal.NewAssert(t, "TestSm2InvalidInput")
// Test with nil public key
_, err := Sm2Encrypt(nil, []byte("test"))
assert.IsNotNil(err)
// Test with nil private key
_, err = Sm2Decrypt(nil, []byte("test"))
assert.IsNotNil(err)
// Test with invalid ciphertext
privateKey, _ := GenerateSm2Key()
_, err = Sm2Decrypt(privateKey, []byte("short"))
assert.IsNotNil(err)
}

View File

@@ -33,6 +33,9 @@ import (
- [ToJson](#ToJson)
- [ToMap](#ToMap)
- [ToPointer](#ToPointer)
- [ToPointers](#ToPointers)
- [FromPointer](#FromPointer)
- [FromPointers](#FromPointers)
- [ToString](#ToString)
- [StructToMap](#StructToMap)
- [MapToSlice](#MapToSlice)
@@ -456,6 +459,108 @@ func main() {
}
```
### <span id="ToPointers">ToPointers</span>
<p>将值的切片转换为指针的切片。</p>
<b>函数签名:</b>
```go
func ToPointers[T any](values []T) []*T
```
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/ZUoXd2i5ZkV)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
strs := []string{"a", "b", "c"}
pointerStrs := convertor.ToPointers(strs)
fmt.Println(*pointerStrs[0])
fmt.Println(*pointerStrs[1])
fmt.Println(*pointerStrs[2])
// Output:
// a
// b
// c
}
```
### <span id="FromPointer">FromPointer</span>
<p>返回指针所指向的值。</p>
<b>函数签名:</b>
```go
func FromPointer[T any](ptr *T) T
```
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/wAp90V7Zu6g)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
str := "abc"
strPtr := &str
result := convertor.FromPointer(strPtr)
fmt.Println(result)
// Output:
// abc
}
```
### <span id="FromPointers">FromPointers</span>
<p>将指针的切片转换为值的切片。</p>
<b>函数签名:</b>
```go
func FromPointers[T any](pointers []*T) []T
```
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/qIPsyYtNy3Q)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
strs := []string{"a", "b", "c"}
strPtr := []*string{&strs[0], &strs[1], &strs[2]}
result := convertor.FromPointers(strPtr)
fmt.Println(result[0])
fmt.Println(result[1])
fmt.Println(result[2])
// Output:
// a
// b
// c
}
```
### <span id="ToString">ToString</span>
<p>将值转换为字符串,对于数字、字符串、[]byte将转换为字符串。 对于其他类型(切片、映射、数组、结构体)将调用 json.Marshal</p>
@@ -1179,4 +1284,4 @@ func main() {
// Output:
// 9876543210
}
```
```

View File

@@ -1,6 +1,6 @@
# Cryptor
cryptor 包包含数据加密和解密功能。支持 base64, md5, hmac, hash, aes, des, rsa。
cryptor 包包含数据加密和解密功能。支持 base64, md5, hmac, hash, aes, des, rsa, sm2, sm3, sm4
<div STYLE="page-break-after: always;"></div>
@@ -74,6 +74,14 @@ import (
- [RsaDecryptOAEP](#RsaDecryptOAEP)
- [RsaSign](#RsaSign)
- [RsaVerifySign](#RsaVerifySign)
- [Sm3](#Sm3)
- [Sm4EcbEncrypt](#Sm4EcbEncrypt)
- [Sm4EcbDecrypt](#Sm4EcbDecrypt)
- [Sm4CbcEncrypt](#Sm4CbcEncrypt)
- [Sm4CbcDecrypt](#Sm4CbcDecrypt)
- [GenerateSm2Key](#GenerateSm2Key)
- [Sm2Encrypt](#Sm2Encrypt)
- [Sm2Decrypt](#Sm2Decrypt)
<div STYLE="page-break-after: always;"></div>
@@ -1829,3 +1837,279 @@ func main() {
}
}
```
### <span id="Sm3">Sm3</span>
<p>计算 SM3 哈希值国密SM3密码杂凑算法。SM3 是中国国家密码管理局发布的密码杂凑算法,用于替代 MD5/SHA-1/SHA-2 等国际算法。</p>
<b>函数签名:</b>
```go
func Sm3(data []byte) []byte
```
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/zDAQpteAiOc)</span></b>
```go
package main
import (
"encoding/hex"
"fmt"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
data := []byte("hello world")
hash := cryptor.Sm3(data)
fmt.Println(hex.EncodeToString(hash))
// Output:
// 44f0061e69fa6fdfc290c494654a05dc0c053da7e5c52b84ef93a9d67d3fff88
}
```
### <span id="Sm4EcbEncrypt">Sm4EcbEncrypt</span>
<p>使用 SM4 ECB 模式加密数据国密SM4分组密码算法。密钥长度必须为 16 字节。</p>
<b>函数签名:</b>
```go
func Sm4EcbEncrypt(data, key []byte) []byte
```
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/l5IQxYuuaED)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
key := []byte("1234567890abcdef") // 16 bytes key
plaintext := []byte("hello world")
encrypted := cryptor.Sm4EcbEncrypt(plaintext, key)
decrypted := cryptor.Sm4EcbDecrypt(encrypted, key)
fmt.Println(string(decrypted))
// Output:
// hello world
}
```
### <span id="Sm4EcbDecrypt">Sm4EcbDecrypt</span>
<p>使用 SM4 ECB 模式解密数据。密钥长度必须为 16 字节。</p>
<b>函数签名:</b>
```go
func Sm4EcbDecrypt(encrypted, key []byte) []byte
```
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/l5IQxYuuaED)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
key := []byte("1234567890abcdef")
plaintext := []byte("hello world")
encrypted := cryptor.Sm4EcbEncrypt(plaintext, key)
decrypted := cryptor.Sm4EcbDecrypt(encrypted, key)
fmt.Println(string(decrypted))
// Output:
// hello world
}
```
### <span id="Sm4CbcEncrypt">Sm4CbcEncrypt</span>
<p>使用 SM4 CBC 模式加密数据。密钥长度必须为 16 字节。返回的密文包含 IV前 16 字节)。</p>
<b>函数签名:</b>
```go
func Sm4CbcEncrypt(data, key []byte) []byte
```
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/65Q6iYhLRTa)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
key := []byte("1234567890abcdef")
plaintext := []byte("hello world")
encrypted := cryptor.Sm4CbcEncrypt(plaintext, key)
decrypted := cryptor.Sm4CbcDecrypt(encrypted, key)
fmt.Println(string(decrypted))
// Output:
// hello world
}
```
### <span id="Sm4CbcDecrypt">Sm4CbcDecrypt</span>
<p>使用 SM4 CBC 模式解密数据。密钥长度必须为 16 字节。密文应包含 IV前 16 字节)。</p>
<b>函数签名:</b>
```go
func Sm4CbcDecrypt(encrypted, key []byte) []byte
```
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/65Q6iYhLRTa)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
key := []byte("1234567890abcdef")
plaintext := []byte("hello world")
encrypted := cryptor.Sm4CbcEncrypt(plaintext, key)
decrypted := cryptor.Sm4CbcDecrypt(encrypted, key)
fmt.Println(string(decrypted))
// Output:
// hello world
}
```
### <span id="GenerateSm2Key">GenerateSm2Key</span>
<p>生成 SM2 密钥对国密SM2椭圆曲线公钥密码算法。SM2 是基于椭圆曲线的非对称加密算法。</p>
<b>函数签名:</b>
```go
func GenerateSm2Key() (*Sm2PrivateKey, error)
```
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/bKYMqRLvIx3)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
privateKey, err := cryptor.GenerateSm2Key()
if err != nil {
return
}
plaintext := []byte("hello world")
ciphertext, _ := cryptor.Sm2Encrypt(&privateKey.PublicKey, plaintext)
decrypted, _ := cryptor.Sm2Decrypt(privateKey, ciphertext)
fmt.Println(string(decrypted))
// Output:
// hello world
}
```
### <span id="Sm2Encrypt">Sm2Encrypt</span>
<p>使用 SM2 公钥加密数据。返回的密文格式为C1(65字节) || C3(32字节) || C2(明文长度)。</p>
<b>函数签名:</b>
```go
func Sm2Encrypt(pub *Sm2PublicKey, plaintext []byte) ([]byte, error)
```
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/bKYMqRLvIx3)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
privateKey, _ := cryptor.GenerateSm2Key()
plaintext := []byte("hello world")
ciphertext, _ := cryptor.Sm2Encrypt(&privateKey.PublicKey, plaintext)
decrypted, _ := cryptor.Sm2Decrypt(privateKey, ciphertext)
fmt.Println(string(decrypted))
// Output:
// hello world
}
```
### <span id="Sm2Decrypt">Sm2Decrypt</span>
<p>使用 SM2 私钥解密数据。密文格式应为C1(65字节) || C3(32字节) || C2(明文长度)。</p>
<b>函数签名:</b>
```go
func Sm2Decrypt(priv *Sm2PrivateKey, ciphertext []byte) ([]byte, error)
```
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/bKYMqRLvIx3)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
privateKey, _ := cryptor.GenerateSm2Key()
plaintext := []byte("hello world")
ciphertext, _ := cryptor.Sm2Encrypt(&privateKey.PublicKey, plaintext)
decrypted, _ := cryptor.Sm2Decrypt(privateKey, ciphertext)
fmt.Println(string(decrypted))
// Output:
// hello world
}
```

View File

@@ -1,12 +1,12 @@
# Enum
Enum实现一个简单枚举工具包。
Enum 实现一个简单枚举工具包。
<div STYLE="page-break-after: always;"></div>
## 源码:
- [https://github.com/duke-git/lancet/blob/main/enum/enum.go](https://github.com/duke-git/lancet/blob/main/enum/enum.go)
- [https://github.com/duke-git/lancet/blob/main/enum/enum.go](https://github.com/duke-git/lancet/blob/main/enum/enum.go)
<div STYLE="page-break-after: always;"></div>
@@ -55,7 +55,7 @@ import (
func NewItem[T comparable](value T, name string) *Item[T]
```
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/todo)</span></b>
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/8qNsLw01HD5)</span></b>
```go
package main
@@ -96,7 +96,7 @@ func main() {
func NewItemsFromPairs[T comparable](pairs ...Pair[T]) []*Item[T]
```
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/todo)</span></b>
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/xKnoGa7gnev)</span></b>
```go
package main
@@ -139,7 +139,7 @@ func main() {
func (it *Item[T]) Value() T
```
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/todo)</span></b>
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/xKnoGa7gnev)</span></b>
```go
package main
@@ -182,7 +182,7 @@ func main() {
func (it *Item[T]) Name() string
```
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/todo)</span></b>
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/xKnoGa7gnev)</span></b>
```go
package main
@@ -225,7 +225,7 @@ func main() {
func (it *Item[T]) Valid(checker ...func(T) bool) bool
```
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/todo)</span></b>
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/pA3lYY2VSm3)</span></b>
```go
package main
@@ -258,7 +258,7 @@ func main() {
### <span id="MarshalJSON">MarshalJSON</span>
<p>枚举项实现json.Marshaler 接口。</p>
<p>枚举项实现json.Marshaler接口。</p>
<b>函数签名:</b>
@@ -267,7 +267,7 @@ func (it *Item[T]) MarshalJSON() ([]byte, error)
func (it *Item[T]) UnmarshalJSON(data []byte) error
```
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/todo)</span></b>
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/zIZEdAnneB5)</span></b>
```go
package main
@@ -290,7 +290,7 @@ func main() {
data, _ := item.MarshalJSON()
fmt.Println(string(data))
var unmarshaledItem Item[Status]
var unmarshaledItem enum.Item[Status]
_ = unmarshaledItem.UnmarshalJSON(data)
fmt.Println(unmarshaledItem.Name(), unmarshaledItem.Value())
@@ -310,7 +310,7 @@ func main() {
func NewRegistry[T comparable](items ...*Item[T]) *Registry[T]
```
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/todo)</span></b>
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/ABEXsYfJKMo)</span></b>
```go
package main
@@ -359,7 +359,7 @@ func main() {
func (r *Registry[T]) Add(items ...*Item[T])
```
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/todo)</span></b>
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/ABEXsYfJKMo)</span></b>
```go
package main
@@ -408,7 +408,7 @@ func main() {
func (r *Registry[T]) Remove(value T) bool
```
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/todo)</span></b>
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/dSG84wQ3TuC)</span></b>
```go
package main
@@ -454,7 +454,7 @@ func main() {
func (r *Registry[T]) Update(value T, newName string) bool
```
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/todo)</span></b>
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/Ol0moT1J9Xl)</span></b>
```go
package main
@@ -500,7 +500,7 @@ func main() {
func (r *Registry[T]) GetByValue(value T) (*Item[T], bool)
```
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/todo)</span></b>
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/niJ1U2KlE_m)</span></b>
```go
package main
@@ -520,9 +520,9 @@ const (
func main() {
registry := enum.NewRegistry[Status]()
item1 := enum.NewItem(Active, "Active")
item := enum.NewItem(Active, "Active")
registry.Add(item1, item2)
registry.Add(item)
if item, found := registry.GetByValue(Active); found {
fmt.Println("Found name by value:", item.Name())
@@ -543,7 +543,7 @@ func main() {
func (r *Registry[T]) GetByName(name string) (*Item[T], bool)
```
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/todo)</span></b>
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/49ie_gpqH0m)</span></b>
```go
package main
@@ -586,7 +586,7 @@ func main() {
func (r *Registry[T]) Items() []*Item[T]
```
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/todo)</span></b>
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/lAJFAradbvQ)</span></b>
```go
package main
@@ -631,7 +631,7 @@ func main() {
func (r *Registry[T]) Contains(value T) bool
```
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/todo)</span></b>
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/_T-lPYkZn2j)</span></b>
```go
package main
@@ -673,7 +673,7 @@ func main() {
func (r *Registry[T]) Size() int
```
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/todo)</span></b>
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/TeDArWhlQe2)</span></b>
```go
package main
@@ -721,7 +721,7 @@ func main() {
func (r *Registry[T]) Range(fn func(*Item[T]) bool)
```
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/todo)</span></b>
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/GPsZbQbefWN)</span></b>
```go
package main
@@ -745,7 +745,7 @@ func main() {
item2 := enum.NewItem(Inactive, "Inactive")
registry.Add(item1, item2)
registry.Range(func(item *Item[Status]) bool {
registry.Range(func(item *enum.Item[Status]) bool {
fmt.Println(item.Name(), item.Value())
return true // continue iteration
})
@@ -766,7 +766,7 @@ func main() {
func (r *Registry[T]) SortedItems(less func(*Item[T], *Item[T]) bool) []*Item[T]
```
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/todo)</span></b>
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/tN9RE_m_WEI)</span></b>
```go
package main
@@ -790,8 +790,8 @@ func main() {
item2 := enum.NewItem(Active, "Active")
registry.Add(item1, item2)
for _, item := range registry.SortedItems(func(i1, i2 *Item[Status]) bool {
return i1.value < i2.value
for _, item := range registry.SortedItems(func(i1, i2 *enum.Item[Status]) bool {
return i1.Value() < i2.Value()
}) {
fmt.Println(item.Name(), item.Value())
}
@@ -812,7 +812,7 @@ func main() {
func (r *Registry[T]) Filter(predicate func(*Item[T]) bool) []*Item[T]
```
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/todo)</span></b>
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/uTUpTdcyoCU)</span></b>
```go
package main
@@ -836,7 +836,7 @@ func main() {
item2 := enum.NewItem(Inactive, "Inactive")
registry.Add(item1, item2)
activeItems := registry.Filter(func(item *Item[Status]) bool {
activeItems := registry.Filter(func(item *enum.Item[Status]) bool {
return item.Value() == Active
})
@@ -847,4 +847,4 @@ func main() {
// Output:
// Active 1
}
```
```

View File

@@ -2357,8 +2357,8 @@ func main() {
编辑
func ToMarkdownTable(data []map[string]interface{}, headerMap map[string]string, columnOrder []string) string
```
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/todo)</span></b>
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/w_pSLfeyEB5)</span></b>
```go
package main
@@ -2410,4 +2410,4 @@ func main() {
// |50000|Alice|
// |60000|Bob|
}
```
```

View File

@@ -69,7 +69,7 @@ func main() {
}
p1 := &People{Name: "11"}
s := structs.New(p1)
fmt.Println(s.ToMap())
// Output:
@@ -261,7 +261,7 @@ func main() {
tag := n.Tag()
fmt.Println(tag.Name)
// Output:
// name
}
@@ -295,10 +295,10 @@ func main() {
s := structs.New(p1)
n, _ := s.Field("Name")
fmt.Println(n.Value())
// Output:
// Output:
// 111
}
```
@@ -338,11 +338,11 @@ func main() {
s := structs.New(c1)
n, _ := s.Field("Name")
a, _ := s.Field("Age")
fmt.Println(n.IsEmbedded())
fmt.Println(a.IsEmbedded())
// Output:
// Output:
// true
// false
}
@@ -377,11 +377,11 @@ func main() {
s := structs.New(p1)
n, _ := s.Field("Name")
a, _ := s.Field("age")
fmt.Println(n.IsExported())
fmt.Println(a.IsExported())
// Output:
// Output:
// true
// false
}
@@ -416,11 +416,11 @@ func main() {
s := structs.New(p1)
n, _ := s.Field("Name")
a, _ := s.Field("Age")
fmt.Println(n.IsZero())
fmt.Println(a.IsZero())
// Output:
// Output:
// true
// false
}
@@ -455,11 +455,11 @@ func main() {
s := structs.New(p1)
n, _ := s.Field("Name")
a, _ := s.Field("Age")
fmt.Println(n.Name())
fmt.Println(a.Name())
// Output:
// Output:
// Name
// Age
}
@@ -494,11 +494,11 @@ func main() {
s := structs.New(p1)
n, _ := s.Field("Name")
a, _ := s.Field("Age")
fmt.Println(n.Kind())
fmt.Println(a.Kind())
// Output:
// Output:
// string
// int
}
@@ -514,7 +514,7 @@ func main() {
func (s *Struct) TypeName() string
```
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/todo)</span></b>
<b>示例:<span style="float:right;display:inline-block;">[运行](https://go.dev/play/p/SWLWd0XBaBb)</span></b>
```go
package main
@@ -529,13 +529,13 @@ func main() {
Name string
Age int
}
p := &Parent{Age: 11}
s := structs.New(p1)
s := structs.New(p)
fmt.Println(s.TypeName())
// Output:
// Output:
// Parent
}
```
@@ -569,10 +569,10 @@ func main() {
p1 := &Parent{arr: []int{1, 2, 3}}
s := structs.New(p1)
a, _ := s.Field("arr")
fmt.Println(a.IsSlice())
// Output:
// Output:
// true
}
```
@@ -608,12 +608,12 @@ func main() {
s := structs.New(p1)
n, _ := s.Field("Name")
a, _ := s.Field("arr")
fmt.Println(n.IsTargetType(reflect.String))
fmt.Println(a.IsTargetType(reflect.Slice))
// Output:
// Output:
// true
// true
}
```
```

View File

@@ -549,7 +549,7 @@ func main() {
func IsEmail(email string) bool
```
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/Os9VaFlT33G)</span></b>
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/HVQ5LAe-vFz)</span></b>
```go
import (
@@ -559,13 +559,28 @@ import (
func main() {
result1 := validator.IsEmail("abc@xyz.com")
result2 := validator.IsEmail("a.b@@com")
result2 := validator.IsEmail("user@domain.co")
result3 := validator.IsEmail("test.user@example.org")
result4 := validator.IsEmail("@abc@xyz.com")
result5 := validator.IsEmail("a.b@@com")
result6 := validator.IsEmail("a.b@com")
result7 := validator.IsEmail("test@example")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
fmt.Println(result6)
fmt.Println(result7)
// Output:
// true
// true
// true
// false
// false
// false
// false
}
```
@@ -1552,6 +1567,8 @@ func IsChinaUnionPay(v string) bool
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/yafpdxLiymu)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
@@ -1580,9 +1597,11 @@ func main() {
func IsPassport(passport, country string) bool
```
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/todo)</span></b>
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/dvOiV2BW7Aw)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/validator"
@@ -1617,7 +1636,7 @@ func main() {
func IsChineseHMPassport(hmPassport string) bool
```
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/todo)</span></b>
<b>示例:<span style="float:right;display:inline-block">[运行](https://go.dev/play/p/xKG6spQTcY0)</span></b>
```go
import (
@@ -1645,4 +1664,4 @@ func main() {
// false
// false
}
```
```

View File

@@ -33,6 +33,9 @@ import (
- [ToJson](#ToJson)
- [ToMap](#ToMap)
- [ToPointer](#ToPointer)
- [ToPointers](#ToPointers)
- [FromPointer](#FromPointer)
- [FromPointers](#FromPointers)
- [ToString](#ToString)
- [StructToMap](#StructToMap)
- [MapToSlice](#MapToSlice)
@@ -456,6 +459,108 @@ func main() {
}
```
### <span id="ToPointers">ToPointers</span>
<p>Convert a slice of values to a slice of pointers.</p>
<b>Signature:</b>
```go
func ToPointers[T any](values []T) []*T
```
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/ZUoXd2i5ZkV)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
strs := []string{"a", "b", "c"}
pointerStrs := convertor.ToPointers(strs)
fmt.Println(*pointerStrs[0])
fmt.Println(*pointerStrs[1])
fmt.Println(*pointerStrs[2])
// Output:
// a
// b
// c
}
```
### <span id="FromPointer">FromPointer</span>
<p>Returns the value pointed to by the pointer.</p>
<b>Signature:</b>
```go
func FromPointer[T any](ptr *T) T
```
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/wAp90V7Zu6g)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
str := "abc"
strPtr := &str
result := convertor.FromPointer(strPtr)
fmt.Println(result)
// Output:
// abc
}
```
### <span id="FromPointers">FromPointers</span>
<p>Convert a slice of pointers to a slice of values.</p>
<b>Signature:</b>
```go
func FromPointers[T any](pointers []*T) []T
```
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/qIPsyYtNy3Q)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/convertor"
)
func main() {
strs := []string{"a", "b", "c"}
strPtr := []*string{&strs[0], &strs[1], &strs[2]}
result := convertor.FromPointers(strPtr)
fmt.Println(result[0])
fmt.Println(result[1])
fmt.Println(result[2])
// Output:
// a
// b
// c
}
```
### <span id="ToString">ToString</span>
<p>ToString convert value to string, for number, string, []byte, will convert to string. For other type (slice, map, array, struct) will call json.Marshal</p>
@@ -572,7 +677,6 @@ func main() {
}
```
### <span id="EncodeByte">EncodeByte</span>
<p>Encode data to byte slice.</p>
@@ -638,7 +742,6 @@ func main() {
}
```
### <span id="CopyProperties">CopyProperties</span>
<p>Copies each field from the source struct into the destination struct. Use json.Marshal/Unmarshal, so json tag should be set for fields of dst and src struct.</p>
@@ -748,7 +851,7 @@ func main() {
// Output:
// true
// true
// true
}
```
@@ -781,7 +884,7 @@ func main() {
// Output:
// true
// hello
// hello
}
```
@@ -857,8 +960,6 @@ func main() {
```
### <span id="ToUrlBase64">ToUrlBase64</span>
<p>Convert a value to a string encoded in url Base64. Error data of type "error" will also be encoded, and complex structures will be converted to a JSON formatted string.</p>
@@ -1147,4 +1248,4 @@ func main() {
// Output:
// 9876543210
}
```
```

View File

@@ -1,6 +1,6 @@
# Cryptor
Package cryptor contains some functions for data encryption and decryption. Support base64, md5, hmac, aes, des, rsa.
Package cryptor contains some functions for data encryption and decryption. Support base64, md5, hmac, aes, des, rsa, sm2, sm3, sm4.
<div STYLE="page-break-after: always;"></div>
@@ -76,6 +76,14 @@ import (
- [RsaDecryptOAEP](#RsaDecryptOAEP)
- [RsaSign](#RsaSign)
- [RsaVerifySign](#RsaVerifySign)
- [Sm3](#Sm3)
- [Sm4EcbEncrypt](#Sm4EcbEncrypt)
- [Sm4EcbDecrypt](#Sm4EcbDecrypt)
- [Sm4CbcEncrypt](#Sm4CbcEncrypt)
- [Sm4CbcDecrypt](#Sm4CbcDecrypt)
- [GenerateSm2Key](#GenerateSm2Key)
- [Sm2Encrypt](#Sm2Encrypt)
- [Sm2Decrypt](#Sm2Decrypt)
<div STYLE="page-break-after: always;"></div>
@@ -1831,3 +1839,278 @@ func main() {
}
}
```
### <span id="Sm3">Sm3</span>
<p>Calculate SM3 hash (Chinese National Cryptography SM3 Hash Algorithm). SM3 is a cryptographic hash algorithm published by the Chinese State Cryptography Administration, designed to replace MD5/SHA-1/SHA-2.</p>
<b>Signature:</b>
```go
func Sm3(data []byte) []byte
```
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/zDAQpteAiOc)</span></b>
```go
package main
import (
"encoding/hex"
"fmt"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
data := []byte("hello world")
hash := cryptor.Sm3(data)
fmt.Println(hex.EncodeToString(hash))
// Output:
// 44f0061e69fa6fdfc290c494654a05dc0c053da7e5c52b84ef93a9d67d3fff88
}
```
### <span id="Sm4EcbEncrypt">Sm4EcbEncrypt</span>
<p>Encrypt data using SM4 ECB mode (Chinese National Cryptography SM4 Block Cipher Algorithm). Key length must be 16 bytes.</p>
<b>Signature:</b>
```go
func Sm4EcbEncrypt(data, key []byte) []byte
```
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/l5IQxYuuaED)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
key := []byte("1234567890abcdef") // 16 bytes key
plaintext := []byte("hello world")
encrypted := cryptor.Sm4EcbEncrypt(plaintext, key)
decrypted := cryptor.Sm4EcbDecrypt(encrypted, key)
fmt.Println(string(decrypted))
// Output:
// hello world
}
```
### <span id="Sm4EcbDecrypt">Sm4EcbDecrypt</span>
<p>Decrypt data using SM4 ECB mode. Key length must be 16 bytes.</p>
<b>Signature:</b>
```go
func Sm4EcbDecrypt(encrypted, key []byte) []byte
```
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/l5IQxYuuaED)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
key := []byte("1234567890abcdef")
plaintext := []byte("hello world")
encrypted := cryptor.Sm4EcbEncrypt(plaintext, key)
decrypted := cryptor.Sm4EcbDecrypt(encrypted, key)
fmt.Println(string(decrypted))
// Output:
// hello world
}
```
### <span id="Sm4CbcEncrypt">Sm4CbcEncrypt</span>
<p>Encrypt data using SM4 CBC mode. Key length must be 16 bytes. The returned ciphertext contains IV (first 16 bytes).</p>
<b>Signature:</b>
```go
func Sm4CbcEncrypt(data, key []byte) []byte
```
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/65Q6iYhLRTa)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
key := []byte("1234567890abcdef")
plaintext := []byte("hello world")
encrypted := cryptor.Sm4CbcEncrypt(plaintext, key)
decrypted := cryptor.Sm4CbcDecrypt(encrypted, key)
fmt.Println(string(decrypted))
// Output:
// hello world
}
```
### <span id="Sm4CbcDecrypt">Sm4CbcDecrypt</span>
<p>Decrypt data using SM4 CBC mode. Key length must be 16 bytes. The ciphertext should contain IV (first 16 bytes).</p>
<b>Signature:</b>
```go
func Sm4CbcDecrypt(encrypted, key []byte) []byte
```
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/65Q6iYhLRTa)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
key := []byte("1234567890abcdef")
plaintext := []byte("hello world")
encrypted := cryptor.Sm4CbcEncrypt(plaintext, key)
decrypted := cryptor.Sm4CbcDecrypt(encrypted, key)
fmt.Println(string(decrypted))
// Output:
// hello world
}
```
### <span id="GenerateSm2Key">GenerateSm2Key</span>
<p>Generate SM2 key pair (Chinese National Cryptography SM2 Elliptic Curve Public Key Algorithm). SM2 is an asymmetric encryption algorithm based on elliptic curve cryptography.</p>
<b>Signature:</b>
```go
func GenerateSm2Key() (*Sm2PrivateKey, error)
```
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/bKYMqRLvIx3)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
privateKey, err := cryptor.GenerateSm2Key()
if err != nil {
return
}
plaintext := []byte("hello world")
ciphertext, _ := cryptor.Sm2Encrypt(&privateKey.PublicKey, plaintext)
decrypted, _ := cryptor.Sm2Decrypt(privateKey, ciphertext)
fmt.Println(string(decrypted))
// Output:
// hello world
}
```
### <span id="Sm2Encrypt">Sm2Encrypt</span>
<p>Encrypt data using SM2 public key. The returned ciphertext format is: C1(65 bytes) || C3(32 bytes) || C2(plaintext length).</p>
<b>Signature:</b>
```go
func Sm2Encrypt(pub *Sm2PublicKey, plaintext []byte) ([]byte, error)
```
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/bKYMqRLvIx3)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
privateKey, _ := cryptor.GenerateSm2Key()
plaintext := []byte("hello world")
ciphertext, _ := cryptor.Sm2Encrypt(&privateKey.PublicKey, plaintext)
decrypted, _ := cryptor.Sm2Decrypt(privateKey, ciphertext)
fmt.Println(string(decrypted))
// Output:
// hello world
}
```
### <span id="Sm2Decrypt">Sm2Decrypt</span>
<p>Decrypt data using SM2 private key. The ciphertext format should be: C1(65 bytes) || C3(32 bytes) || C2(plaintext length).</p>
<b>Signature:</b>
```go
func Sm2Decrypt(priv *Sm2PrivateKey, ciphertext []byte) ([]byte, error)
```
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/bKYMqRLvIx3)</span></b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/cryptor"
)
func main() {
privateKey, _ := cryptor.GenerateSm2Key()
plaintext := []byte("hello world")
ciphertext, _ := cryptor.Sm2Encrypt(&privateKey.PublicKey, plaintext)
decrypted, _ := cryptor.Sm2Decrypt(privateKey, ciphertext)
fmt.Println(string(decrypted))
// Output:
// hello world
}
```

View File

@@ -6,7 +6,7 @@ Package enum provides a simple enum implementation.
## Source:
- [https://github.com/duke-git/lancet/blob/main/enum/enum.go](https://github.com/duke-git/lancet/blob/main/enum/enum.go)
- [https://github.com/duke-git/lancet/blob/main/enum/enum.go](https://github.com/duke-git/lancet/blob/main/enum/enum.go)
<div STYLE="page-break-after: always;"></div>
@@ -55,7 +55,7 @@ import (
func NewItem[T comparable](value T, name string) *Item[T]
```
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/todo)</span></b>
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/8qNsLw01HD5)</span></b>
```go
package main
@@ -96,7 +96,7 @@ func main() {
func NewItemsFromPairs[T comparable](pairs ...Pair[T]) []*Item[T]
```
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/todo)</span></b>
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/xKnoGa7gnev)</span></b>
```go
package main
@@ -139,7 +139,7 @@ func main() {
func (it *Item[T]) Value() T
```
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/todo)</span></b>
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/xKnoGa7gnev)</span></b>
```go
package main
@@ -182,7 +182,7 @@ func main() {
func (it *Item[T]) Name() string
```
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/todo)</span></b>
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/xKnoGa7gnev)</span></b>
```go
package main
@@ -225,7 +225,7 @@ func main() {
func (it *Item[T]) Valid(checker ...func(T) bool) bool
```
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/todo)</span></b>
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/pA3lYY2VSm3)</span></b>
```go
package main
@@ -267,7 +267,7 @@ func (it *Item[T]) MarshalJSON() ([]byte, error)
func (it *Item[T]) UnmarshalJSON(data []byte) error
```
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/todo)</span></b>
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/zIZEdAnneB5)</span></b>
```go
package main
@@ -290,7 +290,7 @@ func main() {
data, _ := item.MarshalJSON()
fmt.Println(string(data))
var unmarshaledItem Item[Status]
var unmarshaledItem enum.Item[Status]
_ = unmarshaledItem.UnmarshalJSON(data)
fmt.Println(unmarshaledItem.Name(), unmarshaledItem.Value())
@@ -310,7 +310,7 @@ func main() {
func NewRegistry[T comparable](items ...*Item[T]) *Registry[T]
```
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/todo)</span></b>
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/ABEXsYfJKMo)</span></b>
```go
package main
@@ -359,7 +359,7 @@ func main() {
func (r *Registry[T]) Add(items ...*Item[T])
```
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/todo)</span></b>
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/ABEXsYfJKMo)</span></b>
```go
package main
@@ -408,7 +408,7 @@ func main() {
func (r *Registry[T]) Remove(value T) bool
```
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/todo)</span></b>
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/dSG84wQ3TuC)</span></b>
```go
package main
@@ -454,7 +454,7 @@ func main() {
func (r *Registry[T]) Update(value T, newName string) bool
```
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/todo)</span></b>
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/Ol0moT1J9Xl)</span></b>
```go
package main
@@ -500,7 +500,7 @@ func main() {
func (r *Registry[T]) GetByValue(value T) (*Item[T], bool)
```
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/todo)</span></b>
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/niJ1U2KlE_m)</span></b>
```go
package main
@@ -520,9 +520,9 @@ const (
func main() {
registry := enum.NewRegistry[Status]()
item1 := enum.NewItem(Active, "Active")
item := enum.NewItem(Active, "Active")
registry.Add(item1, item2)
registry.Add(item)
if item, found := registry.GetByValue(Active); found {
fmt.Println("Found name by value:", item.Name())
@@ -543,7 +543,7 @@ func main() {
func (r *Registry[T]) GetByName(name string) (*Item[T], bool)
```
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/todo)</span></b>
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/49ie_gpqH0m)</span></b>
```go
package main
@@ -586,7 +586,7 @@ func main() {
func (r *Registry[T]) Items() []*Item[T]
```
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/todo)</span></b>
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/lAJFAradbvQ)</span></b>
```go
package main
@@ -631,7 +631,7 @@ func main() {
func (r *Registry[T]) Contains(value T) bool
```
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/todo)</span></b>
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/_T-lPYkZn2j)</span></b>
```go
package main
@@ -673,7 +673,7 @@ func main() {
func (r *Registry[T]) Size() int
```
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/todo)</span></b>
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/TeDArWhlQe2)</span></b>
```go
package main
@@ -721,7 +721,7 @@ func main() {
func (r *Registry[T]) Range(fn func(*Item[T]) bool)
```
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/todo)</span></b>
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/GPsZbQbefWN)</span></b>
```go
package main
@@ -745,7 +745,7 @@ func main() {
item2 := enum.NewItem(Inactive, "Inactive")
registry.Add(item1, item2)
registry.Range(func(item *Item[Status]) bool {
registry.Range(func(item *enum.Item[Status]) bool {
fmt.Println(item.Name(), item.Value())
return true // continue iteration
})
@@ -766,7 +766,7 @@ func main() {
func (r *Registry[T]) SortedItems(less func(*Item[T], *Item[T]) bool) []*Item[T]
```
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/todo)</span></b>
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/tN9RE_m_WEI)</span></b>
```go
package main
@@ -790,8 +790,8 @@ func main() {
item2 := enum.NewItem(Active, "Active")
registry.Add(item1, item2)
for _, item := range registry.SortedItems(func(i1, i2 *Item[Status]) bool {
return i1.value < i2.value
for _, item := range registry.SortedItems(func(i1, i2 *enum.Item[Status]) bool {
return i1.Value() < i2.Value()
}) {
fmt.Println(item.Name(), item.Value())
}
@@ -812,7 +812,7 @@ func main() {
func (r *Registry[T]) Filter(predicate func(*Item[T]) bool) []*Item[T]
```
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/todo)</span></b>
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/uTUpTdcyoCU)</span></b>
```go
package main
@@ -836,7 +836,7 @@ func main() {
item2 := enum.NewItem(Inactive, "Inactive")
registry.Add(item1, item2)
activeItems := registry.Filter(func(item *Item[Status]) bool {
activeItems := registry.Filter(func(item *enum.Item[Status]) bool {
return item.Value() == Active
})
@@ -847,4 +847,4 @@ func main() {
// Output:
// Active 1
}
```
```

View File

@@ -81,7 +81,6 @@ import (
- [FindValuesBy](#FindValuesBy)
- [ToMarkdownTable](#ToMarkdownTable)
<div STYLE="page-break-after: always;"></div>
## Documentation
@@ -2376,8 +2375,8 @@ func main() {
编辑
func ToMarkdownTable(data []map[string]interface{}, headerMap map[string]string, columnOrder []string) string
```
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/todo)</span></b>
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/w_pSLfeyEB5)</span></b>
```go
package main
@@ -2424,10 +2423,10 @@ func main() {
result = maputil.ToMarkdownTable(data, nil, columnOrder)
fmt.Println(result)
// 输出:
// output:
// |salary|name|
// |---|---|
// |50000|Alice|
// |60000|Bob|
}
```
```

View File

@@ -70,7 +70,7 @@ func main() {
}
p1 := &People{Name: "11"}
s := structs.New(p1)
fmt.Println(s.ToMap())
// Output:
@@ -516,7 +516,7 @@ func main() {
func (s *Struct) TypeName() string
```
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/todo)</span></b>
<b>Example:<span style="float:right;display:inline-block;">[Run](https://go.dev/play/p/SWLWd0XBaBb)</span></b>
```go
package main
@@ -533,11 +533,11 @@ func main() {
}
p := &Parent{Age: 11}
s := structs.New(p1)
s := structs.New(p)
fmt.Println(s.TypeName())
// Output:
// Output:
// Parent
}
```
@@ -610,12 +610,12 @@ func main() {
s := structs.New(p1)
n, _ := s.Field("Name")
a, _ := s.Field("arr")
fmt.Println(n.IsTargetType(reflect.String))
fmt.Println(a.IsTargetType(reflect.Slice))
// Output:
// Output:
// true
// true
}
```
```

View File

@@ -551,7 +551,7 @@ func main() {
func IsEmail(email string) bool
```
<b>Example:<span style="float:right;display:inline-block">[Run](https://go.dev/play/p/Os9VaFlT33G)</span></b>
<b>Example:<span style="float:right;display:inline-block">[Run](https://go.dev/play/p/HVQ5LAe-vFz)</span></b>
```go
import (
@@ -561,13 +561,28 @@ import (
func main() {
result1 := validator.IsEmail("abc@xyz.com")
result2 := validator.IsEmail("a.b@@com")
result2 := validator.IsEmail("user@domain.co")
result3 := validator.IsEmail("test.user@example.org")
result4 := validator.IsEmail("@abc@xyz.com")
result5 := validator.IsEmail("a.b@@com")
result6 := validator.IsEmail("a.b@com")
result7 := validator.IsEmail("test@example")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
fmt.Println(result6)
fmt.Println(result7)
// Output:
// true
// true
// true
// false
// false
// false
// false
}
```
@@ -1582,7 +1597,7 @@ func main() {
func IsPassport(passport, country string) bool
```
<b>Example:<span style="float:right;display:inline-block">[Run](https://go.dev/play/p/todo)</span></b>
<b>Example:<span style="float:right;display:inline-block">[Run](https://go.dev/play/p/dvOiV2BW7Aw)</span></b>
```go
import (
@@ -1619,7 +1634,7 @@ func main() {
func IsChineseHMPassport(hmPassport string) bool
```
<b>Example:<span style="float:right;display:inline-block">[Run](https://go.dev/play/p/todo)</span></b>
<b>Example:<span style="float:right;display:inline-block">[Run](https://go.dev/play/p/xKG6spQTcY0)</span></b>
```go
import (
@@ -1647,4 +1662,4 @@ func main() {
// false
// false
}
```
```

View File

@@ -27,6 +27,7 @@ type Item[T comparable] struct {
}
// NewItem creates a new enum item.
// Play: https://go.dev/play/p/8qNsLw01HD5
func NewItem[T comparable](value T, name string) *Item[T] {
return &Item[T]{value: value, name: name}
}
@@ -38,6 +39,7 @@ type Pair[T comparable] struct {
}
// NewItemsFromPairs creates enum items from a slice of Pair structs.
// Play: https://go.dev/play/p/xKnoGa7gnev
func NewItemsFromPairs[T comparable](pairs ...Pair[T]) []*Item[T] {
if len(pairs) == 0 {
return []*Item[T]{}
@@ -52,11 +54,13 @@ func NewItemsFromPairs[T comparable](pairs ...Pair[T]) []*Item[T] {
}
// Value returns the value of the enum item.
// Play: https://go.dev/play/p/xKnoGa7gnev
func (it *Item[T]) Value() T {
return it.value
}
// Name returns the name of the enum item.
// Play: https://go.dev/play/p/xKnoGa7gnev
func (it *Item[T]) Name() string {
return it.name
}
@@ -67,6 +71,7 @@ func (it *Item[T]) String() string {
}
// Valid checks if the enum item is valid. If a custom check function is provided, it will be used to validate the value.
// Play: https://go.dev/play/p/pA3lYY2VSm3
func (it *Item[T]) Valid(checker ...func(T) bool) bool {
if len(checker) > 0 {
return checker[0](it.value) && it.name != ""
@@ -76,6 +81,7 @@ func (it *Item[T]) Valid(checker ...func(T) bool) bool {
}
// MarshalJSON implements the json.Marshaler interface.
// Play: https://go.dev/play/p/zIZEdAnneB5
func (it *Item[T]) MarshalJSON() ([]byte, error) {
return json.Marshal(map[string]any{
"value": it.value,
@@ -84,6 +90,7 @@ func (it *Item[T]) MarshalJSON() ([]byte, error) {
}
// UnmarshalJSON implements the json.Unmarshaler interface.
// Play: https://go.dev/play/p/zIZEdAnneB5
func (it *Item[T]) UnmarshalJSON(data []byte) error {
type alias struct {
Value any `json:"value"`
@@ -156,6 +163,7 @@ type Registry[T comparable] struct {
}
// NewRegistry creates a new enum registry.
// Play: https://go.dev/play/p/ABEXsYfJKMo
func NewRegistry[T comparable](items ...*Item[T]) *Registry[T] {
r := &Registry[T]{
values: make(map[T]*Item[T]),
@@ -169,6 +177,7 @@ func NewRegistry[T comparable](items ...*Item[T]) *Registry[T] {
}
// Add adds enum items to the registry.
// Play: https://go.dev/play/p/ABEXsYfJKMo
func (r *Registry[T]) Add(items ...*Item[T]) {
r.mu.Lock()
defer r.mu.Unlock()
@@ -188,6 +197,7 @@ func (r *Registry[T]) Add(items ...*Item[T]) {
}
// Remove removes an enum item from the registry by its value.
// Play: https://go.dev/play/p/dSG84wQ3TuC
func (r *Registry[T]) Remove(value T) bool {
r.mu.Lock()
defer r.mu.Unlock()
@@ -207,6 +217,7 @@ func (r *Registry[T]) Remove(value T) bool {
}
// Update updates the name of an enum item in the registry by its value.
// Play: https://go.dev/play/p/Ol0moT1J9Xl
func (r *Registry[T]) Update(value T, newName string) bool {
r.mu.Lock()
defer r.mu.Unlock()
@@ -221,6 +232,7 @@ func (r *Registry[T]) Update(value T, newName string) bool {
}
// GetByValue retrieves an enum item by its value.
// Play: https://go.dev/play/p/niJ1U2KlE_m
func (r *Registry[T]) GetByValue(value T) (*Item[T], bool) {
r.mu.RLock()
defer r.mu.RUnlock()
@@ -230,6 +242,7 @@ func (r *Registry[T]) GetByValue(value T) (*Item[T], bool) {
}
// GetByName retrieves an enum item by its name.
// Play: https://go.dev/play/p/49ie_gpqH0m
func (r *Registry[T]) GetByName(name string) (*Item[T], bool) {
r.mu.RLock()
defer r.mu.RUnlock()
@@ -239,6 +252,7 @@ func (r *Registry[T]) GetByName(name string) (*Item[T], bool) {
}
// Items returns a slice of all enum items in the registry.
// Play: https://go.dev/play/p/lAJFAradbvQ
func (r *Registry[T]) Items() []*Item[T] {
r.mu.RLock()
defer r.mu.RUnlock()
@@ -249,12 +263,14 @@ func (r *Registry[T]) Items() []*Item[T] {
}
// Contains checks if an enum item with the given value exists in the registry.
// Play: https://go.dev/play/p/_T-lPYkZn2j
func (r *Registry[T]) Contains(value T) bool {
_, ok := r.GetByValue(value)
return ok
}
// Size returns the number of enum items in the registry.
// Play: https://go.dev/play/p/TeDArWhlQe2
func (r *Registry[T]) Size() int {
r.mu.RLock()
defer r.mu.RUnlock()
@@ -263,6 +279,7 @@ func (r *Registry[T]) Size() int {
}
// Range iterates over all enum items in the registry and applies the given function.
// Play: https://go.dev/play/p/GPsZbQbefWN
func (r *Registry[T]) Range(fn func(*Item[T]) bool) {
r.mu.RLock()
defer r.mu.RUnlock()
@@ -275,6 +292,7 @@ func (r *Registry[T]) Range(fn func(*Item[T]) bool) {
}
// SortedItems returns a slice of all enum items sorted by the given less function.
// Play: https://go.dev/play/p/tN9RE_m_WEI
func (r *Registry[T]) SortedItems(less func(*Item[T], *Item[T]) bool) []*Item[T] {
items := r.Items()
sort.Slice(items, func(i, j int) bool {
@@ -284,6 +302,7 @@ func (r *Registry[T]) SortedItems(less func(*Item[T], *Item[T]) bool) []*Item[T]
}
// Filter returns a slice of enum items that satisfy the given predicate function.
// Play: https://go.dev/play/p/uTUpTdcyoCU
func (r *Registry[T]) Filter(predicate func(*Item[T]) bool) []*Item[T] {
r.mu.RLock()
defer r.mu.RUnlock()

View File

@@ -683,7 +683,7 @@ func FindValuesBy[K comparable, V any](m map[K]V, predicate func(key K, value V)
}
// ToMarkdownTable converts a slice of maps to a Markdown table.
// Play: ttps://go.dev/play/p/todo
// Play: ttps://go.dev/play/p/w_pSLfeyEB5
func ToMarkdownTable(data []map[string]interface{}, headerMap map[string]string, columnOrder []string) string {
if len(data) == 0 {
return "| |\n|---|\n"

View File

@@ -130,7 +130,7 @@ func ToMap(v any) (map[string]any, error) {
}
// TypeName return struct type name
// Play: https://go.dev/play/p/todo
// Play: https://go.dev/play/p/SWLWd0XBaBb
func (s *Struct) TypeName() string {
return s.rtype.Name()
}

View File

@@ -8,7 +8,6 @@ import (
"encoding/json"
"fmt"
"net"
"net/mail"
"net/url"
"reflect"
"regexp"
@@ -26,6 +25,7 @@ var (
intStrMatcher *regexp.Regexp = regexp.MustCompile(`^[\+-]?\d+$`)
// dnsMatcher *regexp.Regexp = regexp.MustCompile(`^(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$`)
dnsMatcher *regexp.Regexp = regexp.MustCompile(`^(?:[a-zA-Z0-9](?:[a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)*(?:xn--[a-zA-Z0-9\-]{1,59}|[a-zA-Z0-9](?:[a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?)$`)
emailMatcher *regexp.Regexp = regexp.MustCompile(`^[a-z0-9._%+\-]+@[a-z0-9.\-]+\.[a-z]{2,}$`)
chineseMobileMatcher *regexp.Regexp = regexp.MustCompile(`^1(?:3\d|4[4-9]|5[0-35-9]|6[67]|7[013-8]|8\d|9\d)\d{8}$`)
chineseIdMatcher *regexp.Regexp = regexp.MustCompile(`([1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx])|([1-9]\d{5}\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{2}[0-9Xx])`)
chineseMatcher *regexp.Regexp = regexp.MustCompile("[\u4e00-\u9fa5]")
@@ -321,10 +321,9 @@ func IsDns(dns string) bool {
}
// IsEmail check if the string is a email address.
// Play: https://go.dev/play/p/Os9VaFlT33G
// Play: https://go.dev/play/p/HVQ5LAe-vFz
func IsEmail(email string) bool {
_, err := mail.ParseAddress(email)
return err == nil
return emailMatcher.MatchString(strings.ToLower(email))
}
// IsChineseMobile check if the string is chinese mobile number.
@@ -634,7 +633,7 @@ func IsChinaUnionPay(cardNo string) bool {
// IsPassport checks if the passport number is valid for a given country.
// country is a two-letter country code (ISO 3166-1 alpha-2).
// Play: todo
// Play: https://go.dev/play/p/dvOiV2BW7Aw
func IsPassport(passport, country string) bool {
if matcher, ok := passportMatcher[country]; ok {
return matcher.MatchString(passport)
@@ -645,7 +644,7 @@ func IsPassport(passport, country string) bool {
// IsChineseHMPassport checks if the string is a valid Chinese Hong Kong and Macau Travel Permit number.
// Chinese Hong Kong and Macau Travel Permit format: C or M + 8 digits (e.g., C12345678, M12345678).
// Play: https://go.dev/play/p/TODO
// Play: https://go.dev/play/p/xKG6spQTcY0
func IsChineseHMPassport(hmPassport string) bool {
return chineseHMPassportMatcher.MatchString(hmPassport)
}

View File

@@ -494,8 +494,12 @@ func TestIsEmail(t *testing.T) {
assert := internal.NewAssert(t, "TestIsEmail")
assert.Equal(true, IsEmail("abc@xyz.com"))
assert.Equal(true, IsEmail("user@domain.co"))
assert.Equal(true, IsEmail("test.user@example.org"))
assert.Equal(false, IsEmail("@abc@xyz.com"))
assert.Equal(false, IsEmail("a.b@@com"))
assert.Equal(false, IsEmail("a.b@com"))
assert.Equal(false, IsEmail("test@example"))
}
func TestContainChinese(t *testing.T) {