orbiter_rs/macros.rs
1/// Helper macro for defining [`Vector3`](super::VECTOR3) objects
2#[macro_export]
3macro_rules! V {
4 ($x:expr, $y:expr, $z:expr) => {
5 $crate::Vector3::new($x, $y, $z)
6 };
7}
8/// Macro for defining ctype wrappers
9///
10/// Adapted from [comment](https://github.com/dtolnay/cxx/issues/254#issuecomment-747860504) by Adrian Taylor
11#[macro_export]
12macro_rules! ctype_wrapper {
13 ($r:ident, $c:ty) => {
14 #[doc = "Newtype wrapper for `"]
15 #[doc = stringify!($r)]
16 #[doc = "` as a [`"]
17 #[doc = stringify!($c)]
18 #[doc = "`]"]
19 #[derive(Debug, Eq, Clone, PartialEq, Hash, Default, Copy)]
20 #[allow(non_camel_case_types)]
21 #[repr(transparent)]
22 pub struct $r(pub $c);
23 unsafe impl cxx::ExternType for $r {
24 type Id = cxx::type_id!($r);
25 type Kind = cxx::kind::Trivial;
26 }
27 };
28 ($r:ident, $c:ty, $nice_name:ident) => {
29 #[doc = "Newtype wrapper for `"]
30 #[doc = stringify!($r)]
31 #[doc = "` as a ["]
32 #[doc = stringify!($c)]
33 #[doc = "]"]
34 #[derive(Debug, Eq, Clone, PartialEq, Hash, Default, Copy)]
35 #[allow(non_camel_case_types)]
36 #[repr(transparent)]
37 pub struct $r(pub $c);
38 unsafe impl cxx::ExternType for $r {
39 type Id = cxx::type_id!($r);
40 type Kind = cxx::kind::Trivial;
41 }
42 #[doc = "Type alias for ["]
43 #[doc = stringify!($r)]
44 #[doc = "]"]
45 pub type $nice_name = $r;
46 };
47}
48
49/// Helper macro for defining entry point into a Vessel addon
50///
51/// Inspired by emgre's [orbiter-rs](https://github.com/emgre/orbiter-rs/blob/107068c6e66564b9dff86c8b964515da9771a3af/orbiter/src/lib.rs#L37)
52///
53/// The macro should contain two function blocks `init()` and `exit()`. The `init` function takes one argument,
54/// an `[SDKVessel]` instance. It is expected that this `[SDKVessel]` instance is passed to and stored in the Rust code implementing the addon.
55///
56/// The `exit` function is called at the end of a simulation session and can be used to perform cleanup functions.
57///
58/// Example:
59/// ```no_run
60/// fn init(vessel)
61/// {
62/// Surveyor::new(vessel)
63/// }
64/// fn exit() {}
65/// ```
66#[macro_export]
67macro_rules! init_vessel {
68 (fn init($vessel_ident:ident) $init_block:block fn exit() $body_exit:block) => {
69 #[no_mangle]
70 pub extern "C" fn ovcInit (hvessel: $crate::OBJHANDLE, flightmodel: i32) -> *mut $crate::ffi::VESSEL
71 {
72 // The init function pointer gets stored in the C++ object
73 // and gets triggered on clbkSetClassCaps() before the trait method
74 unsafe { $crate::ffi::vessel_ovcInit(hvessel, flightmodel, vessel_init) }
75 }
76 #[no_mangle]
77 pub extern "C" fn ovcExit (vessel: *mut $crate::ffi::VESSEL)
78 {
79 $body_exit
80 unsafe { $crate::ffi::vessel_ovcExit(vessel); }
81 }
82 pub fn vessel_init<'a> (vessel: std::pin::Pin<&'static mut $crate::ffi::VesselContext>) -> Box<dyn $crate::OrbiterVessel + 'static>
83 {
84 let $vessel_ident = vessel;
85 let spacecraft = {
86 $init_block
87 };
88 return Box::new(spacecraft);
89 }
90 };
91}
92
93/// Displays a string in the lower left corner of the viewport.
94///
95/// This macro uses the exact same parameters as the [`format!`] macro of the
96/// standard library.
97///
98/// Due to how Orbiter handles this string, its length is limited to 255 characters.
99/// The Rust code truncates the formatted string to 255 characters to make sure that
100/// no buffer overflow occurs.
101///
102/// **This function should only be used for debugging purposes.**
103///
104/// # Examples
105///
106/// ```
107/// use orbiter_rs::debug_string;
108///
109/// let some_value = 42;
110/// debug_string!("This is my value: {}", 42);
111/// ```
112///
113/// [`format!`]: https://doc.rust-lang.org/std/fmt/index.html
114///
115/// Macro adapted from Émile Grégoire's version at
116/// <https://github.com/emgre/orbiter-rs/blob/107068c6e66564b9dff86c8b964515da9771a3af/orbiter/src/lib.rs#L96>
117#[macro_export]
118macro_rules! debug_string {
119 ($($args:tt)+) => {
120 $crate::ODebug(format!($($args)*));
121 }
122}