Skip to main content

rune/runtime/
function.rs

1use core::fmt;
2use core::future::Future;
3
4use crate as rune;
5use crate::alloc::fmt::TryWrite;
6use crate::alloc::prelude::*;
7use crate::alloc::{self, Box, Vec};
8use crate::function;
9use crate::runtime;
10use crate::runtime::vm::Isolated;
11use crate::shared::AssertSend;
12use crate::sync::Arc;
13use crate::{Any, Hash};
14
15use super::{
16    Address, AnySequence, Args, Call, ConstValue, Formatter, FromValue, FunctionHandler, Globals,
17    GuardedArgs, Output, OwnedTuple, Rtti, RuntimeContext, RuntimeError, Stack, Unit, Value, Vm,
18    VmCall, VmError, VmErrorKind, VmHalt,
19};
20
21/// The type of a function in Rune.
22///
23/// Functions can be called using call expression syntax, such as `<expr>()`.
24///
25/// There are multiple different kind of things which can be coerced into a
26/// function in Rune:
27/// * Regular functions.
28/// * Closures (which might or might not capture their environment).
29/// * Built-in constructors for tuple types (tuple structs, tuple variants).
30///
31/// # Examples
32///
33/// ```rune
34/// // Captures the constructor for the `Some(<value>)` tuple variant.
35/// let build_some = Some;
36/// assert_eq!(build_some(42), Some(42));
37///
38/// fn build(value) {
39///     Some(value)
40/// }
41///
42/// // Captures the function previously defined.
43/// let build_some = build;
44/// assert_eq!(build_some(42), Some(42));
45/// ```
46#[derive(Any, TryClone)]
47#[repr(transparent)]
48#[rune(item = ::std::ops)]
49pub struct Function(FunctionImpl<Value>);
50
51impl Function {
52    /// Construct a [Function] from a Rust closure.
53    ///
54    /// # Examples
55    ///
56    /// ```
57    /// use rune::{Hash, Vm};
58    /// use rune::runtime::Function;
59    /// use rune::sync::Arc;
60    ///
61    /// let mut sources = rune::sources! {
62    ///     entry => {
63    ///         pub fn main(function) {
64    ///             function(41)
65    ///         }
66    ///     }
67    /// };
68    ///
69    /// let unit = rune::prepare(&mut sources).build()?;
70    /// let unit = Arc::try_new(unit)?;
71    /// let mut vm = Vm::without_runtime(unit)?;
72    ///
73    /// let function = Function::new(|value: u32| value + 1)?;
74    ///
75    /// assert_eq!(function.type_hash(), Hash::EMPTY);
76    ///
77    /// let value = vm.call(["main"], (function,))?;
78    /// let value: u32 = rune::from_value(value)?;
79    /// assert_eq!(value, 42);
80    /// # Ok::<_, rune::support::Error>(())
81    /// ```
82    ///
83    /// Asynchronous functions:
84    ///
85    /// ```
86    /// use rune::{Hash, Vm};
87    /// use rune::runtime::Function;
88    /// use rune::sync::Arc;
89    ///
90    /// # futures_executor::block_on(async move {
91    /// let mut sources = rune::sources! {
92    ///     entry => {
93    ///         pub async fn main(function) {
94    ///             function(41).await
95    ///         }
96    ///     }
97    /// };
98    ///
99    /// let unit = rune::prepare(&mut sources).build()?;
100    /// let unit = Arc::try_new(unit)?;
101    /// let mut vm = Vm::without_runtime(unit)?;
102    ///
103    /// let function = Function::new(|value: u32| async move { value + 1 })?;
104    ///
105    /// assert_eq!(function.type_hash(), Hash::EMPTY);
106    ///
107    /// let value = vm.async_call(["main"], (function,)).await?;
108    /// let value: u32 = rune::from_value(value)?;
109    /// assert_eq!(value, 42);
110    /// # Ok::<_, rune::support::Error>(())
111    /// # })?;
112    /// # Ok::<_, rune::support::Error>(())
113    /// ```
114    pub fn new<F, A, K>(f: F) -> alloc::Result<Self>
115    where
116        F: function::Function<A, K>,
117        K: function::FunctionKind,
118    {
119        Ok(Self(FunctionImpl {
120            inner: Inner::FnHandler(FnHandler {
121                handler: FunctionHandler::new(move |stack, addr, args, output| {
122                    f.call(stack, addr, args, output)
123                })?,
124                hash: Hash::EMPTY,
125            }),
126        }))
127    }
128
129    /// Perform an asynchronous call over the function which also implements
130    /// [Send].
131    pub async fn async_send_call<A, T>(&self, args: A) -> Result<T, VmError>
132    where
133        A: Send + GuardedArgs,
134        T: Send + FromValue,
135    {
136        self.0.async_send_call(args).await
137    }
138
139    /// Perform a call over the function represented by this function pointer.
140    ///
141    /// # Examples
142    ///
143    /// ```
144    /// use rune::{Hash, Vm};
145    /// use rune::runtime::Function;
146    /// use rune::sync::Arc;
147    ///
148    /// let mut sources = rune::sources! {
149    ///     entry => {
150    ///         fn add(a, b) {
151    ///             a + b
152    ///         }
153    ///
154    ///         pub fn main() { add }
155    ///     }
156    /// };
157    ///
158    /// let unit = rune::prepare(&mut sources).build()?;
159    /// let unit = Arc::try_new(unit)?;
160    /// let mut vm = Vm::without_runtime(unit)?;
161    ///
162    /// let value = vm.call(["main"], ())?;
163    ///
164    /// let value: Function = rune::from_value(value)?;
165    /// assert_eq!(value.call::<u32>((1, 2))?, 3);
166    /// # Ok::<_, rune::support::Error>(())
167    /// ```
168    pub fn call<T>(&self, args: impl GuardedArgs) -> Result<T, VmError>
169    where
170        T: FromValue,
171    {
172        self.0.call(args)
173    }
174
175    /// Call with the given virtual machine. This allows for certain
176    /// optimizations, like avoiding the allocation of a new vm state in case
177    /// the call is internal.
178    ///
179    /// A stop reason will be returned in case the function call results in
180    /// a need to suspend the execution.
181    pub(crate) fn call_with_vm(
182        &self,
183        vm: &mut Vm,
184        addr: Address,
185        args: usize,
186        out: Output,
187    ) -> Result<Option<VmHalt>, VmError> {
188        self.0.call_with_vm(vm, addr, args, out)
189    }
190
191    /// Create a function pointer from a handler.
192    pub(crate) fn from_handler(handler: FunctionHandler, hash: Hash) -> Self {
193        Self(FunctionImpl::from_handler(handler, hash))
194    }
195
196    /// Create a function pointer from an offset.
197    pub(crate) fn from_vm_offset(
198        context: Arc<RuntimeContext>,
199        unit: Arc<Unit>,
200        globals: Globals,
201        offset: usize,
202        call: Call,
203        args: usize,
204        hash: Hash,
205    ) -> Self {
206        Self(FunctionImpl::from_offset(
207            context, unit, globals, offset, call, args, hash,
208        ))
209    }
210
211    /// Create a function pointer from an offset.
212    pub(crate) fn from_vm_closure(
213        context: Arc<RuntimeContext>,
214        unit: Arc<Unit>,
215        globals: Globals,
216        offset: usize,
217        call: Call,
218        args: usize,
219        environment: Box<[Value]>,
220        hash: Hash,
221    ) -> Self {
222        Self(FunctionImpl::from_closure(
223            context,
224            unit,
225            globals,
226            offset,
227            call,
228            args,
229            environment,
230            hash,
231        ))
232    }
233
234    /// Create a function pointer from an offset.
235    pub(crate) fn from_unit_struct(rtti: Arc<Rtti>) -> Self {
236        Self(FunctionImpl::from_unit_struct(rtti))
237    }
238
239    /// Create a function pointer from an offset.
240    pub(crate) fn from_tuple_struct(rtti: Arc<Rtti>, args: usize) -> Self {
241        Self(FunctionImpl::from_tuple_struct(rtti, args))
242    }
243
244    /// Type [Hash][struct@Hash] of the underlying function.
245    ///
246    /// # Examples
247    ///
248    /// The type hash of a top-level function matches what you get out of
249    /// [Hash::type_hash].
250    ///
251    /// ```
252    /// use rune::runtime::Function;
253    /// use rune::sync::Arc;
254    /// use rune::{Hash, Vm};
255    ///
256    /// let mut sources = rune::sources! {
257    ///     entry => {
258    ///         fn pony() { }
259    ///
260    ///         pub fn main() { pony }
261    ///     }
262    /// };
263    ///
264    /// let unit = rune::prepare(&mut sources).build()?;
265    /// let unit = Arc::try_new(unit)?;
266    /// let mut vm = Vm::without_runtime(unit)?;
267    ///
268    /// let pony = vm.call(["main"], ())?;
269    /// let pony: Function = rune::from_value(pony)?;
270    ///
271    /// assert_eq!(pony.type_hash(), Hash::type_hash(["pony"]));
272    /// # Ok::<_, rune::support::Error>(())
273    /// ```
274    pub fn type_hash(&self) -> Hash {
275        self.0.type_hash()
276    }
277
278    /// Try to convert into a [SyncFunction]. This might not be possible if this
279    /// function is something which is not [Sync], like a closure capturing
280    /// context which is not thread-safe.
281    ///
282    /// # Examples
283    ///
284    /// ```
285    /// use rune::{Hash, Vm};
286    /// use rune::runtime::Function;
287    /// use rune::sync::Arc;
288    ///
289    /// let mut sources = rune::sources! {
290    ///     entry => {
291    ///         fn pony() { }
292    ///
293    ///         pub fn main() { pony }
294    ///     }
295    /// };
296    ///
297    /// let unit = rune::prepare(&mut sources).build()?;
298    /// let unit = Arc::try_new(unit)?;
299    /// let mut vm = Vm::without_runtime(unit)?;
300    ///
301    /// let pony = vm.call(["main"], ())?;
302    /// let pony: Function = rune::from_value(pony)?;
303    ///
304    /// // This is fine, since `pony` is a free function.
305    /// let pony = pony.into_sync()?;
306    ///
307    /// assert_eq!(pony.type_hash(), Hash::type_hash(["pony"]));
308    /// # Ok::<_, rune::support::Error>(())
309    /// ```
310    ///
311    /// The following *does not* work, because we return a closure which tries
312    /// to make use of a [Generator][crate::runtime::Generator] which is not a
313    /// constant value.
314    ///
315    /// ```
316    /// use rune::runtime::Function;
317    /// use rune::sync::Arc;
318    /// use rune::{Hash, Vm};
319    ///
320    /// let mut sources = rune::sources! {
321    ///     entry => {
322    ///         fn generator() {
323    ///             yield 42;
324    ///         }
325    ///
326    ///         pub fn main() {
327    ///             let g = generator();
328    ///
329    ///             move || {
330    ///                 g.next()
331    ///             }
332    ///         }
333    ///     }
334    /// };
335    ///
336    /// let unit = rune::prepare(&mut sources).build()?;
337    /// let unit = Arc::try_new(unit)?;
338    /// let mut vm = Vm::without_runtime(unit)?;
339    ///
340    /// let closure = vm.call(["main"], ())?;
341    /// let closure: Function = rune::from_value(closure)?;
342    ///
343    /// // This is *not* fine since the returned closure has captured a
344    /// // generator which is not a constant value.
345    /// assert!(closure.into_sync().is_err());
346    /// # Ok::<_, rune::support::Error>(())
347    /// ```
348    pub fn into_sync(self) -> Result<SyncFunction, RuntimeError> {
349        Ok(SyncFunction(self.0.into_sync()?))
350    }
351
352    /// Clone a function.
353    ///
354    /// # Examples
355    ///
356    /// ```rune
357    /// fn function() {
358    ///     42
359    /// }
360    ///
361    /// let a = function;
362    /// let b = a.clone();
363    /// assert_eq!(a(), b());
364    /// ```
365    #[rune::function(keep, protocol = CLONE)]
366    fn clone(&self) -> Result<Function, VmError> {
367        Ok(self.try_clone()?)
368    }
369
370    /// Debug format a function.
371    ///
372    /// # Examples
373    ///
374    /// ```rune
375    /// fn function() {
376    ///     42
377    /// }
378    ///
379    /// println!("{function:?}");
380    /// ``
381    #[rune::function(keep, protocol = DEBUG_FMT)]
382    fn debug_fmt(&self, f: &mut Formatter) -> alloc::Result<()> {
383        write!(f, "{self:?}")
384    }
385}
386
387/// A callable sync function. This currently only supports a subset of values
388/// that are supported by the Vm.
389#[repr(transparent)]
390pub struct SyncFunction(FunctionImpl<ConstValue>);
391
392assert_impl!(SyncFunction: Send + Sync);
393
394impl SyncFunction {
395    /// Perform an asynchronous call over the function which also implements
396    /// [Send].
397    ///
398    /// # Examples
399    ///
400    /// ```
401    /// use rune::runtime::SyncFunction;
402    /// use rune::sync::Arc;
403    /// use rune::{Hash, Vm};
404    ///
405    /// # futures_executor::block_on(async move {
406    /// let mut sources = rune::sources! {
407    ///     entry => {
408    ///         async fn add(a, b) {
409    ///             a + b
410    ///         }
411    ///
412    ///         pub fn main() { add }
413    ///     }
414    /// };
415    ///
416    /// let unit = rune::prepare(&mut sources).build()?;
417    /// let unit = Arc::try_new(unit)?;
418    /// let mut vm = Vm::without_runtime(unit)?;
419    ///
420    /// let add = vm.call(["main"], ())?;
421    /// let add: SyncFunction = rune::from_value(add)?;
422    ///
423    /// let value = add.async_send_call::<u32>((1, 2)).await?;
424    /// assert_eq!(value, 3);
425    /// # Ok::<_, rune::support::Error>(())
426    /// # })?;
427    /// # Ok::<_, rune::support::Error>(())
428    /// ```
429    pub async fn async_send_call<T>(&self, args: impl GuardedArgs + Send) -> Result<T, VmError>
430    where
431        T: Send + FromValue,
432    {
433        self.0.async_send_call(args).await
434    }
435
436    /// Perform a call over the function represented by this function pointer.
437    ///
438    /// # Examples
439    ///
440    /// ```
441    /// use rune::runtime::SyncFunction;
442    /// use rune::sync::Arc;
443    /// use rune::{Hash, Vm};
444    ///
445    /// let mut sources = rune::sources! {
446    ///     entry => {
447    ///         fn add(a, b) {
448    ///             a + b
449    ///         }
450    ///
451    ///         pub fn main() { add }
452    ///     }
453    /// };
454    ///
455    /// let unit = rune::prepare(&mut sources).build()?;
456    /// let unit = Arc::try_new(unit)?;
457    /// let mut vm = Vm::without_runtime(unit)?;
458    ///
459    /// let add = vm.call(["main"], ())?;
460    /// let add: SyncFunction = rune::from_value(add)?;
461    ///
462    /// assert_eq!(add.call::<u32>((1, 2))?, 3);
463    /// # Ok::<_, rune::support::Error>(())
464    /// ```
465    pub fn call<T>(&self, args: impl GuardedArgs) -> Result<T, VmError>
466    where
467        T: FromValue,
468    {
469        self.0.call(args)
470    }
471
472    /// Type [Hash][struct@Hash] of the underlying function.
473    ///
474    /// # Examples
475    ///
476    /// The type hash of a top-level function matches what you get out of
477    /// [Hash::type_hash].
478    ///
479    /// ```
480    /// use rune::runtime::SyncFunction;
481    /// use rune::sync::Arc;
482    /// use rune::{Hash, Vm};
483    ///
484    /// let mut sources = rune::sources! {
485    ///     entry => {
486    ///         fn pony() { }
487    ///
488    ///         pub fn main() { pony }
489    ///     }
490    /// };
491    ///
492    /// let unit = rune::prepare(&mut sources).build()?;
493    /// let unit = Arc::try_new(unit)?;
494    /// let mut vm = Vm::without_runtime(unit)?;
495    ///
496    /// let pony = vm.call(["main"], ())?;
497    /// let pony: SyncFunction = rune::from_value(pony)?;
498    ///
499    /// assert_eq!(pony.type_hash(), Hash::type_hash(["pony"]));
500    /// # Ok::<_, rune::support::Error>(())
501    /// ```
502    pub fn type_hash(&self) -> Hash {
503        self.0.type_hash()
504    }
505}
506
507impl TryClone for SyncFunction {
508    fn try_clone(&self) -> alloc::Result<Self> {
509        Ok(Self(self.0.try_clone()?))
510    }
511}
512
513/// A stored function, of some specific kind.
514struct FunctionImpl<V>
515where
516    V: FnValue,
517{
518    inner: Inner<V>,
519}
520
521impl<V> TryClone for FunctionImpl<V>
522where
523    V: FnValue,
524{
525    #[inline]
526    fn try_clone(&self) -> alloc::Result<Self> {
527        Ok(Self {
528            inner: self.inner.try_clone()?,
529        })
530    }
531}
532
533impl<V> FunctionImpl<V>
534where
535    V: FnValue,
536    OwnedTuple: TryFrom<Box<[V]>>,
537    VmErrorKind: From<<OwnedTuple as TryFrom<Box<[V]>>>::Error>,
538{
539    fn call<T>(&self, args: impl GuardedArgs) -> Result<T, VmError>
540    where
541        T: FromValue,
542    {
543        let value = match &self.inner {
544            Inner::FnHandler(handler) => {
545                let count = args.count();
546                let size = count.max(1);
547                // Ensure we have space for the return value.
548                let mut stack = Stack::with_capacity(size)?;
549                let _guard = unsafe { args.guarded_into_stack(&mut stack) }?;
550                stack.resize(size)?;
551                handler
552                    .handler
553                    .call(&mut stack, Address::ZERO, count, Address::ZERO.output())?;
554                stack.at(Address::ZERO).clone()
555            }
556            Inner::FnOffset(fn_offset) => fn_offset.call(args, ())?,
557            Inner::FnClosureOffset(closure) => {
558                let environment = closure.environment.try_clone()?;
559                let environment = OwnedTuple::try_from(environment)?;
560                closure.fn_offset.call(args, (environment,))?
561            }
562            Inner::FnUnitStruct(empty) => {
563                check_args(args.count(), 0)?;
564                Value::empty_struct(empty.rtti.clone())?
565            }
566            Inner::FnTupleStruct(tuple) => {
567                check_args(args.count(), tuple.args)?;
568                // SAFETY: We don't let the guard outlive the value.
569                let (args, _guard) = unsafe { args.guarded_into_vec()? };
570                Value::tuple_struct(tuple.rtti.clone(), args)?
571            }
572        };
573
574        Ok(T::from_value(value)?)
575    }
576
577    fn async_send_call<'a, A, T>(
578        &'a self,
579        args: A,
580    ) -> impl Future<Output = Result<T, VmError>> + Send + 'a
581    where
582        A: 'a + Send + GuardedArgs,
583        T: 'a + Send + FromValue,
584    {
585        let future = async move {
586            let value: Value = self.call(args)?;
587
588            let value = match value.try_borrow_mut::<runtime::Future>()? {
589                Some(future) => future.await?,
590                None => value,
591            };
592
593            Ok(T::from_value(value)?)
594        };
595
596        // Safety: Future is send because there is no way to call this
597        // function in a manner which allows any values from the future
598        // to escape outside of this future, hence it can only be
599        // scheduled by one thread at a time.
600        unsafe { AssertSend::new(future) }
601    }
602
603    /// Call with the given virtual machine. This allows for certain
604    /// optimizations, like avoiding the allocation of a new vm state in case
605    /// the call is internal.
606    ///
607    /// A stop reason will be returned in case the function call results in
608    /// a need to suspend the execution.
609    pub(crate) fn call_with_vm(
610        &self,
611        vm: &mut Vm,
612        addr: Address,
613        args: usize,
614        out: Output,
615    ) -> Result<Option<VmHalt>, VmError> {
616        let reason = match &self.inner {
617            Inner::FnHandler(handler) => {
618                handler.handler.call(vm.stack_mut(), addr, args, out)?;
619                None
620            }
621            Inner::FnOffset(fn_offset) => {
622                if let Some(vm_call) = fn_offset.call_with_vm(vm, addr, args, (), out)? {
623                    return Ok(Some(VmHalt::VmCall(vm_call)));
624                }
625
626                None
627            }
628            Inner::FnClosureOffset(closure) => {
629                let environment = closure.environment.try_clone()?;
630                let environment = OwnedTuple::try_from(environment)?;
631
632                if let Some(vm_call) =
633                    closure
634                        .fn_offset
635                        .call_with_vm(vm, addr, args, (environment,), out)?
636                {
637                    return Ok(Some(VmHalt::VmCall(vm_call)));
638                }
639
640                None
641            }
642            Inner::FnUnitStruct(empty) => {
643                check_args(args, 0)?;
644                vm.stack_mut()
645                    .store(out, || Value::empty_struct(empty.rtti.clone()))?;
646                None
647            }
648            Inner::FnTupleStruct(tuple) => {
649                check_args(args, tuple.args)?;
650
651                let seq = vm.stack().slice_at(addr, args)?;
652                let data = seq.iter().cloned();
653                let value = AnySequence::new(tuple.rtti.clone(), data)?;
654                vm.stack_mut().store(out, value)?;
655                None
656            }
657        };
658
659        Ok(reason)
660    }
661
662    /// Create a function pointer from a handler.
663    pub(crate) fn from_handler(handler: FunctionHandler, hash: Hash) -> Self {
664        Self {
665            inner: Inner::FnHandler(FnHandler { handler, hash }),
666        }
667    }
668
669    /// Create a function pointer from an offset.
670    pub(crate) fn from_offset(
671        context: Arc<RuntimeContext>,
672        unit: Arc<Unit>,
673        globals: V::Globals,
674        offset: usize,
675        call: Call,
676        args: usize,
677        hash: Hash,
678    ) -> Self {
679        Self {
680            inner: Inner::FnOffset(FnOffset {
681                context,
682                unit,
683                globals,
684                offset,
685                call,
686                args,
687                hash,
688            }),
689        }
690    }
691
692    /// Create a function pointer from an offset.
693    pub(crate) fn from_closure(
694        context: Arc<RuntimeContext>,
695        unit: Arc<Unit>,
696        globals: V::Globals,
697        offset: usize,
698        call: Call,
699        args: usize,
700        environment: Box<[V]>,
701        hash: Hash,
702    ) -> Self {
703        Self {
704            inner: Inner::FnClosureOffset(FnClosureOffset {
705                fn_offset: FnOffset {
706                    context,
707                    unit,
708                    globals,
709                    offset,
710                    call,
711                    args,
712                    hash,
713                },
714                environment,
715            }),
716        }
717    }
718
719    /// Create a function pointer from an offset.
720    pub(crate) fn from_unit_struct(rtti: Arc<Rtti>) -> Self {
721        Self {
722            inner: Inner::FnUnitStruct(FnUnitStruct { rtti }),
723        }
724    }
725
726    /// Create a function pointer from an offset.
727    pub(crate) fn from_tuple_struct(rtti: Arc<Rtti>, args: usize) -> Self {
728        Self {
729            inner: Inner::FnTupleStruct(FnTupleStruct { rtti, args }),
730        }
731    }
732
733    #[inline]
734    fn type_hash(&self) -> Hash {
735        match &self.inner {
736            Inner::FnHandler(FnHandler { hash, .. }) | Inner::FnOffset(FnOffset { hash, .. }) => {
737                *hash
738            }
739            Inner::FnClosureOffset(fco) => fco.fn_offset.hash,
740            Inner::FnUnitStruct(func) => func.rtti.type_hash(),
741            Inner::FnTupleStruct(func) => func.rtti.type_hash(),
742        }
743    }
744}
745
746impl FunctionImpl<Value> {
747    /// Try to convert into a [SyncFunction].
748    fn into_sync(self) -> Result<FunctionImpl<ConstValue>, RuntimeError> {
749        let inner = match self.inner {
750            Inner::FnClosureOffset(closure) => {
751                let mut env = Vec::try_with_capacity(closure.environment.len())?;
752
753                for value in Vec::from(closure.environment) {
754                    env.try_push(FromValue::from_value(value)?)?;
755                }
756
757                Inner::FnClosureOffset(FnClosureOffset {
758                    fn_offset: closure.fn_offset.into_sync(),
759                    environment: env.try_into_boxed_slice()?,
760                })
761            }
762            Inner::FnHandler(inner) => Inner::FnHandler(inner),
763            Inner::FnOffset(inner) => Inner::FnOffset(inner.into_sync()),
764            Inner::FnUnitStruct(inner) => Inner::FnUnitStruct(inner),
765            Inner::FnTupleStruct(inner) => Inner::FnTupleStruct(inner),
766        };
767
768        Ok(FunctionImpl { inner })
769    }
770}
771
772impl fmt::Debug for Function {
773    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
774        match &self.0.inner {
775            Inner::FnHandler(handler) => {
776                write!(f, "native function ({:p})", handler.handler)?;
777            }
778            Inner::FnOffset(offset) => {
779                write!(f, "{} function (at: 0x{:x})", offset.call, offset.offset)?;
780            }
781            Inner::FnClosureOffset(closure) => {
782                write!(
783                    f,
784                    "closure (at: 0x{:x}, env:{:?})",
785                    closure.fn_offset.offset, closure.environment
786                )?;
787            }
788            Inner::FnUnitStruct(empty) => {
789                write!(f, "empty {}", empty.rtti.item)?;
790            }
791            Inner::FnTupleStruct(tuple) => {
792                write!(f, "tuple {}", tuple.rtti.item)?;
793            }
794        }
795
796        Ok(())
797    }
798}
799
800#[derive(Debug)]
801enum Inner<V>
802where
803    V: FnValue,
804{
805    /// A native function handler.
806    /// This is wrapped as an `Arc<dyn FunctionHandler>`.
807    FnHandler(FnHandler),
808    /// The offset to a free function.
809    ///
810    /// This also captures the context and unit it belongs to allow for external
811    /// calls.
812    FnOffset(FnOffset<V>),
813    /// A closure with a captured environment.
814    ///
815    /// This also captures the context and unit it belongs to allow for external
816    /// calls.
817    FnClosureOffset(FnClosureOffset<V>),
818    /// Constructor for a unit struct.
819    FnUnitStruct(FnUnitStruct),
820    /// Constructor for a tuple.
821    FnTupleStruct(FnTupleStruct),
822}
823
824impl<V> TryClone for Inner<V>
825where
826    V: FnValue,
827{
828    fn try_clone(&self) -> alloc::Result<Self> {
829        Ok(match self {
830            Inner::FnHandler(inner) => Inner::FnHandler(inner.clone()),
831            Inner::FnOffset(inner) => Inner::FnOffset(inner.clone()),
832            Inner::FnClosureOffset(inner) => Inner::FnClosureOffset(inner.try_clone()?),
833            Inner::FnUnitStruct(inner) => Inner::FnUnitStruct(inner.clone()),
834            Inner::FnTupleStruct(inner) => Inner::FnTupleStruct(inner.clone()),
835        })
836    }
837}
838
839#[derive(Clone, TryClone)]
840struct FnHandler {
841    /// The function handler.
842    handler: FunctionHandler,
843    /// Hash for the function type
844    hash: Hash,
845}
846
847impl fmt::Debug for FnHandler {
848    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
849        write!(f, "FnHandler")
850    }
851}
852
853/// The kind of value a function closes over, and with it the kind of static
854/// item storage the function is able to carry.
855///
856/// A [`Function`] carries the [`Globals`] of the virtual machine which produced
857/// it, so that calling it from the outside still observes the same statics. A
858/// [`SyncFunction`] can be sent between threads and the storage isn't thread
859/// safe, so it carries nothing.
860pub(crate) trait FnValue: TryClone {
861    /// How static item storage is represented for this kind of function.
862    type Globals: TryClone + Clone;
863
864    /// Materialize the storage a virtual machine should be given.
865    fn globals(globals: &Self::Globals) -> Globals;
866
867    /// Test if the given vm already uses this storage.
868    fn same_globals(globals: &Self::Globals, vm: &Vm) -> bool;
869}
870
871impl FnValue for Value {
872    type Globals = Globals;
873
874    #[inline]
875    fn globals(globals: &Self::Globals) -> Globals {
876        globals.clone()
877    }
878
879    #[inline]
880    fn same_globals(globals: &Self::Globals, vm: &Vm) -> bool {
881        vm.is_same_globals(globals)
882    }
883}
884
885impl FnValue for ConstValue {
886    type Globals = ();
887
888    #[inline]
889    fn globals(_: &Self::Globals) -> Globals {
890        Globals::empty()
891    }
892
893    #[inline]
894    fn same_globals(_: &Self::Globals, vm: &Vm) -> bool {
895        !vm.globals().is_configured()
896    }
897}
898
899struct FnOffset<V>
900where
901    V: FnValue,
902{
903    context: Arc<RuntimeContext>,
904    /// The unit where the function resides.
905    unit: Arc<Unit>,
906    /// The storage for static items declared by the unit.
907    globals: V::Globals,
908    /// The offset of the function.
909    offset: usize,
910    /// The calling convention.
911    call: Call,
912    /// The number of arguments the function takes.
913    args: usize,
914    /// Hash for the function type
915    hash: Hash,
916}
917
918impl<V> Clone for FnOffset<V>
919where
920    V: FnValue,
921{
922    fn clone(&self) -> Self {
923        Self {
924            context: self.context.clone(),
925            unit: self.unit.clone(),
926            globals: self.globals.clone(),
927            offset: self.offset,
928            call: self.call,
929            args: self.args,
930            hash: self.hash,
931        }
932    }
933}
934
935impl<V> TryClone for FnOffset<V>
936where
937    V: FnValue,
938{
939    #[inline]
940    fn try_clone(&self) -> alloc::Result<Self> {
941        Ok(self.clone())
942    }
943}
944
945impl<V> FnOffset<V>
946where
947    V: FnValue,
948{
949    /// Perform a call into the specified offset and return the produced value.
950    #[tracing::instrument(skip_all, fields(args = args.count(), extra = extra.count(), ?self.offset, ?self.call, ?self.args, ?self.hash))]
951    fn call(&self, args: impl GuardedArgs, extra: impl Args) -> Result<Value, VmError> {
952        check_args(args.count().wrapping_add(extra.count()), self.args)?;
953
954        let mut vm = Vm::new(self.context.clone(), self.unit.clone())
955            .with_globals(V::globals(&self.globals));
956
957        vm.set_ip(self.offset);
958        let _guard = unsafe { args.guarded_into_stack(vm.stack_mut())? };
959        extra.into_stack(vm.stack_mut())?;
960
961        self.call.call_with_vm(vm)
962    }
963
964    /// Perform a potentially optimized call into the specified vm.
965    ///
966    /// This will cause a halt in case the vm being called into isn't the same
967    /// as the context and unit of the function.
968    #[tracing::instrument(skip_all, fields(args, extra = extra.count(), keep, ?self.offset, ?self.call, ?self.args, ?self.hash))]
969    fn call_with_vm(
970        &self,
971        vm: &mut Vm,
972        addr: Address,
973        args: usize,
974        extra: impl Args,
975        out: Output,
976    ) -> Result<Option<VmCall>, VmError> {
977        check_args(args.wrapping_add(extra.count()), self.args)?;
978
979        let same_unit = matches!(self.call, Call::Immediate if vm.is_same_unit(&self.unit));
980        let same_context =
981            matches!(self.call, Call::Immediate if vm.is_same_context(&self.context));
982        let same_globals =
983            matches!(self.call, Call::Immediate if V::same_globals(&self.globals, vm));
984
985        vm.push_call_frame(self.offset, addr, args, Isolated::new(!same_context), out)?;
986        extra.into_stack(vm.stack_mut())?;
987
988        // Fast path, just allocate a call frame and keep running.
989        if same_context && same_unit && same_globals {
990            tracing::trace!("same context, unit and globals");
991            return Ok(None);
992        }
993
994        let call = VmCall::new(
995            self.call,
996            (!same_context).then(|| self.context.clone()),
997            (!same_unit).then(|| self.unit.clone()),
998            (!same_globals).then(|| V::globals(&self.globals)),
999            out,
1000        );
1001
1002        Ok(Some(call))
1003    }
1004}
1005
1006impl FnOffset<Value> {
1007    /// Shed the static item storage so that the function can be sent between
1008    /// threads.
1009    ///
1010    /// The storage isn't thread safe, so a [`SyncFunction`] cannot carry it.
1011    /// Reading a static through the resulting function reports that no storage
1012    /// has been configured.
1013    fn into_sync(self) -> FnOffset<ConstValue> {
1014        FnOffset {
1015            context: self.context,
1016            unit: self.unit,
1017            globals: (),
1018            offset: self.offset,
1019            call: self.call,
1020            args: self.args,
1021            hash: self.hash,
1022        }
1023    }
1024}
1025
1026impl<V> fmt::Debug for FnOffset<V>
1027where
1028    V: FnValue,
1029{
1030    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1031        f.debug_struct("FnOffset")
1032            .field("context", &(&self.context as *const _))
1033            .field("unit", &(&self.unit as *const _))
1034            .field("offset", &self.offset)
1035            .field("call", &self.call)
1036            .field("args", &self.args)
1037            .finish()
1038    }
1039}
1040
1041#[derive(Debug)]
1042struct FnClosureOffset<V>
1043where
1044    V: FnValue,
1045{
1046    /// The offset in the associated unit that the function lives.
1047    fn_offset: FnOffset<V>,
1048    /// Captured environment.
1049    environment: Box<[V]>,
1050}
1051
1052impl<V> TryClone for FnClosureOffset<V>
1053where
1054    V: FnValue,
1055{
1056    #[inline]
1057    fn try_clone(&self) -> alloc::Result<Self> {
1058        Ok(Self {
1059            fn_offset: self.fn_offset.clone(),
1060            environment: self.environment.try_clone()?,
1061        })
1062    }
1063}
1064
1065#[derive(Debug, Clone, TryClone)]
1066struct FnUnitStruct {
1067    /// The type of the empty.
1068    rtti: Arc<Rtti>,
1069}
1070
1071#[derive(Debug, Clone, TryClone)]
1072struct FnTupleStruct {
1073    /// The type of the tuple.
1074    rtti: Arc<Rtti>,
1075    /// The number of arguments the tuple takes.
1076    args: usize,
1077}
1078
1079impl FromValue for SyncFunction {
1080    #[inline]
1081    fn from_value(value: Value) -> Result<Self, RuntimeError> {
1082        value.downcast::<Function>()?.into_sync()
1083    }
1084}
1085
1086#[inline]
1087fn check_args(actual: usize, expected: usize) -> Result<(), VmError> {
1088    if actual != expected {
1089        return Err(VmError::new(VmErrorKind::BadArgumentCount {
1090            expected,
1091            actual,
1092        }));
1093    }
1094
1095    Ok(())
1096}