rune/module/
variant_mut.rs

1use core::marker::PhantomData;
2
3use crate::compile::{ContextError, Docs};
4use crate::function::{Function, Plain};
5use crate::runtime::{FunctionHandler, TypeOf};
6
7use super::{Fields, TypeConstructor};
8
9/// Handle to a a variant inserted into a module which allows for mutation of
10/// its metadata.
11pub struct VariantMut<'a, T>
12where
13    T: ?Sized + TypeOf,
14{
15    pub(crate) name: &'static str,
16    pub(crate) docs: &'a mut Docs,
17    pub(crate) fields: &'a mut Option<Fields>,
18    pub(crate) constructor: &'a mut Option<TypeConstructor>,
19    pub(crate) _marker: PhantomData<T>,
20}
21
22impl<T> VariantMut<'_, T>
23where
24    T: ?Sized + TypeOf,
25{
26    /// Set documentation for an inserted type.
27    ///
28    /// This completely replaces any existing documentation.
29    pub fn docs(self, docs: impl IntoIterator<Item: AsRef<str>>) -> Result<Self, ContextError> {
30        self.docs.set_docs(docs)?;
31        Ok(self)
32    }
33
34    /// Set static documentation.
35    ///
36    /// This completely replaces any existing documentation.
37    pub fn static_docs(self, docs: &'static [&'static str]) -> Result<Self, ContextError> {
38        self.docs.set_docs(docs)?;
39        Ok(self)
40    }
41
42    /// Mark the given variant with named fields.
43    pub fn make_named(self, fields: &'static [&'static str]) -> Result<Self, ContextError> {
44        self.make(Fields::Named(fields))
45    }
46
47    /// Mark the given variant with unnamed fields.
48    pub fn make_unnamed(self, fields: usize) -> Result<Self, ContextError> {
49        self.make(Fields::Unnamed(fields))
50    }
51
52    /// Mark the given variant as empty.
53    pub fn make_empty(self) -> Result<Self, ContextError> {
54        self.make(Fields::Empty)
55    }
56
57    /// Register a constructor method for the current variant.
58    pub fn constructor<F, A>(self, constructor: F) -> Result<Self, ContextError>
59    where
60        F: Function<A, Plain, Return = T>,
61    {
62        if self.constructor.is_some() {
63            return Err(ContextError::VariantConstructorConflict {
64                type_info: T::type_info(),
65                name: self.name,
66            });
67        }
68
69        let handler = FunctionHandler::new(move |stack, addr, args, output| {
70            constructor.call(stack, addr, args, output)
71        })?;
72
73        *self.constructor = Some(TypeConstructor {
74            handler,
75            args: F::ARGS,
76        });
77
78        Ok(self)
79    }
80
81    fn make(self, fields: Fields) -> Result<Self, ContextError> {
82        let old = self.fields.replace(fields);
83
84        if old.is_some() {
85            return Err(ContextError::ConflictingVariantMeta {
86                type_info: T::type_info(),
87                name: self.name,
88            });
89        }
90
91        Ok(self)
92    }
93}