1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
//! Safe, idiomatic wrappers over `xplm-sys`: dataref access, plugin
//! lifecycle, menus, windows/widgets, and the rest of the XPLM SDK surface.
/// Attribute macro for a plugin's top-level state struct — see
/// [`xplm_macros::plugin`] for the full example. Sugar over
/// [`register_plugin!`]'s metadata-argument form.
pub use plugin;
/// Derives `find() -> Option<Self>` for a `#[dataref = "..."]`-tagged
/// struct — see [`xplm_macros::DataRefContainer`] for the full example.
pub use DataRefContainer;
/// Derives `publish(shared) -> Option<FooHandles>` for a struct of plain
/// values backing published datarefs — see
/// [`xplm_macros::PublishedDataRefContainer`] for the full example.
pub use PublishedDataRefContainer;
// FlightLoop's underlying XPLMCreateFlightLoop/XPLMDestroyFlightLoop/
// XPLMScheduleFlightLoop are all `#if defined(XPLM210)` in XPLMProcessing.h
// (only the legacy XPLMRegisterFlightLoopCallback predates that) — default
// features always include XPLM210, so this gap only surfaces building a
// lower feature set explicitly (see CLAUDE.md's "test minimal features").
use CString;
/// Runs `f`, catching any panic at the FFI boundary so it can never unwind
/// into the X-Plane host process (which would be undefined behavior).
///
/// On panic, logs the payload via `XPLMDebugString` (best-effort; a second
/// panic while formatting the message is swallowed) and returns `None`.
/// Every `extern "C"` trampoline that X-Plane calls back into MUST go
/// through this.
/// Writes a line to X-Plane's `Log.txt` via `XPLMDebugString`. Never panics;
/// a message containing an interior NUL is truncated at the NUL instead.
///
/// Under `cfg(test)` this writes to stderr instead: `XPLMDebugString` (like
/// every other XPLM function) assumes it's being called from inside a
/// plugin hosted by a running X-Plane process, and segfaults when called
/// from a bare `cargo test` binary — the DLL exists and loads (delay-load
/// resolves it against a local X-Plane install), it just isn't operating in
/// the environment it expects.