|
| 1 | +package safe |
| 2 | + |
| 3 | +import ( |
| 4 | + "fmt" |
| 5 | + "math" |
| 6 | + "math/big" |
| 7 | + "time" |
| 8 | +) |
| 9 | + |
| 10 | +const ( |
| 11 | + MinInt16 = -1 << 15 // -32768 |
| 12 | + MaxInt16 = 1<<15 - 1 // 32767 |
| 13 | +) |
| 14 | + |
| 15 | +// IntToUint32 converts an int to uint32 after ensuring it’s in range. |
| 16 | +// Returns an error if the input is negative or exceeds the maximum value of a uint32. |
| 17 | +func IntToUint32(v int) (uint32, error) { |
| 18 | + if v < 0 || v > math.MaxUint32 { |
| 19 | + return 0, fmt.Errorf("value %d out of range", v) |
| 20 | + } |
| 21 | + |
| 22 | + return uint32(v), nil |
| 23 | +} |
| 24 | + |
| 25 | +// Uint64ToUint32 converts a uint64 value to a uint32 value after ensuring it fits into 32 bits. |
| 26 | +// Returns an error if the input value is too large. |
| 27 | +func Uint64ToUint32(v uint64) (uint32, error) { |
| 28 | + // ^uint32(0) is the maximum value of a uint32 (all bits set). |
| 29 | + if v > uint64(math.MaxUint32) { |
| 30 | + return 0, fmt.Errorf("value %d overflows uint32 (max %d)", v, math.MaxUint32) |
| 31 | + } |
| 32 | + |
| 33 | + return uint32(v), nil |
| 34 | +} |
| 35 | + |
| 36 | +// Int64ToUint64 safely converts an int64 to uint64. |
| 37 | +// Returns an error if the input is negative. |
| 38 | +func Int64ToUint64(value int64) (uint64, error) { |
| 39 | + if value < 0 { |
| 40 | + return 0, fmt.Errorf("negative value cannot be converted to uint64: %d", value) |
| 41 | + } |
| 42 | + |
| 43 | + return uint64(value), nil |
| 44 | +} |
| 45 | + |
| 46 | +// IntToUint64 safely converts an int to uint64. |
| 47 | +// Returns an error if the input is negative. |
| 48 | +func IntToUint64(value int) (uint64, error) { |
| 49 | + if value < 0 { |
| 50 | + return 0, fmt.Errorf("negative value cannot be converted to uint64: %d", value) |
| 51 | + } |
| 52 | + |
| 53 | + return uint64(value), nil |
| 54 | +} |
| 55 | + |
| 56 | +// Uint64ToInt safely converts a uint64 to int. |
| 57 | +// Returns an error if the value exceeds the limits of an int. |
| 58 | +func Uint64ToInt(value uint64) (int, error) { |
| 59 | + if value > math.MaxInt { |
| 60 | + return 0, fmt.Errorf("value exceeds int limit: %d", value) |
| 61 | + } |
| 62 | + |
| 63 | + return int(value), nil |
| 64 | +} |
| 65 | + |
| 66 | +// Int64ToInt32 safely converts an int64 to int32. |
| 67 | +// Returns an error if the value is outside the range of int32. |
| 68 | +func Int64ToInt32(value int64) (int32, error) { |
| 69 | + if value < math.MinInt32 || value > math.MaxInt32 { |
| 70 | + return 0, fmt.Errorf("value out of int32 range: %d", value) |
| 71 | + } |
| 72 | + |
| 73 | + return int32(value), nil |
| 74 | +} |
| 75 | + |
| 76 | +// IntToInt32 safely converts an int to int32. |
| 77 | +// Checks if the value is within the valid int32 range. |
| 78 | +func IntToInt32(value int) (int32, error) { |
| 79 | + if value < math.MinInt32 || value > math.MaxInt32 { |
| 80 | + return 0, fmt.Errorf("value out of int32 range: %d", value) |
| 81 | + } |
| 82 | + |
| 83 | + return int32(value), nil |
| 84 | +} |
| 85 | + |
| 86 | +// Int32ToUint32 safely converts an int32 to uint32. |
| 87 | +// Checks only for negative values, as positive int32 values are always within uint32 range. |
| 88 | +func Int32ToUint32(value int32) (uint32, error) { |
| 89 | + if value < 0 { |
| 90 | + return 0, fmt.Errorf("negative value cannot be converted to uint32: %d", value) |
| 91 | + } |
| 92 | + |
| 93 | + return uint32(value), nil |
| 94 | +} |
| 95 | + |
| 96 | +// Int64ToUint32 safely converts an int64 to uint32. |
| 97 | +// Checks if the value is non-negative and within the uint32 range. |
| 98 | +func Int64ToUint32(value int64) (uint32, error) { |
| 99 | + if value < 0 { |
| 100 | + return 0, fmt.Errorf("negative value cannot be converted to uint32: %d", value) |
| 101 | + } |
| 102 | + |
| 103 | + if value > math.MaxUint32 { |
| 104 | + return 0, fmt.Errorf("value exceeds uint32 range: %d", value) |
| 105 | + } |
| 106 | + |
| 107 | + return uint32(value), nil |
| 108 | +} |
| 109 | + |
| 110 | +// BigWordToUint32 safely converts a big.Word to uint32. |
| 111 | +// It ensures that the value is within the valid uint32 range before conversion. |
| 112 | +// |
| 113 | +// The function explicitly converts `big.Word` to `uint64` first to avoid the G115 |
| 114 | +// lint warning (integer overflow conversion). This is necessary because `big.Word` |
| 115 | +// can be either `uint32` (on 32-bit systems) or `uint64` (on 64-bit systems). |
| 116 | +// Without this explicit conversion, the linter assumes a potential risk when |
| 117 | +// directly converting from `big.Word` to `uint32`. |
| 118 | +func BigWordToUint32(value big.Word) (uint32, error) { |
| 119 | + valueUint64 := uint64(value) |
| 120 | + |
| 121 | + if valueUint64 > math.MaxUint32 { |
| 122 | + return 0, fmt.Errorf("big.Word exceeds uint32 range: %d", valueUint64) |
| 123 | + } |
| 124 | + |
| 125 | + return uint32(valueUint64), nil |
| 126 | +} |
| 127 | + |
| 128 | +// IntToUint16 safely converts an int to uint16. |
| 129 | +// Checks if the value is non-negative and within the uint16 range. |
| 130 | +func IntToUint16(value int) (uint16, error) { |
| 131 | + if value < 0 { |
| 132 | + return 0, fmt.Errorf("negative value cannot be converted to uint16: %d", value) |
| 133 | + } |
| 134 | + |
| 135 | + if value > math.MaxUint16 { |
| 136 | + return 0, fmt.Errorf("value exceeds uint16 range: %d", value) |
| 137 | + } |
| 138 | + |
| 139 | + return uint16(value), nil |
| 140 | +} |
| 141 | + |
| 142 | +// IntToInt16 safely converts an int to int16. |
| 143 | +// Checks if the value is within the valid int16 range. |
| 144 | +func IntToInt16(value int) (int16, error) { |
| 145 | + if value < MinInt16 || value > MaxInt16 { |
| 146 | + return 0, fmt.Errorf("value out of int16 range: %d", value) |
| 147 | + } |
| 148 | + |
| 149 | + return int16(value), nil |
| 150 | +} |
| 151 | + |
| 152 | +// UintToUint32 safely converts a uint to uint32. |
| 153 | +// Checks if the value exceeds the uint32 range. |
| 154 | +func UintToUint32(value uint) (uint32, error) { |
| 155 | + if value > math.MaxUint32 { |
| 156 | + return 0, fmt.Errorf("value exceeds uint32 range: %d", value) |
| 157 | + } |
| 158 | + |
| 159 | + return uint32(value), nil |
| 160 | +} |
| 161 | + |
| 162 | +// TimeToUint32 safely converts a time.Time's Unix timestamp to uint32. |
| 163 | +// Checks if the timestamp is non-negative and within the uint32 range. |
| 164 | +func TimeToUint32(value time.Time) (uint32, error) { |
| 165 | + timestamp := value.Unix() |
| 166 | + if timestamp < 0 { |
| 167 | + return 0, fmt.Errorf("negative timestamp cannot be converted to uint32: %d", timestamp) |
| 168 | + } |
| 169 | + |
| 170 | + if timestamp > math.MaxUint32 { |
| 171 | + return 0, fmt.Errorf("timestamp exceeds uint32 range: %d", timestamp) |
| 172 | + } |
| 173 | + |
| 174 | + return uint32(timestamp), nil |
| 175 | +} |
| 176 | + |
| 177 | +// Uint32ToUint8 safely converts a uint32 to uint8. |
| 178 | +// Checks if the value exceeds the uint8 range. |
| 179 | +func Uint32ToUint8(value uint32) (uint8, error) { |
| 180 | + if value > math.MaxUint8 { |
| 181 | + return 0, fmt.Errorf("value exceeds uint8 range: %d", value) |
| 182 | + } |
| 183 | + |
| 184 | + return uint8(value), nil |
| 185 | +} |
| 186 | + |
| 187 | +// UintptrToInt safely converts a uintptr to int. |
| 188 | +// Checks if the value exceeds the maximum int range. |
| 189 | +func UintptrToInt(value uintptr) (int, error) { |
| 190 | + if value > uintptr(math.MaxInt) { |
| 191 | + return 0, fmt.Errorf("value exceeds int range: %d", value) |
| 192 | + } |
| 193 | + |
| 194 | + return int(value), nil |
| 195 | +} |
| 196 | + |
| 197 | +// Uint64ToInt64 safely converts a uint64 to int64. |
| 198 | +// Checks if the value exceeds the maximum int64 range. |
| 199 | +func Uint64ToInt64(value uint64) (int64, error) { |
| 200 | + if value > math.MaxInt64 { |
| 201 | + return 0, fmt.Errorf("value exceeds int64 range: %d", value) |
| 202 | + } |
| 203 | + |
| 204 | + return int64(value), nil |
| 205 | +} |
| 206 | + |
| 207 | +// Uint32ToInt32 safely converts a uint32 to int32. |
| 208 | +// Checks if the value exceeds the maximum int32 range. |
| 209 | +func Uint32ToInt32(value uint32) (int32, error) { |
| 210 | + if value > math.MaxInt32 { |
| 211 | + return 0, fmt.Errorf("value exceeds int32 range: %d", value) |
| 212 | + } |
| 213 | + |
| 214 | + return int32(value), nil |
| 215 | +} |
| 216 | + |
| 217 | +// Uint64ToInt32 safely converts a uint64 to int32. |
| 218 | +// Checks if the value exceeds the int32 range or if it's negative. |
| 219 | +func Uint64ToInt32(value uint64) (int32, error) { |
| 220 | + if value > math.MaxInt32 { |
| 221 | + return 0, fmt.Errorf("value exceeds int32 range: %d", value) |
| 222 | + } |
| 223 | + |
| 224 | + return int32(value), nil |
| 225 | +} |
| 226 | + |
| 227 | +// Uint32ToInt64 safely converts a uint32 to int64. |
| 228 | +// Since all uint32 values are within the valid int64 range, the conversion is always safe. |
| 229 | +func Uint32ToInt64(value uint32) (int64, error) { |
| 230 | + return int64(value), nil |
| 231 | +} |
| 232 | + |
| 233 | +// Uint32ToUint64 safely converts a uint32 to uint64. |
| 234 | +// Since all uint32 values fit within the uint64 range, the conversion is always safe. |
| 235 | +func Uint32ToUint64(value uint32) (uint64, error) { |
| 236 | + return uint64(value), nil |
| 237 | +} |
| 238 | + |
| 239 | +// Uint64ToUint16 safely converts a uint64 to uint16. |
| 240 | +// Checks if the value exceeds the uint16 range. |
| 241 | +func Uint64ToUint16(value uint64) (uint16, error) { |
| 242 | + if value > math.MaxUint16 { |
| 243 | + return 0, fmt.Errorf("value exceeds uint16 range: %d", value) |
| 244 | + } |
| 245 | + |
| 246 | + return uint16(value), nil |
| 247 | +} |
0 commit comments