use crate::internal::Primitive;
pub(super) fn from_any<'v, T: 'static>(value: &'v T) -> Option<Primitive<'v>> {
#[cfg(value_bag_capture_const_type_id)]
{
use crate::std::any::TypeId;
macro_rules! to_primitive {
($($ty:ty : ($const_ident:ident, $option_ident:ident),)*) => {
trait ToPrimitive
where
Self: 'static,
{
const CALL: fn(&Self) -> Option<Primitive> = {
$(
const $const_ident: TypeId = TypeId::of::<$ty>();
const $option_ident: TypeId = TypeId::of::<Option<$ty>>();
)*
match TypeId::of::<Self>() {
$(
$const_ident => |v| Some(Primitive::from(unsafe { *(v as *const Self as *const $ty) })),
$option_ident => |v| Some({
let v = unsafe { *(v as *const Self as *const Option<$ty>) };
match v {
Some(v) => Primitive::from(v),
None => Primitive::None,
}
}),
)*
_ => |_| None,
}
};
fn to_primitive(&self) -> Option<Primitive> {
(Self::CALL)(self)
}
}
impl<T: ?Sized + 'static> ToPrimitive for T {}
}
}
to_primitive![
usize: (USIZE, OPTION_USIZE),
u8: (U8, OPTION_U8),
u16: (U16, OPTION_U16),
u32: (U32, OPTION_U32),
u64: (U64, OPTION_U64),
u128: (U128, OPTION_U128),
isize: (ISIZE, OPTION_ISIZE),
i8: (I8, OPTION_I8),
i16: (I16, OPTION_I16),
i32: (I32, OPTION_I32),
i64: (I64, OPTION_I64),
i128: (I128, OPTION_I128),
f32: (F32, OPTION_F32),
f64: (F64, OPTION_F64),
char: (CHAR, OPTION_CHAR),
bool: (BOOL, OPTION_BOOL),
&'static str: (STR, OPTION_STR),
];
value.to_primitive()
}
#[cfg(value_bag_capture_ctor)]
{
#![allow(unused_unsafe)]
use ctor::ctor;
use crate::std::{
any::{Any, TypeId},
cmp::Ordering,
};
macro_rules! type_ids {
($($ty:ty,)*) => {
[
$(
(
std::any::TypeId::of::<$ty>(),
(|value| unsafe {
debug_assert_eq!(value.type_id(), std::any::TypeId::of::<$ty>());
let value = *(value as *const dyn std::any::Any as *const $ty);
Primitive::from(value)
}) as for<'a> fn(&'a (dyn std::any::Any + 'static)) -> Primitive<'a>
),
)*
$(
(
std::any::TypeId::of::<Option<$ty>>(),
(|value| unsafe {
debug_assert_eq!(value.type_id(), std::any::TypeId::of::<Option<$ty>>());
let value = *(value as *const dyn std::any::Any as *const Option<$ty>);
if let Some(value) = value {
Primitive::from(value)
} else {
Primitive::None
}
}) as for<'a> fn(&'a (dyn std::any::Any + 'static)) -> Primitive<'a>
),
)*
]
};
}
fn quicksort_helper<T, F>(arr: &mut [T], left: isize, right: isize, compare: &F)
where
F: Fn(&T, &T) -> Ordering,
{
if right <= left {
return;
}
let mut i: isize = left - 1;
let mut j: isize = right;
let mut p: isize = i;
let mut q: isize = j;
unsafe {
let v: *mut T = &mut arr[right as usize];
loop {
i += 1;
while compare(&arr[i as usize], &*v) == Ordering::Less {
i += 1
}
j -= 1;
while compare(&*v, &arr[j as usize]) == Ordering::Less {
if j == left {
break;
}
j -= 1;
}
if i >= j {
break;
}
arr.swap(i as usize, j as usize);
if compare(&arr[i as usize], &*v) == Ordering::Equal {
p += 1;
arr.swap(p as usize, i as usize)
}
if compare(&*v, &arr[j as usize]) == Ordering::Equal {
q -= 1;
arr.swap(j as usize, q as usize)
}
}
}
arr.swap(i as usize, right as usize);
j = i - 1;
i += 1;
let mut k: isize = left;
while k < p {
arr.swap(k as usize, j as usize);
k += 1;
j -= 1;
assert!(k < arr.len() as isize);
}
k = right - 1;
while k > q {
arr.swap(i as usize, k as usize);
k -= 1;
i += 1;
assert!(k != 0);
}
quicksort_helper(arr, left, j, compare);
quicksort_helper(arr, i, right, compare);
}
fn quicksort_by<T, F>(arr: &mut [T], compare: F)
where
F: Fn(&T, &T) -> Ordering,
{
if arr.len() <= 1 {
return;
}
let len = arr.len();
quicksort_helper(arr, 0, (len - 1) as isize, &compare);
}
#[ctor]
static TYPE_IDS: [(
TypeId,
for<'a> fn(&'a (dyn std::any::Any + 'static)) -> Primitive<'a>,
); 34] = {
let mut type_ids = type_ids![
usize,
u8,
u16,
u32,
u64,
u128,
isize,
i8,
i16,
i32,
i64,
i128,
f32,
f64,
char,
bool,
&'static str,
];
quicksort_by(&mut type_ids, |&(ref a, _), &(ref b, _)| a.cmp(b));
type_ids
};
if let Ok(i) = TYPE_IDS.binary_search_by_key(&value.type_id(), |&(k, _)| k) {
Some((TYPE_IDS[i].1)(value))
} else {
None
}
}
#[cfg(value_bag_capture_fallback)]
{
macro_rules! type_ids {
($($ty:ty,)*) => {
|value| {
$(
if let Some(value) = (value as &dyn std::any::Any).downcast_ref::<$ty>() {
return Some(Primitive::from(*value));
}
)*
$(
if let Some(value) = (value as &dyn std::any::Any).downcast_ref::<Option<$ty>>() {
if let Some(value) = value {
return Some(Primitive::from(*value));
} else {
return Some(Primitive::None);
}
}
)*
None
}
};
}
let type_ids = type_ids![
usize,
u8,
u16,
u32,
u64,
u128,
isize,
i8,
i16,
i32,
i64,
i128,
f32,
f64,
char,
bool,
&'static str,
];
(type_ids)(value)
}
}