1#[macro_use]
13extern crate dlopen_derive;
14
15use safer_ffi::prelude::*;
16use serde::{Deserialize, Serialize};
17
18use std::{borrow::Cow, collections::HashMap};
19
20mod allocation;
21pub use allocation::*;
22
23pub use ty::Erased;
24mod ty {
25 use safer_ffi::derive_ReprC;
26
27 #[derive_ReprC]
28 #[ReprC::opaque]
29 pub struct Erased {
31 _private: (),
32 }
33}
34
35pub type TypePath = String;
37
38pub type ScriptApi = HashMap<TypePath, ScriptType>;
40
41#[derive(Serialize, Deserialize, Debug, Clone)]
43pub enum ScriptType {
44 Struct(StructDefinition),
46 Function(FunctionDefinition),
48}
49
50#[derive(Serialize, Deserialize, Debug, Clone)]
53pub struct StructDefinition {
54 pub layout: DataLayout,
56 pub component_type: DataType,
58 pub method_definitions: Vec<FunctionDefinition>,
60}
61
62impl HasDataLayout for StructDefinition {
63 fn get_data_layout(&self) -> DataLayout {
64 self.layout
65 }
66}
67
68pub trait HasDataLayout {
69 fn get_data_layout(&self) -> DataLayout;
70}
71
72#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
74pub struct DataLayout {
75 size: usize,
77 align: usize,
79}
80
81impl DataLayout {
82 pub fn from_size_align(size: usize, align: usize) -> Result<Self, std::alloc::LayoutError> {
83 std::alloc::Layout::from_size_align(size, align)?;
85
86 Ok(Self { size, align })
87 }
88
89 pub fn size(&self) -> usize {
90 self.size
91 }
92
93 pub fn align(&self) -> usize {
94 self.align
95 }
96}
97
98#[derive(Serialize, Deserialize, Debug, Clone)]
100pub enum DataType {
101 Pointer(Box<ScriptType>),
103 Struct {
105 fields: HashMap<String, StructDefinition>,
106 },
107 Primitive(Primitive),
109}
110
111#[derive(Serialize, Deserialize, Debug, Clone)]
113pub enum Primitive {
114 U8,
115 U16,
116 U32,
117 U64,
118 U128,
119 I8,
120 I16,
121 I32,
122 I64,
123 I128,
124 F32,
125 F64,
126 Char,
127 Bool,
128}
129
130impl HasDataLayout for Primitive {
131 #[rustfmt::skip]
132 fn get_data_layout(&self) -> DataLayout {
133 match self {
134 Primitive::Char => DataLayout::from_size_align(1, 1).unwrap(),
135 Primitive::Bool => DataLayout::from_size_align(1, 1).unwrap(),
136 Primitive::U8 => DataLayout::from_size_align(1, 1).unwrap(),
137 Primitive::U16 => DataLayout::from_size_align(2, 2).unwrap(),
138 Primitive::U32 => DataLayout::from_size_align(4, 4).unwrap(),
139 Primitive::U64 => DataLayout::from_size_align(8, 8).unwrap(),
140 Primitive::U128 => DataLayout::from_size_align(16, 16).unwrap(),
141 Primitive::I8 => DataLayout::from_size_align(1, 1).unwrap(),
142 Primitive::I16 => DataLayout::from_size_align(2, 2).unwrap(),
143 Primitive::I32 => DataLayout::from_size_align(4, 4).unwrap(),
144 Primitive::I64 => DataLayout::from_size_align(8, 8).unwrap(),
145 Primitive::I128 => DataLayout::from_size_align(16, 16).unwrap(),
146 Primitive::F32 => DataLayout::from_size_align(4, 4).unwrap(),
147 Primitive::F64 => DataLayout::from_size_align(8, 8).unwrap(),
148 }
149 }
150}
151
152#[derive(Serialize, Deserialize, Clone, Debug)]
154pub struct FunctionDefinition {
155 pub arguments: HashMap<Cow<'static, str>, TypePath>,
157 pub return_type: Option<TypePath>,
159}
160
161pub use language_adapter::*;
162#[allow(missing_docs)]
163mod language_adapter {
164 use super::{Erased, ScriptApi};
165 use dlopen::wrapper::{Container, WrapperApi};
166 use safer_ffi::{prelude::*, string::str_ref};
167
168 #[derive_ReprC]
169 #[repr(C)]
170 pub struct LanguageAdapterInitArgs {
171 pub log_info: extern "C" fn(safer_ffi::string::String),
172 }
173
174 pub struct LanguageAdapter(Container<LanguageAdapterCApi>);
176
177 impl LanguageAdapter {
178 pub fn new(api: Container<LanguageAdapterCApi>) -> Self {
179 Self(api)
180 }
181
182 pub fn init_adapter(&self, args: &LanguageAdapterInitArgs) {
184 self.0.init_adapter(args)
185 }
186
187 pub fn get_api(&self) -> Result<ScriptApi, serde_cbor::Error> {
189 serde_cbor::from_slice(&self.0.get_api())
190 }
191
192 pub fn run_function(&self, path: &str, args: &[*const Erased]) -> *const Erased {
193 (self.0.run_function)(path.into(), args.into())
194 }
195 }
196
197 #[derive(WrapperApi)]
199 pub struct LanguageAdapterCApi {
200 init_adapter: fn(args: &LanguageAdapterInitArgs),
203
204 get_api: fn() -> safer_ffi::Vec<u8>,
208
209 run_function: fn(path: str_ref, args: c_slice::Ref<*const Erased>) -> *const Erased,
211 }
212}