Skip to content

Commit 0d53670

Browse files
committed
first commit
0 parents  commit 0d53670

File tree

18 files changed

+2413
-0
lines changed

18 files changed

+2413
-0
lines changed

.github/workflows/lint.yaml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
name: golangci-lint
2+
on:
3+
push:
4+
branches:
5+
- main
6+
pull_request:
7+
8+
permissions:
9+
contents: read
10+
11+
jobs:
12+
golangci:
13+
name: lint
14+
runs-on: ubuntu-latest
15+
steps:
16+
- uses: actions/checkout@v5
17+
- uses: actions/setup-go@v6
18+
with:
19+
go-version: stable
20+
- name: golangci-lint
21+
uses: golangci/golangci-lint-action@v8
22+
with:
23+
version: v2.5.0

.github/workflows/test.yaml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
name: Tests
2+
on:
3+
push:
4+
branches:
5+
- main
6+
pull_request:
7+
8+
permissions:
9+
contents: read
10+
11+
jobs:
12+
test:
13+
name: test
14+
runs-on: ubuntu-latest
15+
steps:
16+
- uses: actions/checkout@v5
17+
- uses: actions/setup-go@v6
18+
with:
19+
go-version-file: go.mod
20+
- name: Run tests
21+
run: go test -v -race ./...

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
bin/*

.golangci.yaml

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
version: "2"
2+
3+
run:
4+
go: "1.25"
5+
concurrency: 12
6+
7+
linters:
8+
default: none
9+
enable:
10+
- asciicheck
11+
- errcheck
12+
- govet
13+
- ineffassign
14+
- misspell
15+
- nakedret
16+
- nolintlint
17+
- prealloc
18+
- reassign
19+
- staticcheck
20+
- unconvert
21+
- unused
22+
- whitespace
23+
- bidichk
24+
- bodyclose
25+
- containedctx
26+
- contextcheck
27+
- copyloopvar
28+
- embeddedstructfieldcheck
29+
- errchkjson
30+
- errorlint
31+
- exptostd
32+
- fatcontext
33+
- forcetypeassert
34+
- funcorder
35+
- gocheckcompilerdirectives
36+
- gocritic
37+
- gomoddirectives
38+
- gosec
39+
- gosmopolitan
40+
- grouper
41+
- importas
42+
- inamedparam
43+
- intrange
44+
- loggercheck
45+
- mirror
46+
- musttag
47+
- perfsprint
48+
- predeclared
49+
- tagalign
50+
- tagliatelle
51+
- testifylint
52+
- thelper
53+
- tparallel
54+
- unparam
55+
- usestdlibvars
56+
- usetesting
57+
- varnamelen
58+
- wastedassign
59+
60+
settings:
61+
staticcheck:
62+
checks:
63+
- "all"
64+
- "-S1002"
65+
- "-ST1000"
66+
varnamelen:
67+
ignore-decls:
68+
- w http.ResponseWriter
69+
70+
exclusions:
71+
rules:
72+
- path: _test\.go$
73+
linters:
74+
- errorlint
75+
- forcetypeassert
76+
- perfsprint
77+
- errcheck
78+
- gosec
79+
- varnamelen
80+
81+
- path: _test\.go$
82+
linters:
83+
- staticcheck
84+
text: "SA5011"
85+
86+
formatters:
87+
enable:
88+
- gofmt
89+
90+
settings:
91+
gofmt:
92+
# Simplify code: gofmt with `-s` option.
93+
# Default: true
94+
simplify: true
95+
# Apply the rewrite rules to the source before reformatting.
96+
# https://pkg.go.dev/cmd/gofmt
97+
# Default: []
98+
rewrite-rules:
99+
- pattern: "interface{}"
100+
replacement: "any"
101+
- pattern: "a[b:len(a)]"
102+
replacement: "a[b:]"

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2025 Aykhan Shahsuvarov
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
# go-utils
2+
3+
A collection of generic utility functions for Go projects.
4+
5+
## Installation
6+
7+
```bash
8+
go get github.com/aykhans/go-utils
9+
```
10+
11+
## Packages
12+
13+
### common
14+
15+
Generic type conversion utilities.
16+
17+
**ToPtr** - Convert any value to a pointer
18+
```go
19+
import "github.com/aykhans/go-utils/common"
20+
21+
num := 42
22+
ptr := common.ToPtr(num) // *int
23+
```
24+
25+
### parser
26+
27+
String parsing utilities with generic type support.
28+
29+
**ParseString** - Parse string to various types
30+
```go
31+
import "github.com/aykhans/go-utils/parser"
32+
33+
num, err := parser.ParseString[int]("42")
34+
duration, err := parser.ParseString[time.Duration]("5s")
35+
isValid, err := parser.ParseString[bool]("true")
36+
```
37+
38+
**ParseStringOrZero** - Parse string or return zero value on error
39+
```go
40+
num := parser.ParseStringOrZero[int]("invalid") // returns 0
41+
```
42+
43+
**ParseStringWithDefault** - Parse string with default value fallback
44+
```go
45+
num, err := parser.ParseStringWithDefault("invalid", 10) // returns 10, error
46+
```
47+
48+
**ParseStringOrDefault** - Parse string or return default value without error
49+
```go
50+
num := parser.ParseStringOrDefault("invalid", 10) // returns 10
51+
```
52+
53+
Supported types: `string`, `int`, `int8`, `int16`, `int32`, `int64`, `uint`, `uint8`, `uint16`, `uint32`, `uint64`, `float64`, `bool`, `time.Duration`, `url.URL`
54+
55+
### slice
56+
57+
Slice manipulation utilities.
58+
59+
**Cycle** - Create an infinite cycler through items
60+
```go
61+
import "github.com/aykhans/go-utils/slice"
62+
63+
next := slice.Cycle(1, 2, 3)
64+
fmt.Println(next()) // 1
65+
fmt.Println(next()) // 2
66+
fmt.Println(next()) // 3
67+
fmt.Println(next()) // 1
68+
```
69+
70+
**RandomCycle** - Cycle through items with randomization
71+
```go
72+
next := slice.RandomCycle(nil, "a", "b", "c")
73+
// Cycles through all items, then starts from a random position
74+
```
75+
76+
### maps
77+
78+
Map utility functions.
79+
80+
**InitMap** - Initialize a map pointer if nil
81+
```go
82+
import "github.com/aykhans/go-utils/maps"
83+
84+
var m map[string]int
85+
maps.InitMap(&m)
86+
m["key"] = 42 // safe to use
87+
```
88+
89+
**UpdateMap** - Merge entries from one map into another
90+
```go
91+
old := map[string]int{"a": 1, "b": 2}
92+
new := map[string]int{"b": 3, "c": 4}
93+
maps.UpdateMap(&old, new)
94+
// old is now: {"a": 1, "b": 3, "c": 4}
95+
```
96+
97+
### errors
98+
99+
Advanced error handling utilities.
100+
101+
**HandleError** - Process errors with custom matchers
102+
```go
103+
import "github.com/aykhans/go-utils/errors"
104+
105+
handled, result := errors.HandleError(err,
106+
errors.OnSentinelError(io.EOF, func(e error) error {
107+
return nil // EOF is expected, ignore it
108+
}),
109+
errors.OnCustomError(func(e *CustomError) error {
110+
return fmt.Errorf("custom error: %w", e)
111+
}),
112+
)
113+
```
114+
115+
**HandleErrorOrDie** - Handle errors or panic if unhandled
116+
```go
117+
result := errors.HandleErrorOrDie(err,
118+
errors.OnSentinelError(context.Canceled, func(e error) error {
119+
return fmt.Errorf("operation canceled")
120+
}),
121+
) // Panics if err doesn't match any handler
122+
```
123+
124+
**OnSentinelError** - Create matcher for sentinel errors (like `io.EOF`)
125+
```go
126+
matcher := errors.OnSentinelError(io.EOF, func(e error) error {
127+
log.Println("reached end of file")
128+
return nil
129+
})
130+
```
131+
132+
**OnCustomError** - Create matcher for custom error types
133+
```go
134+
type ValidationError struct {
135+
Field string
136+
Msg string
137+
}
138+
139+
matcher := errors.OnCustomError(func(e *ValidationError) error {
140+
log.Printf("validation failed on field %s", e.Field)
141+
return fmt.Errorf("invalid input: %w", e)
142+
})
143+
```
144+
145+
## Requirements
146+
147+
- Go 1.25.0 or higher

Taskfile.yaml

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# https://taskfile.dev
2+
version: "3"
3+
4+
vars:
5+
BIN_DIR: ./bin
6+
GOLANGCI_LINT_VERSION: v2.5.0
7+
8+
tasks:
9+
ftl:
10+
cmds:
11+
- task: fmt
12+
- task: tidy
13+
- task: lint
14+
15+
tidy: go mod tidy {{.CLI_ARGS}}
16+
17+
test: go test ./... {{.CLI_ARGS}}
18+
19+
fmt:
20+
desc: Run linters
21+
deps:
22+
- install-golangci-lint
23+
cmds:
24+
- "{{.BIN_DIR}}/golangci-lint-{{.GOLANGCI_LINT_VERSION}} fmt"
25+
26+
lint:
27+
desc: Run linters
28+
deps:
29+
- install-golangci-lint
30+
cmds:
31+
- "{{.BIN_DIR}}/golangci-lint-{{.GOLANGCI_LINT_VERSION}} run"
32+
33+
install-golangci-lint:
34+
desc: Install golangci-lint
35+
status:
36+
- test -f {{.BIN_DIR}}/golangci-lint-{{.GOLANGCI_LINT_VERSION}}
37+
cmds:
38+
- mkdir -p {{.BIN_DIR}}
39+
- rm -f {{.BIN_DIR}}/golangci-lint-{{.GOLANGCI_LINT_VERSION}}
40+
- curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b {{.BIN_DIR}} {{.GOLANGCI_LINT_VERSION}}
41+
- mv {{.BIN_DIR}}/golangci-lint {{.BIN_DIR}}/golangci-lint-{{.GOLANGCI_LINT_VERSION}}

common/convert.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package common
2+
3+
func ToPtr[T any](value T) *T {
4+
return &value
5+
}

0 commit comments

Comments
 (0)