sails_idl_parser/ffi/ast/
mod.rs

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