Skip to main content

harn_vm/vm/
builtin.rs

1use std::borrow::Cow;
2
3use harn_builtin_meta::{BuiltinContract, BuiltinExposure};
4
5/// Runtime kind for a registered VM builtin.
6#[derive(Clone, Copy, Debug, PartialEq, Eq)]
7pub enum VmBuiltinKind {
8    Sync,
9    Async,
10}
11
12/// Lightweight arity metadata for registered builtins.
13///
14/// This is descriptive metadata only. Runtime behavior still flows through
15/// the existing parser/typechecker and builtin handlers.
16#[derive(Clone, Copy, Debug, PartialEq, Eq)]
17pub enum VmBuiltinArity {
18    Exact(usize),
19    Min(usize),
20    Range { min: usize, max: usize },
21    Variadic,
22}
23
24/// Discoverable metadata for a VM builtin.
25#[derive(Clone, Debug, PartialEq, Eq)]
26pub struct VmBuiltinMetadata {
27    name: Cow<'static, str>,
28    kind: VmBuiltinKind,
29    signature: Option<Cow<'static, str>>,
30    arity: Option<VmBuiltinArity>,
31    category: Option<Cow<'static, str>>,
32    doc: Option<Cow<'static, str>>,
33    contract: BuiltinContract,
34}
35
36impl VmBuiltinMetadata {
37    pub fn sync(name: impl Into<Cow<'static, str>>) -> Self {
38        Self::new(name, VmBuiltinKind::Sync)
39    }
40
41    pub fn async_builtin(name: impl Into<Cow<'static, str>>) -> Self {
42        Self::new(name, VmBuiltinKind::Async)
43    }
44
45    pub const fn sync_static(name: &'static str) -> Self {
46        Self::new_static(name, VmBuiltinKind::Sync)
47    }
48
49    pub const fn async_static(name: &'static str) -> Self {
50        Self::new_static(name, VmBuiltinKind::Async)
51    }
52
53    fn new(name: impl Into<Cow<'static, str>>, kind: VmBuiltinKind) -> Self {
54        Self {
55            name: name.into(),
56            kind,
57            signature: None,
58            arity: None,
59            category: None,
60            doc: None,
61            contract: BuiltinContract::RUNTIME_INTERNAL,
62        }
63    }
64
65    const fn new_static(name: &'static str, kind: VmBuiltinKind) -> Self {
66        Self {
67            name: Cow::Borrowed(name),
68            kind,
69            signature: None,
70            arity: None,
71            category: None,
72            doc: None,
73            contract: BuiltinContract::RUNTIME_INTERNAL,
74        }
75    }
76
77    pub(crate) fn with_kind(mut self, kind: VmBuiltinKind) -> Self {
78        self.kind = kind;
79        self
80    }
81
82    pub fn signature_static(mut self, signature: &'static str) -> Self {
83        self.signature = Some(Cow::Borrowed(signature));
84        self
85    }
86
87    pub fn signature_owned(mut self, signature: impl Into<Cow<'static, str>>) -> Self {
88        self.signature = Some(signature.into());
89        self
90    }
91
92    pub fn arity(mut self, arity: VmBuiltinArity) -> Self {
93        self.arity = Some(arity);
94        self
95    }
96
97    pub fn category_static(mut self, category: &'static str) -> Self {
98        self.category = Some(Cow::Borrowed(category));
99        self
100    }
101
102    pub fn category_owned(mut self, category: impl Into<Cow<'static, str>>) -> Self {
103        self.category = Some(category.into());
104        self
105    }
106
107    pub fn doc_static(mut self, doc: &'static str) -> Self {
108        self.doc = Some(Cow::Borrowed(doc));
109        self
110    }
111
112    pub fn doc_owned(mut self, doc: impl Into<Cow<'static, str>>) -> Self {
113        self.doc = Some(doc.into());
114        self
115    }
116
117    pub fn with_contract(mut self, contract: BuiltinContract) -> Self {
118        assert!(
119            contract.is_declared(),
120            "dynamic builtin `{}` must supply a declared contract",
121            self.name
122        );
123        self.contract = contract;
124        self
125    }
126
127    pub fn name(&self) -> &str {
128        self.name.as_ref()
129    }
130
131    pub fn kind(&self) -> VmBuiltinKind {
132        self.kind
133    }
134
135    pub fn signature(&self) -> Option<&str> {
136        self.signature.as_deref()
137    }
138
139    pub fn arity_metadata(&self) -> Option<VmBuiltinArity> {
140        self.arity
141    }
142
143    pub fn category(&self) -> Option<&str> {
144        self.category.as_deref()
145    }
146
147    pub fn doc(&self) -> Option<&str> {
148        self.doc.as_deref()
149    }
150
151    pub const fn contract(&self) -> BuiltinContract {
152        self.contract
153    }
154
155    pub const fn is_source_visible(&self) -> bool {
156        !matches!(
157            self.contract.exposure,
158            BuiltinExposure::RuntimeInternal | BuiltinExposure::Undeclared
159        )
160    }
161}