@@ -2183,6 +2183,177 @@ impl CTypeKind {
21832183 _ => unimplemented ! ( "Printer::print_type({:?})" , self ) ,
21842184 }
21852185 }
2186+
2187+ /// Whether `value` is guaranteed to be in this integer type's range.
2188+ /// Thus, minimum ranges are used (e.x. [`i16::MIN`] for [`Self::Int`]).
2189+ pub fn guaranteed_integer_in_range ( & self , value : u64 ) -> bool {
2190+ fn in_range < T : TryFrom < u64 > > ( value : u64 ) -> bool {
2191+ T :: try_from ( value) . is_ok ( )
2192+ }
2193+
2194+ use CTypeKind :: * ;
2195+ match * self {
2196+ Void => false ,
2197+
2198+ Bool => ( 0 ..=1 ) . contains ( & value) ,
2199+
2200+ // Can be signed or unsigned, so choose the minimum range of each.
2201+ Char => ( u8:: MIN as u64 ..=i8:: MAX as u64 ) . contains ( & value) ,
2202+ WChar => in_range :: < i32 > ( value) ,
2203+
2204+ // `int` is at least `i16` and `long` is at least `i32`.
2205+ SChar => in_range :: < i8 > ( value) ,
2206+ Short => in_range :: < i16 > ( value) ,
2207+ Int => in_range :: < i16 > ( value) ,
2208+ Long => in_range :: < i32 > ( value) ,
2209+ LongLong => in_range :: < i64 > ( value) ,
2210+
2211+ // `unsigned int` is at least `u16` and `unsigned long` is at least `u32`.
2212+ UChar => in_range :: < u8 > ( value) ,
2213+ UShort => in_range :: < u16 > ( value) ,
2214+ UInt => in_range :: < u16 > ( value) ,
2215+ ULong => in_range :: < u32 > ( value) ,
2216+ ULongLong => in_range :: < u64 > ( value) ,
2217+
2218+ Int8 => in_range :: < i8 > ( value) ,
2219+ Int16 => in_range :: < i16 > ( value) ,
2220+ Int32 => in_range :: < i32 > ( value) ,
2221+ Int64 => in_range :: < i64 > ( value) ,
2222+ Int128 => in_range :: < i128 > ( value) ,
2223+
2224+ UInt8 => in_range :: < u8 > ( value) ,
2225+ UInt16 => in_range :: < u16 > ( value) ,
2226+ UInt32 => in_range :: < u32 > ( value) ,
2227+ UInt64 => in_range :: < u64 > ( value) ,
2228+ UInt128 => in_range :: < u128 > ( value) ,
2229+
2230+ // There's no guarantee on pointer size, but `NULL` should work.
2231+ IntPtr => value == 0 ,
2232+ UIntPtr => value == 0 ,
2233+
2234+ IntMax => in_range :: < i64 > ( value) ,
2235+ UIntMax => in_range :: < u64 > ( value) ,
2236+
2237+ // `size_t` is at least a `u16`, and similar for `ssize_t` and `ptrdiff_t`.
2238+ Size => in_range :: < u16 > ( value) ,
2239+ SSize => in_range :: < i16 > ( value) ,
2240+ PtrDiff => in_range :: < i16 > ( value) ,
2241+
2242+ // Floats, see `Self::guaranteed_float_in_range`.
2243+ Float => false ,
2244+ Double => false ,
2245+ LongDouble => false ,
2246+ Half => false ,
2247+ BFloat16 => false ,
2248+ Float128 => false ,
2249+
2250+ // Non-scalars.
2251+ Complex ( _) => false ,
2252+ Pointer ( _) => false ,
2253+ Reference ( _) => false ,
2254+ ConstantArray ( _, _) => false ,
2255+ IncompleteArray ( _) => false ,
2256+ VariableArray ( _, _) => false ,
2257+ TypeOf ( _) => false ,
2258+ TypeOfExpr ( _) => false ,
2259+ Function ( _, _, _, _, _) => false ,
2260+ Typedef ( _) => false ,
2261+ Decayed ( _) => false ,
2262+ Elaborated ( _) => false ,
2263+ Paren ( _) => false ,
2264+ Struct ( _) => false ,
2265+ Union ( _) => false ,
2266+ Enum ( _) => false ,
2267+ BuiltinFn => false ,
2268+ Attributed ( _, _) => false ,
2269+ BlockPointer ( _) => false ,
2270+ Vector ( _, _) => false ,
2271+ UnhandledSveType => false ,
2272+ Atomic ( _) => false ,
2273+ }
2274+ }
2275+
2276+ pub fn guaranteed_float_in_range ( & self , value : f64 ) -> bool {
2277+ fn in_range < T : TryFrom < f64 > > ( value : f64 ) -> bool {
2278+ T :: try_from ( value) . is_ok ( )
2279+ }
2280+
2281+ use CTypeKind :: * ;
2282+ match * self {
2283+ // `f32: TryFrom<f64>` is not implemented.
2284+ // C `float`s are not guaranteed to be `f32`,
2285+ // but Rust (namely `libc`) doesn't support any platform where this isn't the case.
2286+ Float => value >= f32:: MIN as f64 && value <= f32:: MAX as f64 ,
2287+
2288+ // Similarly to `float`, `double` is not guaranteed to be `f64`,
2289+ // but `libc` doesn't support any platform where this isn't the case.
2290+ Double => in_range :: < f64 > ( value) ,
2291+
2292+ // `long double` (not `f128`) is only guaranteed to be at least as precise as a `double`.
2293+ LongDouble => in_range :: < f64 > ( value) ,
2294+
2295+ // All `f64`s are valid `f128`s.
2296+ Float128 => in_range :: < f64 > ( value) ,
2297+
2298+ // TODO Would like to depend on `half`.
2299+ Half => todo ! ( "f16 range" ) ,
2300+ BFloat16 => todo ! ( "bf16 range" ) ,
2301+
2302+ Void => false ,
2303+ Bool => false ,
2304+ Char => false ,
2305+ SChar => false ,
2306+ Short => false ,
2307+ Int => false ,
2308+ Long => false ,
2309+ LongLong => false ,
2310+ UChar => false ,
2311+ UShort => false ,
2312+ UInt => false ,
2313+ ULong => false ,
2314+ ULongLong => false ,
2315+ Int128 => false ,
2316+ UInt128 => false ,
2317+ Complex ( _) => false ,
2318+ Pointer ( _) => false ,
2319+ Reference ( _) => false ,
2320+ ConstantArray ( _, _) => false ,
2321+ IncompleteArray ( _) => false ,
2322+ VariableArray ( _, _) => false ,
2323+ TypeOf ( _) => false ,
2324+ TypeOfExpr ( _) => false ,
2325+ Function ( _, _, _, _, _) => false ,
2326+ Typedef ( _) => false ,
2327+ Decayed ( _) => false ,
2328+ Elaborated ( _) => false ,
2329+ Paren ( _) => false ,
2330+ Struct ( _) => false ,
2331+ Union ( _) => false ,
2332+ Enum ( _) => false ,
2333+ BuiltinFn => false ,
2334+ Attributed ( _, _) => false ,
2335+ BlockPointer ( _) => false ,
2336+ Vector ( _, _) => false ,
2337+ UnhandledSveType => false ,
2338+ Atomic ( _) => false ,
2339+ Int8 => false ,
2340+ Int16 => false ,
2341+ Int32 => false ,
2342+ Int64 => false ,
2343+ IntPtr => false ,
2344+ UInt8 => false ,
2345+ UInt16 => false ,
2346+ UInt32 => false ,
2347+ UInt64 => false ,
2348+ UIntPtr => false ,
2349+ IntMax => false ,
2350+ UIntMax => false ,
2351+ Size => false ,
2352+ SSize => false ,
2353+ PtrDiff => false ,
2354+ WChar => false ,
2355+ }
2356+ }
21862357}
21872358
21882359impl Display for CTypeKind {
0 commit comments