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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#![deny(trivial_casts)]

//! Bindings to the X-Plane plugin SDK

extern crate xplm_sys;

use std::ffi::CString;

/// FFI utilities
mod ffi;
/// Path conversion
mod paths;
/// Plugin macro
mod plugin_macro;

/// Utilities that the xplane_plugin macro-generated code uses
///
mod internal;

/// Commands
pub mod command;
/// Datarefs
pub mod data;
/// Low-level drawing callbacks
pub mod draw;
/// Error detection
pub mod error;
/// SDK feature management
pub mod feature;
/// Flight loop callbacks
// TODO: Flight loop implementation that supports SDK 1.0
pub mod flight_loop;
/// 2D user interface geometry
pub mod geometry;
/// User interface menus
pub mod menu;
/// Plugin creation and management
pub mod plugin;
/// X-Plane and XPLM version info
pub mod versions;
/// Relatively low-level windows
pub mod window;

/// Writes a message to the developer console and Log.txt file
///
/// No line terminator is added.
#[deprecated(note = "Please use the debug! or debugln! macro instead")]
pub fn debug<S: Into<String>>(message: S) {
    match CString::new(message.into()) {
        Ok(message_c) => unsafe { XPLMDebugString(message_c.as_ptr()) },
        Err(_) => unsafe {
            XPLMDebugString("[xplm] Invalid debug message\n\0".as_ptr() as *const _)
        },
    }
}

/// Re-export the signature of XPLMDebugString as it is needed in the debug macros.
/// By re-exporting we can avoid that users have to import xplm_sys into their plugin.
#[doc(hidden)]
pub use xplm_sys::XPLMDebugString;

/// Writes a message to the developer console and Log.txt file
#[macro_export]
macro_rules! debug {
    ($($arg:tt)*) => ({
        let formatted_string: String = std::fmt::format(std::format_args!($($arg)*));
        #[allow(unused_unsafe)] // Disable unnecessary unsafe block warning when embedded in unsafe function
        match std::ffi::CString::new(formatted_string) {
            Ok(c_str) => unsafe { $crate::XPLMDebugString(c_str.as_ptr()) },
            Err(_) => unsafe { $crate::XPLMDebugString("[xplm] Invalid debug message\n\0".as_ptr() as *const _) }
        }
    });
}

/// Writes a message to the developer console and Log.txt file, with a newline
#[macro_export]
#[allow(unused_unsafe)]
macro_rules! debugln {
    () => ($crate::debug!("\n"));
    ($($arg:tt)*) => ({
        let mut formatted_string: String = std::fmt::format(std::format_args!($($arg)*));
        formatted_string.push_str("\n");
        #[allow(unused_unsafe)] // Disable unnecessary unsafe block warning when embedded in unsafe function
        match std::ffi::CString::new(formatted_string) {
            Ok(c_str) => unsafe { $crate::XPLMDebugString(c_str.as_ptr()) },
            Err(_) => unsafe { $crate::XPLMDebugString("[xplm] Invalid debug message\n\0".as_ptr() as *const _) }
        }
    });
}

/// Attempts to locate a symbol. If it exists, returns a pointer to it
pub fn find_symbol<S: Into<String>>(name: S) -> *mut std::os::raw::c_void {
    use std::ptr;
    match std::ffi::CString::new(name.into()) {
        Ok(name_c) => unsafe { xplm_sys::XPLMFindSymbol(name_c.as_ptr()) },
        Err(_) => ptr::null_mut(),
    }
}

/// Speak the string and/or display it onscreen/in the ATC history window
pub fn speak<S: Into<String>>(msg: S) {
    match std::ffi::CString::new(msg.into()) {
        Ok(msg) => unsafe {
            xplm_sys::XPLMSpeakString(msg.as_ptr());
        },
        Err(_) => unsafe {
            crate::XPLMDebugString("[xplm] Invalid speak message\n\0".as_ptr() as *const _)
        },
    }
}