rune/runtime/
guarded_args.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
use crate::alloc::Vec;
use crate::runtime::Args;
use crate::runtime::{Stack, UnsafeToValue, Value, VmResult};

/// Trait for converting arguments onto the stack.
///
/// This can take references, because it is unsafe to call. And should only be
/// implemented in contexts where it can be guaranteed that the references will
/// not outlive the call.
pub trait GuardedArgs {
    /// Guard that when dropped will invalidate any values encoded.
    type Guard;

    /// Encode arguments onto a stack.
    ///
    /// # Safety
    ///
    /// This can encode references onto the stack. The caller must ensure that
    /// the guard is dropped before any references which have been encoded are
    /// no longer alive.
    unsafe fn guarded_into_stack(self, stack: &mut Stack) -> VmResult<Self::Guard>;

    /// Encode arguments into a vector.
    ///
    /// # Safety
    ///
    /// This can encode references into the vector. The caller must ensure that
    /// the guard is dropped before any references which have been encoded are
    /// no longer alive.
    unsafe fn guarded_into_vec(self) -> VmResult<(Vec<Value>, Self::Guard)>;

    /// The number of arguments.
    fn count(&self) -> usize;
}

macro_rules! impl_into_args {
    ($count:expr $(, $ty:ident $value:ident $_:expr)*) => {
        impl<$($ty,)*> GuardedArgs for ($($ty,)*)
        where
            $($ty: UnsafeToValue,)*
        {
            type Guard = ($($ty::Guard,)*);

            #[allow(unused)]
            #[inline]
            unsafe fn guarded_into_stack(self, stack: &mut Stack) -> VmResult<Self::Guard> {
                let ($($value,)*) = self;
                $(let $value = vm_try!($value.unsafe_to_value());)*
                $(vm_try!(stack.push($value.0));)*
                VmResult::Ok(($($value.1,)*))
            }

            #[allow(unused)]
            #[inline]
            unsafe fn guarded_into_vec(self) -> VmResult<(Vec<Value>, Self::Guard)> {
                let ($($value,)*) = self;
                $(let $value = vm_try!($value.unsafe_to_value());)*
                let mut out = vm_try!(Vec::try_with_capacity($count));
                $(vm_try!(out.try_push($value.0));)*
                VmResult::Ok((out, ($($value.1,)*)))
            }

            #[inline]
            fn count(&self) -> usize {
                $count
            }
        }
    };
}

repeat_macro!(impl_into_args);

impl GuardedArgs for Vec<Value> {
    type Guard = ();

    #[inline]
    unsafe fn guarded_into_stack(self, stack: &mut Stack) -> VmResult<Self::Guard> {
        self.into_stack(stack)
    }

    #[inline]
    unsafe fn guarded_into_vec(self) -> VmResult<(Vec<Value>, Self::Guard)> {
        VmResult::Ok((self, ()))
    }

    #[inline]
    fn count(&self) -> usize {
        (self as &dyn Args).count()
    }
}

#[cfg(feature = "alloc")]
impl GuardedArgs for ::rust_alloc::vec::Vec<Value> {
    type Guard = ();

    #[inline]
    unsafe fn guarded_into_stack(self, stack: &mut Stack) -> VmResult<Self::Guard> {
        self.into_stack(stack)
    }

    #[inline]
    unsafe fn guarded_into_vec(self) -> VmResult<(Vec<Value>, Self::Guard)> {
        VmResult::Ok((vm_try!(Vec::try_from(self)), ()))
    }

    #[inline]
    fn count(&self) -> usize {
        self.len()
    }
}