Skip to content

Commit

Permalink
General maintenance from go1.21 & 1.22 changes (#47)
Browse files Browse the repository at this point in the history
  • Loading branch information
Dean Karn authored Feb 14, 2024
1 parent 67dfc10 commit d5715da
Show file tree
Hide file tree
Showing 15 changed files with 428 additions and 158 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,6 @@ jobs:
with:
go-version: stable
- name: golangci-lint
uses: golangci/golangci-lint-action@v3
uses: golangci/golangci-lint-action@v4
with:
version: latest
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@

# Output of the go coverage tool, specifically when used with LiteIDE
*.out

.idea
18 changes: 17 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [5.28.0] - 2024-02-13
### Added
- Additionally supported types, cast to `sql.Valuer` supported types.

### Changed
- Option scan to take advantage of new `sql.Null` and `reflect.TypeFor` for go1.22+.
- `BytesToString` & `StringToBytes` to use `unsafe.String` & `unsafe.Slice` for go1.21+.

### Deprecated
- `mathext.Min` & `mathext.Max` in favour of std lib min & max.

### Fixed
- Some documentation typos.

## [5.27.0] - 2024-01-29
### Changed
- `sliceext.Retain` & `sliceext.Filter` to not shuffle data in the underlying slice array but create new slice referencing the data instead. In practice, it can cause unexpected behaviour and users expectations not met when the same data is also referenced elsewhere. If anyone still requires a `shuffle` implementation for efficiency I'd be happy to add a separate function for that as well.
Expand Down Expand Up @@ -102,7 +116,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- Added `timext.NanoTime` for fast low level monotonic time with nanosecond precision.

[Unreleased]: https://github.com/go-playground/pkg/compare/v5.26.0...HEAD
[Unreleased]: https://github.com/go-playground/pkg/compare/v5.28.0...HEAD
[5.28.0]: https://github.com/go-playground/pkg/compare/v5.27.0..v5.28.0
[5.27.0]: https://github.com/go-playground/pkg/compare/v5.26.0..v5.27.0
[5.26.0]: https://github.com/go-playground/pkg/compare/v5.25.0..v5.26.0
[5.25.0]: https://github.com/go-playground/pkg/compare/v5.24.0..v5.25.0
[5.24.0]: https://github.com/go-playground/pkg/compare/v5.23.0..v5.24.0
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# pkg

![Project status](https://img.shields.io/badge/version-5.27.0-green.svg)
![Project status](https://img.shields.io/badge/version-5.28.0-green.svg)
[![Lint & Test](https://github.com/go-playground/pkg/actions/workflows/go.yml/badge.svg)](https://github.com/go-playground/pkg/actions/workflows/go.yml)
[![Coverage Status](https://coveralls.io/repos/github/go-playground/pkg/badge.svg?branch=master)](https://coveralls.io/github/go-playground/pkg?branch=master)
[![GoDoc](https://godoc.org/github.com/go-playground/pkg?status.svg)](https://pkg.go.dev/mod/github.com/go-playground/pkg/v5)
Expand Down
7 changes: 4 additions & 3 deletions math/max.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
//go:build go1.18
// +build go1.18
//go:build go1.18 && !go1.21
// +build go1.18,!go1.21

package mathext

import (
constraintsext "github.com/go-playground/pkg/v5/constraints"
"math"

constraintsext "github.com/go-playground/pkg/v5/constraints"
)

// Max returns the larger value.
Expand Down
16 changes: 16 additions & 0 deletions math/max_go121.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//go:build go1.21

package mathext

import (
constraintsext "github.com/go-playground/pkg/v5/constraints"
)

// Max returns the larger value.
//
// NOTE: this function does not check for difference in floats of 0/zero vs -0/negative zero using Signbit.
//
// Deprecated: use the new std library `max` instead.
func Max[N constraintsext.Number](x, y N) N {
return max(x, y)
}
7 changes: 4 additions & 3 deletions math/min.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
//go:build go1.18
// +build go1.18
//go:build go1.18 && !go1.21
// +build go1.18,!go1.21

package mathext

import (
constraintsext "github.com/go-playground/pkg/v5/constraints"
"math"

constraintsext "github.com/go-playground/pkg/v5/constraints"
)

// Min returns the smaller value.
Expand Down
16 changes: 16 additions & 0 deletions math/min_go121.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//go:build go1.21

package mathext

import (
constraintsext "github.com/go-playground/pkg/v5/constraints"
)

// Min returns the smaller value.
//
// NOTE: this function does not check for difference in floats of 0/zero vs -0/negative zero using Signbit.
//
// Deprecated: use the new std library `max` instead.
func Min[N constraintsext.Number](x, y N) N {
return min(x, y)
}
6 changes: 3 additions & 3 deletions net/http/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ func AcceptedLanguages(r *http.Request) (languages []string) {
return
}

// Attachment is a helper method for returning an attachement file
// Attachment is a helper method for returning an attachment file
// to be downloaded, if you with to open inline see function Inline
func Attachment(w http.ResponseWriter, r io.Reader, filename string) (err error) {
w.Header().Set(ContentDisposition, "attachment;filename="+filename)
Expand All @@ -79,7 +79,7 @@ func Inline(w http.ResponseWriter, r io.Reader, filename string) (err error) {
return
}

// ClientIP implements a best effort algorithm to return the real client IP, it parses
// ClientIP implements the best effort algorithm to return the real client IP, it parses
// X-Real-IP and X-Forwarded-For in order to work properly with reverse-proxies such us: nginx or haproxy.
func ClientIP(r *http.Request) (clientIP string) {
values := r.Header[XRealIP]
Expand All @@ -103,7 +103,7 @@ func ClientIP(r *http.Request) (clientIP string) {
return
}

// JSONStream uses json.Encoder to stream the JSON reponse body.
// JSONStream uses json.Encoder to stream the JSON response body.
//
// This differs from the JSON helper which unmarshalls into memory first allowing the capture of JSON encoding errors.
func JSONStream(w http.ResponseWriter, status int, i interface{}) error {
Expand Down
31 changes: 16 additions & 15 deletions net/http/retryable.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ package httpext
import (
"context"
"fmt"
bytesext "github.com/go-playground/pkg/v5/bytes"
errorsext "github.com/go-playground/pkg/v5/errors"
resultext "github.com/go-playground/pkg/v5/values/result"
"net/http"
"strconv"

bytesext "github.com/go-playground/pkg/v5/bytes"
errorsext "github.com/go-playground/pkg/v5/errors"
. "github.com/go-playground/pkg/v5/values/result"
)

var (
Expand Down Expand Up @@ -59,39 +60,39 @@ type BuildRequestFn func(ctx context.Context) (*http.Request, error)
type IsRetryableStatusCodeFn func(code int) bool

// DoRetryableResponse will execute the provided functions code and automatically retry before returning the *http.Response.
func DoRetryableResponse(ctx context.Context, onRetryFn errorsext.OnRetryFn[error], isRetryableStatusCode IsRetryableStatusCodeFn, client *http.Client, buildFn BuildRequestFn) resultext.Result[*http.Response, error] {
func DoRetryableResponse(ctx context.Context, onRetryFn errorsext.OnRetryFn[error], isRetryableStatusCode IsRetryableStatusCodeFn, client *http.Client, buildFn BuildRequestFn) Result[*http.Response, error] {
if client == nil {
client = http.DefaultClient
}
var attempt int
for {
req, err := buildFn(ctx)
if err != nil {
return resultext.Err[*http.Response, error](err)
return Err[*http.Response, error](err)
}

resp, err := client.Do(req)
if err != nil {
if retryReason, isRetryable := errorsext.IsRetryableHTTP(err); isRetryable {
opt := onRetryFn(ctx, err, retryReason, attempt)
if opt.IsSome() {
return resultext.Err[*http.Response, error](opt.Unwrap())
return Err[*http.Response, error](opt.Unwrap())
}
attempt++
continue
}
return resultext.Err[*http.Response, error](err)
return Err[*http.Response, error](err)
}

if isRetryableStatusCode(resp.StatusCode) {
opt := onRetryFn(ctx, ErrRetryableStatusCode{Response: resp}, strconv.Itoa(resp.StatusCode), attempt)
if opt.IsSome() {
return resultext.Err[*http.Response, error](opt.Unwrap())
return Err[*http.Response, error](opt.Unwrap())
}
attempt++
continue
}
return resultext.Ok[*http.Response, error](resp)
return Ok[*http.Response, error](resp)
}
}

Expand All @@ -101,25 +102,25 @@ func DoRetryableResponse(ctx context.Context, onRetryFn errorsext.OnRetryFn[erro
// Gzip supported:
// - JSON
// - XML
func DoRetryable[T any](ctx context.Context, isRetryableFn errorsext.IsRetryableFn[error], onRetryFn errorsext.OnRetryFn[error], isRetryableStatusCode IsRetryableStatusCodeFn, client *http.Client, expectedResponseCode int, maxMemory bytesext.Bytes, buildFn BuildRequestFn) resultext.Result[T, error] {
func DoRetryable[T any](ctx context.Context, isRetryableFn errorsext.IsRetryableFn[error], onRetryFn errorsext.OnRetryFn[error], isRetryableStatusCode IsRetryableStatusCodeFn, client *http.Client, expectedResponseCode int, maxMemory bytesext.Bytes, buildFn BuildRequestFn) Result[T, error] {

return errorsext.DoRetryable(ctx, isRetryableFn, onRetryFn, func(ctx context.Context) resultext.Result[T, error] {
return errorsext.DoRetryable(ctx, isRetryableFn, onRetryFn, func(ctx context.Context) Result[T, error] {

result := DoRetryableResponse(ctx, onRetryFn, isRetryableStatusCode, client, buildFn)
if result.IsErr() {
return resultext.Err[T, error](result.Err())
return Err[T, error](result.Err())
}
resp := result.Unwrap()

if resp.StatusCode != expectedResponseCode {
return resultext.Err[T, error](ErrUnexpectedResponse{Response: resp})
return Err[T, error](ErrUnexpectedResponse{Response: resp})
}
defer resp.Body.Close()

data, err := DecodeResponse[T](resp, maxMemory)
if err != nil {
return resultext.Err[T, error](err)
return Err[T, error](err)
}
return resultext.Ok[T, error](data)
return Ok[T, error](data)
})
}
3 changes: 3 additions & 0 deletions unsafe/conversions.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
//go:build !go1.21
// +build !go1.21

package unsafeext

import (
Expand Down
21 changes: 21 additions & 0 deletions unsafe/conversions_go121.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//go:build go1.21

package unsafeext

import (
"unsafe"
)

// BytesToString converts an array of bytes into a string without allocating.
// The byte slice passed to this function is not to be used after this call as it's unsafe; you have been warned.
func BytesToString(b []byte) string {
return unsafe.String(unsafe.SliceData(b), len(b))
}

// StringToBytes converts an existing string into an []byte without allocating.
// The string passed to these functions is not to be used again after this call as it's unsafe; you have been warned.
func StringToBytes(s string) (b []byte) {
d := unsafe.StringData(s)
b = unsafe.Slice(d, len(s))
return
}
Loading

0 comments on commit d5715da

Please sign in to comment.