Improve reify syntax.

This commit is contained in:
Stephen Chung
2022-02-08 09:25:53 +08:00
parent f8cee0fe4e
commit 97a8fd3d5b
5 changed files with 184 additions and 174 deletions

View File

@@ -46,11 +46,13 @@ impl<'a> ArgBackup<'a> {
/// This function replaces the first argument of a method call with a clone copy.
/// This is to prevent a pure function unintentionally consuming the first argument.
///
/// `restore_first_arg` must be called before the end of the scope to prevent the shorter lifetime from leaking.
/// `restore_first_arg` must be called before the end of the scope to prevent the shorter
/// lifetime from leaking.
///
/// # Safety
///
/// This method blindly casts a reference to another lifetime, which saves allocation and string cloning.
/// This method blindly casts a reference to another lifetime, which saves allocation and
/// string cloning.
///
/// As long as `restore_first_arg` is called before the end of the scope, the shorter lifetime
/// will not leak.
@@ -71,8 +73,8 @@ impl<'a> ArgBackup<'a> {
// Blindly casting a reference to another lifetime saves allocation and string cloning,
// but must be used with the utmost care.
//
// We can do this here because, before the end of this scope, we'd restore the original reference
// via `restore_first_arg`. Therefore this shorter lifetime does not leak.
// We can do this here because, before the end of this scope, we'd restore the original
// reference via `restore_first_arg`. Therefore this shorter lifetime does not leak.
self.orig_mut = Some(mem::replace(&mut args[0], unsafe {
mem::transmute(&mut self.value_copy)
}));
@@ -81,8 +83,8 @@ impl<'a> ArgBackup<'a> {
///
/// # Safety
///
/// If `change_first_arg_to_copy` has been called, this function **MUST** be called _BEFORE_ exiting
/// the current scope. Otherwise it is undefined behavior as the shorter lifetime will leak.
/// If `change_first_arg_to_copy` has been called, this function **MUST** be called _BEFORE_
/// exiting the current scope. Otherwise it is undefined behavior as the shorter lifetime will leak.
#[inline(always)]
fn restore_first_arg(mut self, args: &mut FnCallArgs<'a>) {
if let Some(p) = self.orig_mut.take() {

View File

@@ -38,25 +38,26 @@ pub fn by_ref<T: Variant + Clone>(data: &mut Dynamic) -> DynamicWriteLock<T> {
}
/// Dereference into value.
#[inline]
#[inline(always)]
#[must_use]
pub fn by_value<T: Variant + Clone>(data: &mut Dynamic) -> T {
if TypeId::of::<T>() == TypeId::of::<&str>() {
// If T is `&str`, data must be `ImmutableString`, so map directly to it
data.flatten_in_place();
let ref_str = data.as_str_ref().expect("&str");
//let ref_t = reify!(&ref_str, |ref_t: &T| ref_t, || unreachable!());
let ref_t = unsafe { mem::transmute::<_, &T>(&ref_str) };
ref_t.clone()
} else if TypeId::of::<T>() == TypeId::of::<String>() {
// If T is `String`, data must be `ImmutableString`, so map directly to it
let t = mem::take(data).into_string().expect("`ImmutableString`");
reify!(t, |t: T| t, || unreachable!())
} else {
// We consume the argument and then replace it with () - the argument is not supposed to be used again.
// This way, we avoid having to clone the argument again, because it is already a clone when passed here.
mem::take(data).cast::<T>()
// # Safety
//
// We already checked that `T` is `&str`, so it is safe to cast here.
return unsafe { std::mem::transmute_copy::<_, T>(&ref_str) };
}
if TypeId::of::<T>() == TypeId::of::<String>() {
// If T is `String`, data must be `ImmutableString`, so map directly to it
return reify!(mem::take(data).into_string().expect("`ImmutableString`") => T);
}
// We consume the argument and then replace it with () - the argument is not supposed to be used again.
// This way, we avoid having to clone the argument again, because it is already a clone when passed here.
return mem::take(data).cast::<T>();
}
/// Trait to register custom Rust functions.