xplm/
data.rs

1use crate::ffi::StringBuffer;
2use std::ffi::{CString, NulError};
3use std::string::FromUtf8Error;
4use xplm_sys::*;
5
6/// Datarefs created by X-Plane or other plugins
7pub mod borrowed;
8/// Datarefs created by this plugin
9pub mod owned;
10
11/// Marks a dataref as readable
12pub enum ReadOnly {}
13
14/// Marks a dataref as writeable
15pub enum ReadWrite {}
16
17/// Marker for data access types
18pub trait Access {
19    /// Returns true if this access allows the dataref to be written
20    fn writeable() -> bool;
21}
22
23impl Access for ReadOnly {
24    fn writeable() -> bool {
25        false
26    }
27}
28
29impl Access for ReadWrite {
30    fn writeable() -> bool {
31        true
32    }
33}
34
35/// Trait for data accessors that can be read
36pub trait DataRead<T> {
37    /// Reads a value
38    fn get(&self) -> T;
39}
40
41/// Trait for writable data accessors
42pub trait DataReadWrite<T>: DataRead<T> {
43    /// Writes a value
44    fn set(&mut self, value: T);
45}
46
47/// Trait for readable array data accessors
48pub trait ArrayRead<T: ArrayType + ?Sized> {
49    /// Reads values
50    ///
51    /// Values are stored in the provided slice. If the dataref is larger than the provided slice,
52    /// values beyond the bounds of the slice are ignored.
53    ///
54    /// If the dataref is smaller than the provided slice, the extra values in the slice will not
55    /// be modified.
56    ///
57    /// The maximum number of values in an array dataref is i32::MAX.
58    ///
59    /// This function returns the number of values that were read.
60    fn get(&self, dest: &mut [T::Element]) -> usize;
61
62    /// Returns the length of the data array
63    fn len(&self) -> usize;
64
65    /// Returns all values in this accessor as a Vec
66    fn as_vec(&self) -> Vec<T::Element>
67    where
68        T::Element: Default + Clone,
69    {
70        let mut values = vec![T::Element::default(); self.len()];
71        self.get(&mut values);
72        values
73    }
74}
75
76/// Trait for array accessors that can be read and written
77pub trait ArrayReadWrite<T: ArrayType + ?Sized>: ArrayRead<T> {
78    /// Writes values
79    ///
80    /// Values are taken from the provided slice. If the dataref is larger than the provided slice,
81    /// values beyond the bounds of the slice are not changed.
82    ///
83    /// If the dataref is smaller than the provided slice, the values beyond the dataref bounds
84    /// will be ignored.
85    fn set(&mut self, values: &[T::Element]);
86}
87
88/// Trait for data accessors that can be read as strings
89pub trait StringRead {
90    /// Reads the value of this dataref and appends it to the provided string
91    ///
92    /// Returns an error if the dataref is not valid UTF-8.
93    ///
94    /// If the provided string is not empty, the value of the dataref will be appended to it.
95    fn get_to_string(&self, out: &mut String) -> Result<(), FromUtf8Error>;
96
97    /// Reads the value of this dataref as a string and returns it
98    fn get_as_string(&self) -> Result<String, FromUtf8Error>;
99}
100
101/// Trait for data accessors that can be written as strings
102pub trait StringReadWrite: StringRead {
103    /// Sets the value of this dataref from a string
104    ///
105    /// Returns an error if the string contains a null byte
106    fn set_as_string(&mut self, value: &str) -> Result<(), NulError>;
107}
108
109impl<T> StringRead for T
110where
111    T: ArrayRead<[u8]>,
112{
113    fn get_to_string(&self, out: &mut String) -> Result<(), FromUtf8Error> {
114        let mut buffer = StringBuffer::new(self.len());
115        self.get(buffer.as_bytes_mut());
116        let value_string = buffer.into_string()?;
117        out.push_str(&value_string);
118        Ok(())
119    }
120    fn get_as_string(&self) -> Result<String, FromUtf8Error> {
121        let mut buffer = StringBuffer::new(self.len());
122        self.get(buffer.as_bytes_mut());
123        buffer.into_string()
124    }
125}
126
127impl<T> StringReadWrite for T
128where
129    T: ArrayReadWrite<[u8]>,
130{
131    fn set_as_string(&mut self, value: &str) -> Result<(), NulError> {
132        let name_c = CString::new(value)?;
133        self.set(name_c.as_bytes_with_nul());
134        Ok(())
135    }
136}
137
138/// Marker for types that can be used with datarefs
139pub trait DataType {
140    /// The type that should be used to store data of this type
141    /// For basic types, this is usually Self. For [T] types, this is Vec<T>.
142    #[doc(hidden)]
143    type Storage: Sized;
144    /// Returns the X-Plane data type corresponding with this type
145    #[doc(hidden)]
146    fn sim_type() -> XPLMDataTypeID;
147    /// Creates an instance of a storage type from an instance of self
148    #[doc(hidden)]
149    fn to_storage(&self) -> Self::Storage;
150}
151
152/// Marker for types that are arrays
153pub trait ArrayType: DataType {
154    /// The type of the array element
155    type Element;
156}
157
158macro_rules! impl_type {
159    ($native_type:ty as $sim_type:ident) => {
160        impl DataType for $native_type {
161            type Storage = Self;
162            fn sim_type() -> XPLMDataTypeID {
163                $sim_type as XPLMDataTypeID
164            }
165            fn to_storage(&self) -> Self::Storage {
166                self.clone()
167            }
168        }
169    };
170    ([$native_type:ty]: array as $sim_type:ident) => {
171        impl DataType for [$native_type] {
172            type Storage = Vec<$native_type>;
173            fn sim_type() -> XPLMDataTypeID {
174                $sim_type as XPLMDataTypeID
175            }
176            fn to_storage(&self) -> Self::Storage {
177                self.to_vec()
178            }
179        }
180        impl ArrayType for [$native_type] {
181            type Element = $native_type;
182        }
183    };
184}
185
186impl_type!(bool as xplmType_Int);
187impl_type!(u8 as xplmType_Int);
188impl_type!(i8 as xplmType_Int);
189impl_type!(u16 as xplmType_Int);
190impl_type!(i16 as xplmType_Int);
191impl_type!(u32 as xplmType_Int);
192impl_type!(i32 as xplmType_Int);
193impl_type!(f32 as xplmType_Float);
194impl_type!(f64 as xplmType_Double);
195impl_type!([i32]: array as xplmType_IntArray);
196impl_type!([u32]: array as xplmType_IntArray);
197impl_type!([f32]: array as xplmType_FloatArray);
198impl_type!([u8]: array as xplmType_Data);
199impl_type!([i8]: array as xplmType_Data);