Skip to main content

sails_idl_parser/ffi/ast/
mod.rs

1use crate::ast;
2use alloc::{boxed::Box, ffi::CString};
3use core::{error::Error as CoreError, ffi::c_char, ptr, slice};
4
5pub mod visitor;
6
7#[repr(C)]
8pub struct ParseResult {
9    program: *mut Program,
10    error: Error,
11}
12
13#[repr(C)]
14pub struct Error {
15    code: ErrorCode,
16    details: *const c_char,
17}
18
19#[repr(C)]
20#[derive(Debug, Clone, Copy, PartialEq)]
21pub enum ErrorCode {
22    Ok,
23    InvalidIDL,
24    ParseError,
25    NullPtr,
26}
27
28/// # Safety
29///
30/// See the safety documentation of [`slice::from_raw_parts`].
31#[unsafe(no_mangle)]
32pub unsafe extern "C" fn parse_idl(idl_ptr: *const u8, idl_len: u32) -> *mut ParseResult {
33    let idl_slice = unsafe { slice::from_raw_parts(idl_ptr, idl_len as usize) };
34    let idl_str = match str::from_utf8(idl_slice) {
35        Ok(s) => s,
36        Err(e) => return create_parse_error(ErrorCode::ParseError, e, "validate IDL string"),
37    };
38
39    let program = match ast::parse_idl(idl_str) {
40        Ok(p) => p,
41        Err(e) => return create_parse_error(ErrorCode::ParseError, e, "parse IDL"),
42    };
43
44    let result = ParseResult {
45        error: Error {
46            code: ErrorCode::Ok,
47            details: ptr::null(),
48        },
49        program: Box::into_raw(Box::new(program)),
50    };
51
52    Box::into_raw(Box::new(result))
53}
54
55fn create_parse_error(
56    code: ErrorCode,
57    e: impl CoreError,
58    context: &'static str,
59) -> *mut ParseResult {
60    let details = CString::new(format!("{context}: {e}")).unwrap();
61    let result = ParseResult {
62        error: Error {
63            code,
64            details: details.into_raw(),
65        },
66        program: ptr::null_mut(),
67    };
68    Box::into_raw(Box::new(result))
69}
70
71/// # Safety
72///
73/// Pointer must be obtained from [`parse_idl`].
74#[unsafe(no_mangle)]
75pub unsafe extern "C" fn free_parse_result(result: *mut ParseResult) {
76    if result.is_null() {
77        return;
78    }
79    unsafe {
80        let result = Box::from_raw(result);
81        if result.error.code != ErrorCode::Ok {
82            let details = CString::from_raw(result.error.details as _);
83            drop(details);
84        }
85    }
86}
87
88pub type Program = ast::Program;
89
90#[repr(C)]
91pub struct Ctor {
92    raw_ptr: Ptr,
93}
94
95#[repr(C)]
96pub struct CtorFunc {
97    raw_ptr: Ptr,
98    name_ptr: *const u8,
99    name_len: u32,
100    docs_ptr: *const u8,
101    docs_len: u32,
102}
103
104#[repr(C)]
105pub struct Service {
106    raw_ptr: Ptr,
107    name_ptr: *const u8,
108    name_len: u32,
109}
110
111#[repr(C)]
112pub struct ServiceFunc {
113    raw_ptr: Ptr,
114    name_ptr: *const u8,
115    name_len: u32,
116    is_query: bool,
117    docs_ptr: *const u8,
118    docs_len: u32,
119}
120
121pub type ServiceEvent = EnumVariant;
122
123#[repr(C)]
124pub struct FuncParam {
125    raw_ptr: Ptr,
126    name_ptr: *const u8,
127    name_len: u32,
128}
129
130#[repr(C)]
131pub struct Type {
132    raw_ptr: Ptr,
133    name_ptr: *const u8,
134    name_len: u32,
135    docs_ptr: *const u8,
136    docs_len: u32,
137}
138
139#[repr(C)]
140pub struct TypeDecl {
141    raw_ptr: Ptr,
142}
143
144pub type PrimitiveType = ast::PrimitiveType;
145
146#[repr(C)]
147pub struct StructDef {
148    raw_ptr: Ptr,
149}
150
151#[repr(C)]
152pub struct StructField {
153    raw_ptr: Ptr,
154    name_ptr: *const u8,
155    name_len: u32,
156    docs_ptr: *const u8,
157    docs_len: u32,
158}
159
160#[repr(C)]
161pub struct EnumDef {
162    raw_ptr: Ptr,
163}
164
165#[repr(C)]
166pub struct EnumVariant {
167    raw_ptr: Ptr,
168    name_ptr: *const u8,
169    name_len: u32,
170    docs_ptr: *const u8,
171    docs_len: u32,
172}
173
174#[repr(transparent)]
175pub struct Ptr(*const ());
176
177impl<T> From<&T> for Ptr {
178    fn from(t: &T) -> Self {
179        Self(t as *const T as *const ())
180    }
181}
182
183impl<T> AsRef<T> for Ptr {
184    fn as_ref(&self) -> &T {
185        unsafe { (self.0 as *const T).as_ref() }.unwrap()
186    }
187}