use std::ffi::CString;
use std::marker::PhantomData;
use xplm_sys::XPLMDataRef;
mod sealed {
pub trait Sealed {}
}
pub struct ReadOnlyMarker;
pub struct ReadWriteMarker;
impl sealed::Sealed for ReadOnlyMarker {}
impl sealed::Sealed for ReadWriteMarker {}
pub trait Access: sealed::Sealed {}
impl Access for ReadOnlyMarker {}
impl Access for ReadWriteMarker {}
pub trait Writable: Access {}
impl Writable for ReadWriteMarker {}
fn find_raw(name: &str) -> Option<XPLMDataRef> {
let c_name = CString::new(name).ok()?;
let raw = unsafe { xplm_sys::XPLMFindDataRef(c_name.as_ptr()) };
(!raw.is_null()).then_some(raw)
}
pub trait Scalar: sealed_scalar::Sealed + Copy {
#[doc(hidden)]
unsafe fn get_raw(raw: XPLMDataRef) -> Self;
#[doc(hidden)]
unsafe fn set_raw(raw: XPLMDataRef, value: Self);
}
mod sealed_scalar {
pub trait Sealed {}
impl Sealed for i32 {}
impl Sealed for f32 {}
impl Sealed for f64 {}
}
impl Scalar for i32 {
unsafe fn get_raw(raw: XPLMDataRef) -> Self {
unsafe { xplm_sys::XPLMGetDatai(raw) }
}
unsafe fn set_raw(raw: XPLMDataRef, value: Self) {
unsafe { xplm_sys::XPLMSetDatai(raw, value) }
}
}
impl Scalar for f32 {
unsafe fn get_raw(raw: XPLMDataRef) -> Self {
unsafe { xplm_sys::XPLMGetDataf(raw) }
}
unsafe fn set_raw(raw: XPLMDataRef, value: Self) {
unsafe { xplm_sys::XPLMSetDataf(raw, value) }
}
}
impl Scalar for f64 {
unsafe fn get_raw(raw: XPLMDataRef) -> Self {
unsafe { xplm_sys::XPLMGetDatad(raw) }
}
unsafe fn set_raw(raw: XPLMDataRef, value: Self) {
unsafe { xplm_sys::XPLMSetDatad(raw, value) }
}
}
pub struct DataRef<T: Scalar, A: Access> {
raw: XPLMDataRef,
_type: PhantomData<T>,
_access: PhantomData<A>,
}
unsafe impl<T: Scalar, A: Access> Send for DataRef<T, A> {}
impl<T: Scalar, A: Access> DataRef<T, A> {
pub fn find(name: &str) -> Option<Self> {
find_raw(name).map(|raw| Self {
raw,
_type: PhantomData,
_access: PhantomData,
})
}
pub fn get(&self) -> T {
unsafe { T::get_raw(self.raw) }
}
}
impl<T: Scalar, A: Writable> DataRef<T, A> {
pub fn set(&self, value: T) {
unsafe { T::set_raw(self.raw, value) }
}
}
pub type ReadOnly<T> = DataRef<T, ReadOnlyMarker>;
pub type ReadWrite<T> = DataRef<T, ReadWriteMarker>;
pub trait ArrayElement: sealed_array::Sealed + Copy + Default {
#[doc(hidden)]
unsafe fn get_raw(raw: XPLMDataRef, out: Option<&mut [Self]>, offset: i32) -> i32;
#[doc(hidden)]
unsafe fn set_raw(raw: XPLMDataRef, values: &[Self], offset: i32);
}
mod sealed_array {
pub trait Sealed {}
impl Sealed for i32 {}
impl Sealed for f32 {}
}
impl ArrayElement for i32 {
unsafe fn get_raw(raw: XPLMDataRef, out: Option<&mut [Self]>, offset: i32) -> i32 {
match out {
Some(buf) => unsafe {
xplm_sys::XPLMGetDatavi(raw, buf.as_mut_ptr(), offset, buf.len() as i32)
},
None => unsafe { xplm_sys::XPLMGetDatavi(raw, std::ptr::null_mut(), 0, 0) },
}
}
unsafe fn set_raw(raw: XPLMDataRef, values: &[Self], offset: i32) {
unsafe {
xplm_sys::XPLMSetDatavi(
raw,
values.as_ptr() as *mut i32,
offset,
values.len() as i32,
)
}
}
}
impl ArrayElement for f32 {
unsafe fn get_raw(raw: XPLMDataRef, out: Option<&mut [Self]>, offset: i32) -> i32 {
match out {
Some(buf) => unsafe {
xplm_sys::XPLMGetDatavf(raw, buf.as_mut_ptr(), offset, buf.len() as i32)
},
None => unsafe { xplm_sys::XPLMGetDatavf(raw, std::ptr::null_mut(), 0, 0) },
}
}
unsafe fn set_raw(raw: XPLMDataRef, values: &[Self], offset: i32) {
unsafe {
xplm_sys::XPLMSetDatavf(
raw,
values.as_ptr() as *mut f32,
offset,
values.len() as i32,
)
}
}
}
pub struct ArrayDataRef<T: ArrayElement, A: Access> {
raw: XPLMDataRef,
_type: PhantomData<T>,
_access: PhantomData<A>,
}
unsafe impl<T: ArrayElement, A: Access> Send for ArrayDataRef<T, A> {}
impl<T: ArrayElement, A: Access> ArrayDataRef<T, A> {
pub fn find(name: &str) -> Option<Self> {
find_raw(name).map(|raw| Self {
raw,
_type: PhantomData,
_access: PhantomData,
})
}
pub fn len(&self) -> usize {
unsafe { T::get_raw(self.raw, None, 0) as usize }
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn get(&self, offset: usize, out: &mut [T]) -> usize {
unsafe { T::get_raw(self.raw, Some(out), offset as i32) as usize }
}
}
impl<T: ArrayElement, A: Writable> ArrayDataRef<T, A> {
pub fn set(&self, offset: usize, values: &[T]) {
unsafe { T::set_raw(self.raw, values, offset as i32) }
}
}
pub type ReadOnlyArray<T> = ArrayDataRef<T, ReadOnlyMarker>;
pub type ReadWriteArray<T> = ArrayDataRef<T, ReadWriteMarker>;