extern crate rustc_middle;
use rustc_middle::ty::{IntTy, Ty, TyKind, UintTy};
use crate::RewriteKind;
pub fn classify_cast<'tcx>(src: Ty<'tcx>, dst: Ty<'tcx>) -> Option<RewriteKind> {
match (src.kind(), dst.kind()) {
(TyKind::Uint(UintTy::U8), TyKind::Char) => Some(RewriteKind::CharFrom),
(TyKind::Float(_), _) | (_, TyKind::Float(_)) => None,
(TyKind::RawPtr(..) | TyKind::Ref(..) | TyKind::FnPtr(..), _)
| (_, TyKind::RawPtr(..) | TyKind::Ref(..) | TyKind::FnPtr(..)) => None,
(TyKind::Adt(def, _), _) if def.is_enum() => None,
(_, TyKind::Adt(def, _)) if def.is_enum() => None,
(TyKind::Int(src_i), TyKind::Int(dst_i)) => {
let dst_name = int_name(*dst_i);
if is_widening_signed(*src_i, *dst_i) {
Some(RewriteKind::TypeFrom { dst: dst_name })
} else {
Some(RewriteKind::TryFrom { dst: dst_name })
}
}
(TyKind::Uint(src_u), TyKind::Uint(dst_u)) => {
let dst_name = uint_name(*dst_u);
if is_widening_unsigned(*src_u, *dst_u) {
Some(RewriteKind::TypeFrom { dst: dst_name })
} else {
Some(RewriteKind::TryFrom { dst: dst_name })
}
}
(TyKind::Uint(src_u), TyKind::Int(dst_i)) => {
let dst_name = int_name(*dst_i);
if is_widening_uint_to_int(*src_u, *dst_i) {
Some(RewriteKind::TypeFrom { dst: dst_name })
} else {
Some(RewriteKind::TryFrom { dst: dst_name })
}
}
(TyKind::Int(_), TyKind::Uint(dst_u)) => Some(RewriteKind::TryFrom {
dst: uint_name(*dst_u),
}),
_ => None,
}
}
fn int_name(t: IntTy) -> String {
match t {
IntTy::I8 => "i8",
IntTy::I16 => "i16",
IntTy::I32 => "i32",
IntTy::I64 => "i64",
IntTy::I128 => "i128",
IntTy::Isize => "isize",
}
.to_string()
}
fn uint_name(t: UintTy) -> String {
match t {
UintTy::U8 => "u8",
UintTy::U16 => "u16",
UintTy::U32 => "u32",
UintTy::U64 => "u64",
UintTy::U128 => "u128",
UintTy::Usize => "usize",
}
.to_string()
}
fn is_widening_signed(src: IntTy, dst: IntTy) -> bool {
bits_signed(src) <= bits_signed(dst)
}
fn is_widening_unsigned(src: UintTy, dst: UintTy) -> bool {
match (bits_unsigned(src), bits_unsigned(dst)) {
(Some(s), Some(d)) => d >= s,
(Some(s), None) => s <= 16, _ => false,
}
}
fn is_widening_uint_to_int(src: UintTy, dst: IntTy) -> bool {
match (bits_unsigned(src), bits_signed(dst)) {
(Some(s), d) => d > s as i32, (None, _) => false, }
}
fn bits_signed(t: IntTy) -> i32 {
match t {
IntTy::I8 => 8,
IntTy::I16 => 16,
IntTy::I32 => 32,
IntTy::I64 => 64,
IntTy::I128 => 128,
IntTy::Isize => 64, }
}
fn bits_unsigned(t: UintTy) -> Option<u32> {
match t {
UintTy::U8 => Some(8),
UintTy::U16 => Some(16),
UintTy::U32 => Some(32),
UintTy::U64 => Some(64),
UintTy::U128 => Some(128),
UintTy::Usize => None, }
}