safecast

package module
v1.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 29, 2025 License: Apache-2.0 Imports: 5 Imported by: 61

README

safecast

Go Report Card GoDoc codecov Maintainability CI Checks

Avoid accidental overflow of numbers during go type conversions (e.g instead of shorter := bigger.(int8) type conversions use shorter := safecast.MustConv[int8](bigger).

Safecast allows you to safely convert between numeric types in Go and return errors (or panic when using the Must* variants) when the cast would result in a loss of precision, range or sign.

See https://pkg.go.dev/fortio.org/safecast for docs and example. This is usable from any go with generics (1.18 or later) though our CI uses the latest go.

safecast is about avoiding gosec G115 and CWE-190: Integer Overflow or Wraparound class of overflow and loss of precision bugs, extended to float64/float32 issues.

Credit for the idea (and a finding a bug in the first implementation) goes to @ccoVeille, Please see https://github.com/ccoVeille/go-safecast for an different style API and implementation to pick whichever fits your style best (though I believe this implementation and API is better both in simplicity of principle (round trip check) and performance and api surface).

Please note that conversions from integer to float are suffering from CPU architecture differences and issues at the "edge" (max int) which are handled by Convert but you should use the new int only Conv/MustConv if possible, to avoid them.

Documentation

Overview

Package safecast allows you to safely cast between numeric types in Go and return errors (or panic when using the Must* variants) when the cast would result in a loss of precision, range or sign.

Example
package main

import (
	"fmt"

	"fortio.org/safecast"
)

func main() {
	var in int16 = 256
	// will error out
	out, err := safecast.Conv[uint8](in)
	fmt.Println(out, err)
	// will be fine
	out = safecast.MustRound[uint8](255.4)
	fmt.Println(out)
	// Also fine
	out = safecast.MustTruncate[uint8](255.6)
	fmt.Println(out)
}
Output:
0 out of range
255
255

Index

Examples

Constants

This section is empty.

Variables

View Source
var ErrOutOfRange = errors.New("out of range")

Functions

func Conv added in v1.1.0

func Conv[NumOut Integer, NumIn Integer](orig NumIn) (converted NumOut, err error)

Conv is an integer only and simpler version of Convert without the weird issue with round trip to floating point. Unlike Convert it can be used for identity (same type in and out) even if that's of dubious value.

func Convert

func Convert[NumOut Number, NumIn Number](orig NumIn) (converted NumOut, err error)

Convert converts a number from one type to another, returning an error if the conversion would result in a loss of precision, range or sign (overflow). In other words if the converted number is not equal to the original number. Use Conv instead if both of your types are Integer. Do not use for identity (same type in and out) but in particular this will error for Convert[uint64](uint64(math.MaxUint64)) or Convert[int64](int64(math.MaxInt64)) because it needs to when converting to any float. Note that +Inf will convert correctly (as in error only if going to an integer type) from a float64/float32 and not a ~float (it will error from say ~float32 to float64 while it shouldn't).

func MustConv added in v1.1.0

func MustConv[NumOut Integer, NumIn Integer](orig NumIn) NumOut

MustConv is as Conv but panics if there is an error.

func MustConvert

func MustConvert[NumOut Number, NumIn Number](orig NumIn) NumOut

Same as Convert but panics if there is an error.

func MustRound

func MustRound[NumOut Number, NumIn Float](orig NumIn) NumOut

Same as Round but panics if there is an error.

Example
package main

import (
	"fmt"

	"fortio.org/safecast"
)

func main() {
	defer func() {
		if r := recover(); r != nil {
			fmt.Println("panic:", r)
		}
	}()
	out := safecast.MustRound[int8](-128.6)
	fmt.Println("not reached", out) // not reached
}
Output:
panic: safecast: out of range for -128.6 (float64) to int8

func MustTruncate

func MustTruncate[NumOut Number, NumIn Float](orig NumIn) NumOut

Same as Truncate but panics if there is an error.

func Round

func Round[NumOut Number, NumIn Float](orig NumIn) (converted NumOut, err error)

Converts a float to an integer by rounding to the nearest integer. Returns an error if the conversion would result in a loss of precision.

func Truncate

func Truncate[NumOut Number, NumIn Float](orig NumIn) (converted NumOut, err error)

Converts a float to an integer by truncating the fractional part. Returns an error if the conversion would result in a loss of precision.

Types

type Float

type Float interface {
	~float32 | ~float64 // Consider removing the ~ because of +Inf issue.
}

type Integer

type Integer interface {
	~int | ~uint | ~int8 | ~uint8 | ~int16 | ~uint16 | ~int32 | ~uint32 | ~int64 | ~uint64 | ~uintptr
}

type Number

type Number interface {
	Integer | Float
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL