Add the derive proc macro

This commit is contained in:
Mihai Dinculescu
2022-10-10 19:33:49 +01:00
parent 2f845f1c8f
commit 9b7e3b97db
29 changed files with 951 additions and 96 deletions

View File

@@ -6,6 +6,10 @@ edition = "2021"
description = "SimConnect SDK for Rust"
license = "MIT"
[features]
default = []
derive = ["simconnect-sdk-derive"]
[build-dependencies]
bindgen = "0.60"
@@ -13,4 +17,4 @@ bindgen = "0.60"
num_enum = "0.5"
tracing = "0.1"
thiserror = "1.0"
simconnect-sdk-derive = { path = "../simconnect-sdk-derive" }
simconnect-sdk-derive = { path = "../simconnect-sdk-derive", optional = true }

View File

@@ -1,3 +1,4 @@
/// Airport data.
#[derive(Debug, Clone)]
pub struct AirportData {
pub icao: String,

View File

@@ -1,5 +1,8 @@
/// Specifies under which conditions the data is to be sent by the server and received by the client.
#[derive(Debug, Clone)]
pub enum ConditionEnum {
pub enum Condition {
/// The default, data will be sent strictly according to the defined period.
None,
/// Data will only be sent to the client when one or more values have changed.
Changed,
}

View File

@@ -1,5 +1,6 @@
/// SimConnect object property data type.
#[derive(Debug, Clone)]
pub enum DataType {
F64,
Float64,
Bool,
}

View File

@@ -1,5 +1,7 @@
use std::os::raw::c_char;
/// SimConnect event.
/// As defined at <https://www.prepar3d.com/SDKv3/LearningCenter/utilities/variables/event_ids.html>
#[derive(Debug, Copy, Clone, num_enum::TryFromPrimitive)]
#[repr(u32)]
pub enum Event {

View File

@@ -1,5 +0,0 @@
#[derive(Copy, Clone)]
#[repr(u32)]
pub enum Group {
Group0,
}

View File

@@ -2,14 +2,14 @@ mod airport_data;
mod condition;
mod data_type;
mod event;
mod group;
mod notification;
mod notification_group;
mod period;
pub use airport_data::*;
pub use condition::*;
pub use data_type::*;
pub use event::*;
pub use group::*;
pub use notification::*;
pub use notification_group::*;
pub use period::*;

View File

@@ -1,28 +1,39 @@
use crate::{AirportData, Event, SimConnectObjectExt};
use crate::{AirportData, Event, SimConnectError, SimConnectObjectExt};
/// Notification received from SimConnect.
pub enum Notification {
/// SimConnect open
Open,
/// SimConnect event
Event(Event),
/// SimConnect object
Data(NotificationData),
/// SimConnect airport list
AirportList(Vec<AirportData>),
/// SimConnect quit
Quit,
/// SimConnect exception
Exception(u32),
}
/// Notification data object.
pub struct NotificationData {
pub(crate) type_id: String,
pub(crate) data_addr: *const u32,
}
impl NotificationData {
pub fn try_into<T: SimConnectObjectExt>(&self) -> Option<T> {
pub fn try_transmute<T: SimConnectObjectExt>(&self) -> Result<T, SimConnectError> {
let type_id: String = std::any::type_name::<T>().into();
if self.type_id == type_id {
let data: &T = unsafe { std::mem::transmute_copy(&self.data_addr) };
Some(data.clone())
Ok(data.clone())
} else {
None
Err(SimConnectError::ObjectMismatch {
actual: self.type_id.clone(),
expected: type_id,
})
}
}
}

View File

@@ -0,0 +1,6 @@
/// SimConnect event notification group.
#[derive(Copy, Clone)]
#[repr(u32)]
pub enum NotificationGroup {
Group0,
}

View File

@@ -1,5 +1,16 @@
/// Specifies how often the data is to be sent by the server and received by the client.
/// 0 - every interval.
/// 1 - every other interval.
/// 2 - every third interval.
/// etc.
#[derive(Debug, Clone)]
pub enum PeriodEnum {
VisualFrame { interval: u32 },
pub enum Period {
/// Specifies that the data should be sent once only. Note that this is not an efficient way of receiving data frequently, use one of the other periods if there is a regular frequency to the data request.
Once,
/// Specifies that the data should be sent every visual (rendered) frame.
VisualFrame,
/// Specifies that the data should be sent every simulated frame, whether that frame is rendered or not.
SimFrame,
/// Specifies that the data should be sent once every second.
Second,
}

View File

@@ -1,15 +1,24 @@
use thiserror::Error;
/// SimConnect SDK error.
#[derive(Error, Debug)]
pub enum SimConnectError {
/// SimConnect error.
#[error("SimConnect error: {0}")]
SimConnectError(i32),
#[error("SimConnect unrecognized: {0}")]
/// SimConnect unrecognized error. Occurs when an unimplemented event is received by the SDK.
SimConnectUnrecognizedEvent(u32),
/// Object already registered with the client instance.
#[error("Object `{0}` has already been registered")]
ObjectAlreadyRegistered(String),
/// Object mismatch.
#[error("Tried to convert object of type {actual} to {expected}")]
ObjectMismatch { actual: String, expected: String },
/// Conversation error.
#[error("Conversion error: {0}")]
ConversionError(#[from] std::num::TryFromIntError),
/// Unexpected error.
#[error("Unexpected error: {0}")]
UnexpectedError(String),
}

View File

@@ -1,3 +1,8 @@
//! # SimConnect SDK
//! SimConnect SDK in Rust.
//!
//! See [examples](https://github.com/mihai-dinculescu/simconnect-sdk/tree/main/examples/src).
mod bindings;
mod domain;
mod errors;
@@ -13,5 +18,7 @@ pub use errors::SimConnectError;
pub use simconnect::SimConnect;
pub use simconnect_object_ext::SimConnectObjectExt;
#[cfg(feature = "simconnect-sdk-derive")]
extern crate simconnect_sdk_derive;
#[cfg(feature = "simconnect-sdk-derive")]
pub use simconnect_sdk_derive::*;

View File

@@ -2,10 +2,11 @@ use std::ffi::c_void;
use crate::{
as_c_string, bindings, helpers::fixed_c_str_to_string, ok_if_fail, success, AirportData,
ConditionEnum, DataType, Event, Group, Notification, NotificationData, PeriodEnum,
Condition, DataType, Event, Notification, NotificationData, NotificationGroup, Period,
SimConnectError, SimConnectObjectExt,
};
/// SimConnect SDK Client.
#[derive(Debug)]
pub struct SimConnect {
pub handle: std::ptr::NonNull<c_void>,
@@ -71,7 +72,7 @@ impl SimConnect {
)
});
let group = Group::Group0;
let group = NotificationGroup::Group0;
success!(unsafe {
bindings::SimConnect_AddClientEventToNotificationGroup(
@@ -98,7 +99,7 @@ impl SimConnect {
data_type: DataType,
) -> Result<(), SimConnectError> {
let c_type = match data_type {
DataType::F64 => bindings::SIMCONNECT_DATATYPE_SIMCONNECT_DATATYPE_FLOAT64,
DataType::Float64 => bindings::SIMCONNECT_DATATYPE_SIMCONNECT_DATATYPE_FLOAT64,
DataType::Bool => bindings::SIMCONNECT_DATATYPE_SIMCONNECT_DATATYPE_INT32,
};
@@ -121,21 +122,22 @@ impl SimConnect {
pub fn request_data_on_sim_object(
&self,
request_id: u32,
period: PeriodEnum,
condition: ConditionEnum,
period: Period,
condition: Condition,
interval: u32,
) -> Result<(), SimConnectError> {
unsafe {
let (simconnect_period, simconnect_interval) = match period {
PeriodEnum::VisualFrame { interval } => (
bindings::SIMCONNECT_PERIOD_SIMCONNECT_PERIOD_VISUAL_FRAME,
interval,
),
PeriodEnum::Second => (bindings::SIMCONNECT_PERIOD_SIMCONNECT_PERIOD_SECOND, 0),
let simconnect_period = match period {
Period::Once => bindings::SIMCONNECT_PERIOD_SIMCONNECT_PERIOD_ONCE,
Period::VisualFrame => bindings::SIMCONNECT_PERIOD_SIMCONNECT_PERIOD_VISUAL_FRAME,
Period::SimFrame => bindings::SIMCONNECT_PERIOD_SIMCONNECT_PERIOD_SIM_FRAME,
Period::Second => bindings::SIMCONNECT_PERIOD_SIMCONNECT_PERIOD_SECOND,
};
let simconnect_flags: u32 = match condition {
ConditionEnum::None => 0,
ConditionEnum::Changed => bindings::SIMCONNECT_DATA_REQUEST_FLAG_CHANGED,
Condition::None => 0,
Condition::Changed => bindings::SIMCONNECT_DATA_REQUEST_FLAG_CHANGED,
};
success!(bindings::SimConnect_RequestDataOnSimObject(
@@ -146,7 +148,7 @@ impl SimConnect {
simconnect_period,
simconnect_flags,
0,
simconnect_interval,
interval,
0,
));
}

View File

@@ -1,5 +1,6 @@
use crate::{NotificationData, SimConnect, SimConnectError};
/// Trait to be implemented by objects that can be registered with SimConnect.
pub trait SimConnectObjectExt: Clone + for<'a> TryFrom<&'a NotificationData> {
fn register(client: &mut SimConnect, id: u32) -> Result<(), SimConnectError>;
}