11package safecast
22
3- import "math"
3+ import (
4+ "math"
45
5- // ToInt attempts to convert any [IConvertable] value to an int.
6- // If the conversion results in a value outside the range of an int,
7- // the closest boundary value will be returned.
8- func ToInt [C IConvertable ](i C ) int {
6+ "github.com/ARM-software/golang-utils/utils/commonerrors"
7+ "github.com/ARM-software/golang-utils/utils/ptr"
8+ )
9+
10+ // CastFunc defines a function that converts a value of type F to type T,
11+ // where both types satisfy [IConvertible].
12+ type CastFunc [F , T IConvertible ] func (F ) T
13+
14+ // Cast converts an [IConvertible] value to another [IConvertible] type
15+ // using the supplied conversion function.
16+ func Cast [F , T IConvertible ](i F , f CastFunc [F , T ]) T {
17+ return f (i )
18+ }
19+
20+ // RobustCast converts an [IConvertible] value to the target type T by
21+ // dispatching to the appropriate safe helper for T.
22+ //
23+ // Conversions to bounded integer and float32 types use the corresponding
24+ // helper, so out-of-range values are clamped to the nearest valid boundary.
25+ // If types are not supported, an error is returned.
26+ func RobustCast [F , T IConvertible ](i F ) (c T , err error ) {
27+ var zero T
28+
29+ switch any (zero ).(type ) {
30+ case int :
31+ c = any (Cast (i , ToInt [F ])).(T )
32+ case uint :
33+ c = any (Cast (i , ToUint [F ])).(T )
34+ case int8 :
35+ c = any (Cast (i , ToInt8 [F ])).(T )
36+ case uint8 :
37+ c = any (Cast (i , ToUint8 [F ])).(T )
38+ case int16 :
39+ c = any (Cast (i , ToInt16 [F ])).(T )
40+ case uint16 :
41+ c = any (Cast (i , ToUint16 [F ])).(T )
42+ case int32 :
43+ c = any (Cast (i , ToInt32 [F ])).(T )
44+ case uint32 :
45+ c = any (Cast (i , ToUint32 [F ])).(T )
46+ case int64 :
47+ c = any (Cast (i , ToInt64 [F ])).(T )
48+ case uint64 :
49+ c = any (Cast (i , ToUint64 [F ])).(T )
50+ case float32 :
51+ c = any (Cast (i , ToFloat32 [F ])).(T )
52+ case float64 :
53+ c = any (Cast (i , ToFloat64 [F ])).(T )
54+ default :
55+ err = commonerrors .New (commonerrors .ErrUnsupported , "target type for casting is not supported" )
56+ }
57+ return
58+ }
59+
60+ // CastRef converts a reference to an [IConvertible] value to a reference
61+ // to another [IConvertible] type using the supplied conversion function.
62+ // A nil input returns nil.
63+ func CastRef [F , T IConvertible ](i * F , f CastFunc [F , T ]) * T {
64+ if i == nil {
65+ return nil
66+ }
67+ return ptr .To (Cast [F , T ](ptr .From (i ), f ))
68+ }
69+
70+ // RobustCastRef converts a reference to an [IConvertible] value to a reference
71+ // to the target type T by dispatching to the appropriate safe helper for T.
72+ // A nil input returns nil.
73+ // If types are not supported, an error is returned.
74+ func RobustCastRef [F , T IConvertible ](i * F ) (c * T , err error ) {
75+ if i == nil {
76+ c = nil
77+ return
78+ }
79+
80+ v , err := RobustCast [F , T ](ptr .From (i ))
81+ if err != nil {
82+ return
83+ }
84+ c = ptr .To (v )
85+ return
86+ }
87+
88+ // ToInt attempts to convert an [IConvertible] value to an int.
89+ // If the converted value falls outside the range of int,
90+ // the nearest boundary value is returned instead.
91+ func ToInt [C IConvertible ](i C ) int {
992 if lessThanLowerBoundary (i , math .MinInt ) {
1093 return math .MinInt
1194 }
@@ -15,10 +98,16 @@ func ToInt[C IConvertable](i C) int {
1598 return int (i )
1699}
17100
18- // ToUint attempts to convert any [IConvertable] value to an uint.
19- // If the conversion results in a value outside the range of an uint,
20- // the closest boundary value will be returned.
21- func ToUint [C IConvertable ](i C ) uint {
101+ // ToIntRef attempts to convert a reference to an [IConvertible] value
102+ // to a reference to an int. A nil input returns nil.
103+ func ToIntRef [C IConvertible ](i * C ) * int {
104+ return CastRef (i , ToInt [C ])
105+ }
106+
107+ // ToUint attempts to convert an [IConvertible] value to a uint.
108+ // If the converted value falls outside the range of uint,
109+ // the nearest boundary value is returned instead.
110+ func ToUint [C IConvertible ](i C ) uint {
22111 if lessThanLowerBoundary (i , uint (0 )) {
23112 return 0
24113 }
@@ -28,10 +117,16 @@ func ToUint[C IConvertable](i C) uint {
28117 return uint (i )
29118}
30119
31- // ToInt8 attempts to convert any [IConvertable] value to an int8.
32- // If the conversion results in a value outside the range of an int8,
33- // the closest boundary value will be returned.
34- func ToInt8 [C IConvertable ](i C ) int8 {
120+ // ToUintRef attempts to convert a reference to an [IConvertible] value
121+ // to a reference to a uint. A nil input returns nil.
122+ func ToUintRef [C IConvertible ](i * C ) * uint {
123+ return CastRef (i , ToUint [C ])
124+ }
125+
126+ // ToInt8 attempts to convert an [IConvertible] value to an int8.
127+ // If the converted value falls outside the range of int8,
128+ // the nearest boundary value is returned instead.
129+ func ToInt8 [C IConvertible ](i C ) int8 {
35130 if lessThanLowerBoundary (i , math .MinInt8 ) {
36131 return math .MinInt8
37132 }
@@ -41,10 +136,16 @@ func ToInt8[C IConvertable](i C) int8 {
41136 return int8 (i )
42137}
43138
44- // ToUint8 attempts to convert any [IConvertable] value to an uint8.
45- // If the conversion results in a value outside the range of an uint8,
46- // the closest boundary value will be returned.
47- func ToUint8 [C IConvertable ](i C ) uint8 {
139+ // ToInt8Ref attempts to convert a reference to an [IConvertible] value
140+ // to a reference to an int8. A nil input returns nil.
141+ func ToInt8Ref [C IConvertible ](i * C ) * int8 {
142+ return CastRef (i , ToInt8 [C ])
143+ }
144+
145+ // ToUint8 attempts to convert an [IConvertible] value to a uint8.
146+ // If the converted value falls outside the range of uint8,
147+ // the nearest boundary value is returned instead.
148+ func ToUint8 [C IConvertible ](i C ) uint8 {
48149 if lessThanLowerBoundary (i , 0 ) {
49150 return 0
50151 }
@@ -54,10 +155,16 @@ func ToUint8[C IConvertable](i C) uint8 {
54155 return uint8 (i )
55156}
56157
57- // ToInt16 attempts to convert any [IConvertable] value to an int16.
58- // If the conversion results in a value outside the range of an int16,
59- // the closest boundary value will be returned.
60- func ToInt16 [C IConvertable ](i C ) int16 {
158+ // ToUint8Ref attempts to convert a reference to an [IConvertible] value
159+ // to a reference to a uint8. A nil input returns nil.
160+ func ToUint8Ref [C IConvertible ](i * C ) * uint8 {
161+ return CastRef (i , ToUint8 [C ])
162+ }
163+
164+ // ToInt16 attempts to convert an [IConvertible] value to an int16.
165+ // If the converted value falls outside the range of int16,
166+ // the nearest boundary value is returned instead.
167+ func ToInt16 [C IConvertible ](i C ) int16 {
61168 if lessThanLowerBoundary (i , math .MinInt16 ) {
62169 return math .MinInt16
63170 }
@@ -67,10 +174,16 @@ func ToInt16[C IConvertable](i C) int16 {
67174 return int16 (i )
68175}
69176
70- // ToUint16 attempts to convert any [IConvertable] value to an uint16.
71- // If the conversion results in a value outside the range of an uint16,
72- // the closest boundary value will be returned.
73- func ToUint16 [C IConvertable ](i C ) uint16 {
177+ // ToInt16Ref attempts to convert a reference to an [IConvertible] value
178+ // to a reference to an int16. A nil input returns nil.
179+ func ToInt16Ref [C IConvertible ](i * C ) * int16 {
180+ return CastRef (i , ToInt16 [C ])
181+ }
182+
183+ // ToUint16 attempts to convert an [IConvertible] value to a uint16.
184+ // If the converted value falls outside the range of uint16,
185+ // the nearest boundary value is returned instead.
186+ func ToUint16 [C IConvertible ](i C ) uint16 {
74187 if lessThanLowerBoundary (i , 0 ) {
75188 return 0
76189 }
@@ -80,10 +193,16 @@ func ToUint16[C IConvertable](i C) uint16 {
80193 return uint16 (i )
81194}
82195
83- // ToInt32 attempts to convert any [IConvertable] value to an int32.
84- // If the conversion results in a value outside the range of an int32,
85- // the closest boundary value will be returned.
86- func ToInt32 [C IConvertable ](i C ) int32 {
196+ // ToUint16Ref attempts to convert a reference to an [IConvertible] value
197+ // to a reference to a uint16. A nil input returns nil.
198+ func ToUint16Ref [C IConvertible ](i * C ) * uint16 {
199+ return CastRef (i , ToUint16 [C ])
200+ }
201+
202+ // ToInt32 attempts to convert an [IConvertible] value to an int32.
203+ // If the converted value falls outside the range of int32,
204+ // the nearest boundary value is returned instead.
205+ func ToInt32 [C IConvertible ](i C ) int32 {
87206 if lessThanLowerBoundary (i , math .MinInt32 ) {
88207 return math .MinInt32
89208 }
@@ -93,10 +212,16 @@ func ToInt32[C IConvertable](i C) int32 {
93212 return int32 (i )
94213}
95214
96- // ToUint32 attempts to convert any [IConvertable] value to an uint32.
97- // If the conversion results in a value outside the range of an uint32,
98- // the closest boundary value will be returned.
99- func ToUint32 [C IConvertable ](i C ) uint32 {
215+ // ToInt32Ref attempts to convert a reference to an [IConvertible] value
216+ // to a reference to an int32. A nil input returns nil.
217+ func ToInt32Ref [C IConvertible ](i * C ) * int32 {
218+ return CastRef (i , ToInt32 [C ])
219+ }
220+
221+ // ToUint32 attempts to convert an [IConvertible] value to a uint32.
222+ // If the converted value falls outside the range of uint32,
223+ // the nearest boundary value is returned instead.
224+ func ToUint32 [C IConvertible ](i C ) uint32 {
100225 if lessThanLowerBoundary (i , 0 ) {
101226 return 0
102227 }
@@ -106,10 +231,16 @@ func ToUint32[C IConvertable](i C) uint32 {
106231 return uint32 (i )
107232}
108233
109- // ToInt64 attempts to convert any [IConvertable] value to an int64.
110- // If the conversion results in a value outside the range of an int64,
111- // the closest boundary value will be returned.
112- func ToInt64 [C IConvertable ](i C ) int64 {
234+ // ToUint32Ref attempts to convert a reference to an [IConvertible] value
235+ // to a reference to a uint32. A nil input returns nil.
236+ func ToUint32Ref [C IConvertible ](i * C ) * uint32 {
237+ return CastRef (i , ToUint32 [C ])
238+ }
239+
240+ // ToInt64 attempts to convert an [IConvertible] value to an int64.
241+ // If the converted value falls outside the range of int64,
242+ // the nearest boundary value is returned instead.
243+ func ToInt64 [C IConvertible ](i C ) int64 {
113244 if lessThanLowerBoundary (i , math .MinInt64 ) {
114245 return math .MinInt64
115246 }
@@ -119,10 +250,16 @@ func ToInt64[C IConvertable](i C) int64 {
119250 return int64 (i )
120251}
121252
122- // ToUint64 attempts to convert any [IConvertable] value to an uint64.
123- // If the conversion results in a value outside the range of an uint64,
124- // the closest boundary value will be returned.
125- func ToUint64 [C IConvertable ](i C ) uint64 {
253+ // ToInt64Ref attempts to convert a reference to an [IConvertible] value
254+ // to a reference to an int64. A nil input returns nil.
255+ func ToInt64Ref [C IConvertible ](i * C ) * int64 {
256+ return CastRef (i , ToInt64 [C ])
257+ }
258+
259+ // ToUint64 attempts to convert an [IConvertible] value to a uint64.
260+ // If the converted value falls outside the range of uint64,
261+ // the nearest boundary value is returned instead.
262+ func ToUint64 [C IConvertible ](i C ) uint64 {
126263 if lessThanLowerBoundary (i , uint64 (0 )) {
127264 return 0
128265 }
@@ -132,7 +269,38 @@ func ToUint64[C IConvertable](i C) uint64 {
132269 return uint64 (i )
133270}
134271
135- // ToFloat64 attempts to convert any [IConvertable] value to an float64.
136- func ToFloat64 [C IConvertable ](i C ) float64 {
272+ // ToUint64Ref attempts to convert a reference to an [IConvertible] value
273+ // to a reference to a uint64. A nil input returns nil.
274+ func ToUint64Ref [C IConvertible ](i * C ) * uint64 {
275+ return CastRef (i , ToUint64 [C ])
276+ }
277+
278+ // ToFloat64 attempts to convert an [IConvertible] value to a float64.
279+ func ToFloat64 [C IConvertible ](i C ) float64 {
137280 return float64 (i )
138281}
282+
283+ // ToFloat64Ref attempts to convert a reference to an [IConvertible] value
284+ // to a reference to a float64. A nil input returns nil.
285+ func ToFloat64Ref [C IConvertible ](i * C ) * float64 {
286+ return CastRef (i , ToFloat64 [C ])
287+ }
288+
289+ // ToFloat32 attempts to convert an [IConvertible] value to a float32.
290+ // If the converted value falls outside the range of float32,
291+ // the nearest boundary value is returned instead.
292+ func ToFloat32 [C IConvertible ](i C ) float32 {
293+ if lessThanLowerBoundary (i , - math .MaxFloat32 ) || math .IsInf (float64 (i ), - 1 ) {
294+ return - math .MaxFloat32
295+ }
296+ if greaterThanUpperBoundary (i , math .MaxFloat32 ) || math .IsInf (float64 (i ), 1 ) {
297+ return math .MaxFloat32
298+ }
299+ return float32 (i )
300+ }
301+
302+ // ToFloat32Ref attempts to convert a reference to an [IConvertible] value
303+ // to a reference to a float32. A nil input returns nil.
304+ func ToFloat32Ref [C IConvertible ](i * C ) * float32 {
305+ return CastRef (i , ToFloat32 [C ])
306+ }
0 commit comments