Skip to main content

aranya_policy_module/
ffi.rs

1//! Data definitions used by the FFI interface
2extern crate alloc;
3use alloc::boxed::Box;
4
5use aranya_policy_ast::{Identifier, ResultTypeKind, Span, TypeKind, VType, WithSpanExt as _};
6
7/// The type of a value
8#[derive(Clone, Debug, Eq, PartialEq)]
9pub enum Type<'a> {
10    /// A UTF-8 string.
11    String,
12    /// A byte string
13    Bytes,
14    /// A signed, 64-bit integer.
15    Int,
16    /// A boolean.
17    Bool,
18    /// A unique identifier.
19    Id,
20    /// A named struct.
21    Struct(Identifier),
22    /// A named enum.
23    Enum(Identifier),
24    /// An optional type of some other type.
25    Optional(&'a Type<'a>),
26    /// Result
27    Result(&'a Type<'a>, &'a Type<'a>),
28}
29
30impl Type<'_> {
31    // Like `==`, but can be used in a const context.
32    //
33    // Used by `policy-derive`.
34    #[doc(hidden)]
35    pub const fn const_eq(&self, rhs: &Self) -> bool {
36        use Type::*;
37        match (self, rhs) {
38            (String, String) | (Bytes, Bytes) | (Int, Int) | (Bool, Bool) | (Id, Id) => true,
39            (Struct(lhs), Struct(rhs)) => lhs.const_eq(rhs),
40            (Enum(lhs), Enum(rhs)) => lhs.const_eq(rhs),
41            (Optional(lhs), Optional(rhs)) => lhs.const_eq(rhs),
42            (Result(lhs1, lhs2), Result(rhs1, rhs2)) => lhs1.const_eq(rhs1) && lhs2.const_eq(rhs2),
43            _ => false,
44        }
45    }
46}
47
48impl From<&Type<'_>> for VType {
49    fn from(value: &Type<'_>) -> Self {
50        let kind = match value {
51            Type::String => TypeKind::String,
52            Type::Bytes => TypeKind::Bytes,
53            Type::Int => TypeKind::Int,
54            Type::Bool => TypeKind::Bool,
55            Type::Id => TypeKind::Id,
56            Type::Struct(s) => TypeKind::Struct(s.clone().nowhere()),
57            Type::Enum(e) => TypeKind::Enum(e.clone().nowhere()),
58            Type::Optional(t) => TypeKind::Optional(Box::new((*t).into())),
59            Type::Result(ok, err) => TypeKind::Result(Box::new(ResultTypeKind {
60                ok: (*ok).into(),
61                err: (*err).into(),
62            })),
63        };
64        Self {
65            inner: kind,
66            span: Span::empty(),
67        }
68    }
69}
70
71/// Describes the context in which the function can be called.
72#[derive(Clone, Debug)]
73pub enum Color<'a> {
74    /// Function is valid outside of finish blocks, and returns
75    /// a value.
76    Pure(Type<'a>),
77    /// Function is valid inside finish blocks, and does not
78    /// return a value.
79    Finish,
80}
81
82/// A foreign function.
83#[derive(Clone, Debug)]
84pub struct Func<'a> {
85    /// The function's name.
86    pub name: Identifier,
87    /// The function's arguments.
88    pub args: &'a [Arg<'a>],
89    /// The return type of the function.
90    pub return_type: Type<'a>,
91}
92
93/// An argument to a foreign function.
94#[derive(Clone, Debug, PartialEq, Eq)]
95pub struct Arg<'a> {
96    /// The argument's name.
97    pub name: Identifier,
98    /// The field's type.
99    pub vtype: Type<'a>,
100}
101
102/// A struct definition
103pub struct Struct<'a> {
104    /// The name of the struct.
105    pub name: Identifier,
106    /// The fields of the struct.
107    pub fields: &'a [Arg<'a>],
108}
109
110/// Enumeration definition
111pub struct Enum<'a> {
112    /// name of enumeration
113    pub name: Identifier,
114    /// list of possible values
115    pub variants: &'a [Identifier],
116}
117
118/// Shorthand for creating [`Arg`]s.
119///
120/// # Example
121///
122/// ```rust
123/// use aranya_policy_module::{
124///     arg,
125///     ast::ident,
126///     ffi::{Arg, Type},
127/// };
128///
129/// let got = arg!("string", String);
130/// let want = Arg {
131///     name: ident!("string"),
132///     vtype: Type::String,
133/// };
134/// assert_eq!(got, want);
135///
136/// let got = arg!("bytes", Bytes);
137/// let want = Arg {
138///     name: ident!("bytes"),
139///     vtype: Type::Bytes,
140/// };
141/// assert_eq!(got, want);
142///
143/// let got = arg!("int", Int);
144/// let want = Arg {
145///     name: ident!("int"),
146///     vtype: Type::Int,
147/// };
148/// assert_eq!(got, want);
149///
150/// let got = arg!("bool", Bool);
151/// let want = Arg {
152///     name: ident!("bool"),
153///     vtype: Type::Bool,
154/// };
155/// assert_eq!(got, want);
156///
157/// let got = arg!("id", Id);
158/// let want = Arg {
159///     name: ident!("id"),
160///     vtype: Type::Id,
161/// };
162/// assert_eq!(got, want);
163///
164/// let got = arg!("struct", Struct("foo"));
165/// let want = Arg {
166///     name: ident!("struct"),
167///     vtype: Type::Struct(ident!("foo")),
168/// };
169/// assert_eq!(got, want);
170///
171/// let inner = &Type::Struct(ident!("bar"));
172/// let got = arg!("optional", Optional(&inner));
173/// let want = Arg {
174///     name: ident!("optional"),
175///     vtype: Type::Optional(const { &Type::Struct(ident!("bar")) }),
176/// };
177/// assert_eq!(got, want);
178///
179/// let ok = &Type::String;
180/// let err = &Type::Int;
181/// let got = arg!("result", Result(&ok, &err));
182/// let want = Arg {
183///     name: ident!("result"),
184///     vtype: Type::Result(const { &Type::String }, const { &Type::Int }),
185/// };
186/// assert_eq!(got, want);
187/// ```
188#[macro_export]
189macro_rules! arg {
190    ($name:literal, String) => {{
191        $crate::__arg!($name, String)
192    }};
193    ($name:literal, Bytes) => {{
194        $crate::__arg!($name, Bytes)
195    }};
196    ($name:literal, Int) => {{
197        $crate::__arg!($name, Int)
198    }};
199    ($name:literal, Bool) => {{
200        $crate::__arg!($name, Bool)
201    }};
202    ($name:literal, Id) => {{
203        $crate::__arg!($name, Id)
204    }};
205    ($name:literal, Struct($struct_name:literal)) => {{
206        $crate::__arg!($name, Struct($struct_name))
207    }};
208    ($name:literal, Enum($enum_name:literal)) => {{
209        $crate::__arg!($name, Enum($enum_name))
210    }};
211    ($name:literal, Optional($(inner:tt)+)) => {{
212        $crate::__arg!($name, Optional($(inner)+))
213    }};
214    ($name:literal, Optional($inner:expr)) => {{
215        $crate::__arg!($name, Optional($inner))
216    }};
217    ($name:literal, Result($ok:expr, $err:expr)) => {{
218        $crate::__arg!($name, Result($ok, $err))
219    }};
220    ($name:literal, $type:ident) => {{
221        ::core::compile_error!(::core::concat!(
222            "unknown argument type: ",
223            ::core::stringify!($type)
224        ))
225    }};
226}
227
228#[doc(hidden)]
229#[macro_export]
230macro_rules! __arg {
231    ($name:literal, $type:ident) => {{
232        $crate::ffi::Arg {
233            name: $crate::ast::ident!($name),
234            vtype: $crate::__type!($type),
235        }
236    }};
237    ($name:literal, Struct($struct_name:literal)) => {{
238        $crate::ffi::Arg {
239            name: $crate::ast::ident!($name),
240            vtype: $crate::__type!(Struct($struct_name)),
241        }
242    }};
243    ($name:literal, Enum($enum_name:literal)) => {{
244        $crate::ffi::Arg {
245            name: $crate::ast::ident!($name),
246            vtype: $crate::__type!(Enum($enum_name)),
247        }
248    }};
249    ($name:literal, Optional($inner:expr)) => {{
250        $crate::ffi::Arg {
251            name: $crate::ast::ident!($name),
252            vtype: $crate::__type!(Optional($inner)),
253        }
254    }};
255    ($name:literal, Result($ok:expr, $err:expr)) => {{
256        $crate::ffi::Arg {
257            name: $crate::ast::ident!($name),
258            vtype: $crate::__type!(Result($ok, $err)),
259        }
260    }};
261}
262
263#[doc(hidden)]
264#[macro_export]
265macro_rules! __type {
266    (@raw $type:ident) => {
267        $crate::ffi::Type::$type
268    };
269    (@raw Struct($struct_name:literal)) => {
270        $crate::ffi::Type::Struct($crate::ast::ident!($struct_name))
271    };
272    (@raw Enum($enum_name:literal)) => {
273        $crate::ffi::Type::Enum($crate::ast::ident!($enum_name))
274    };
275    (@raw Optional($inner:expr)) => {
276        $crate::ffi::Type::Optional($inner)
277    };
278    (@raw Result($ok:expr, $err:expr)) => {
279        $crate::ffi::Type::Result($ok, $err)
280    };
281
282    (String) => {{ $crate::__type!(@raw String) }};
283    (Bytes) => {{ $crate::__type!(@raw Bytes) }};
284    (Int) => {{ $crate::__type!(@raw Int) }};
285    (Bool) => {{ $crate::__type!(@raw Bool) }};
286    (Id) => {{ $crate::__type!(@raw Id) }};
287    (Struct($struct_name:literal)) => {{
288        $crate::__type!(@raw Struct($struct_name))
289    }};
290    (Enum($enum_name:literal)) => {{
291        $crate::__type!(@raw Enum($enum_name))
292    }};
293    (Optional($(inner:tt)+)) => {{
294        $crate::__type!(@raw Optional($(inner)+))
295    }};
296    (Optional($inner:expr)) => {{
297        $crate::__type!(@raw Optional($inner))
298    }};
299    (Result($ok:expr, $err:expr)) => {{
300        $crate::__type!(@raw Result($ok, $err))
301    }};
302    ($type:ident) => {{
303        ::core::compile_error!(::core::concat!(
304            "unknown argument type: ",
305            ::core::stringify!($type)
306        ))
307    }};
308}
309
310/// Foreign-function module declaration.
311pub struct ModuleSchema<'a> {
312    /// module name
313    pub name: Identifier,
314    /// list of functions provided by the module
315    pub functions: &'a [Func<'a>],
316    /// list of structs defined by the module
317    pub structs: &'a [Struct<'a>],
318    /// list of enums
319    pub enums: &'a [Enum<'a>],
320}