1use yog_abi::{YogBytes, YogHandlerFn, YogReply, YogStatus, status};
8use yog_data::Schema;
9use yog_event::Message;
10
11use crate::registry::guard;
12use crate::service::call_at;
13
14#[doc(hidden)]
16pub struct YogExportEntry {
17 pub name: &'static str,
18 pub handler: YogHandlerFn,
19 pub doc: &'static str,
21 pub shapes: fn() -> (yog_data::Shape, yog_data::Shape),
23 pub implements: &'static [&'static str],
25}
26
27#[doc(hidden)]
28pub fn __yog_export_registry() -> &'static yog_sync::Mutex<Vec<YogExportEntry>> {
29 static REG: yog_sync::Mutex<Vec<YogExportEntry>> = yog_sync::Mutex::new(Vec::new());
30 ®
31}
32
33pub fn export_address(mod_id: &str, name: &str) -> String {
35 yog_ids::join(mod_id, name)
36}
37
38#[doc(hidden)]
45pub unsafe fn __yog_serve<A: Schema, R: Schema>(
46 payload: YogBytes,
47 reply: *const YogReply,
48 run: impl FnOnce(A) -> R,
49) -> YogStatus {
50 let Some(args) = A::from_bytes(unsafe { payload.as_slice() }) else {
51 return status::BAD_PAYLOAD;
52 };
53 let Some(answer) = guard(None, || Some(run(args))) else {
54 return status::FAILED;
55 };
56 unsafe { YogReply::send(reply, &answer.to_bytes()) };
57 status::OK
58}
59
60pub fn call_export<A: Schema, R: Schema>(mod_id: &str, name: &str, args: &A) -> Option<R> {
63 R::from_bytes(&call_at(
64 yog_event::resolve(&export_address(mod_id, name)),
65 &args.to_bytes(),
66 )?)
67}
68
69impl crate::Registry {
70 #[doc(hidden)]
72 pub fn provide_export(&mut self, mod_id: &str, entry: &YogExportEntry) {
73 let address = export_address(mod_id, entry.name);
74 if self.provide_raw(&address, entry.handler) {
75 let (args, answer) = (entry.shapes)();
76 let interfaces = entry.implements.iter().map(|i| (*i).to_owned()).collect();
77 self.declare(&address, entry.doc, &args, &answer, interfaces);
78 }
79 }
80}