async_load/ds_map/
mod.rs

1mod types;
2mod internals;
3
4use std::ffi::CString;
5use std::os::raw::{c_char, c_double, c_int, c_void};
6use crate::types::GMLDouble;
7pub use types::*;
8use internals::*;
9
10/// GML data structure used for passing data into an async event.
11///
12/// Read more here:
13/// https://manual.yoyogames.com/The_Asset_Editors/Object_Properties/Async_Events.htm
14#[derive(Debug, Eq, PartialEq)]
15pub struct DSMap {
16    pub(crate) map_id: c_int,
17}
18
19impl DSMap {
20    /// Function used for registering internal calls into GMS2.
21    /// It is designated to run inside of exported function `RegisterCallbacks`.
22    ///
23    /// # Args
24    /// All arguments are internal GMS2 functions.
25    /// - `event_perform_async`: Calls a specific async event.
26    /// - `ds_map_create`: Creates new map data structure.
27    /// - `ds_map_add_double`: Adds a `double` value into the map.
28    /// - `ds_map_add_string`: Adds a `string` value into the map.
29    ///
30    /// # Safety
31    /// DO NOT call this function on your own as it might cause undefined behaviour!
32    /// All the methods of `DSMap` structure calls the internal GMS2 functions passed as the arguments here,
33    /// so when the callbacks are not registered and any of the method is executed, undefined behaviour will occur.
34    pub unsafe fn register_calls(
35        event_perform_async: *const c_void,
36        ds_map_create: *const c_void,
37        ds_map_add_double: *const c_void,
38        ds_map_add_string: *const c_void,
39    ) {
40        register_event_perform_async(event_perform_async as FnAddr);
41        register_ds_map_create(ds_map_create as FnAddr);
42        register_ds_map_add_double(ds_map_add_double as FnAddr);
43        register_ds_map_add_string(ds_map_add_string as FnAddr);
44    }
45
46    /// Creates a new map data structure.
47    ///
48    /// # Safety
49    /// Do not execute this method if the internal GMS2 functions were not
50    /// registered using `DSMap::register_calls`.
51    pub unsafe fn new() -> Self {
52        let map_id = (*FN_DS_MAP_CREATE)(0);
53        DSMap { map_id }
54    }
55
56    /// Creates a wrapper around existing map data structure.
57    ///
58    /// This method could be used to perform some work on a ds_map created
59    /// inside GMS2 by passing its ID.
60    ///
61    /// # Args
62    /// - `map_id`: ID of the existing map data structure.
63    ///
64    /// # Safety
65    /// There is no checks in place that will make sure the provided ID is valid,
66    /// or that the map will not be destroyed while in use.
67    ///
68    /// It's easy to break something when working on a data structure created inside of the GMS2,
69    /// so use it only if you know what you are doing.
70    pub fn new_existing(map_id: c_int) -> Self {
71        DSMap { map_id }
72    }
73
74    /// Adds a new `double` value to the map on a specific key.
75    ///
76    /// # Args
77    /// - `key`: The key of the value to add.
78    /// - `value`: The `double` value to add to the map.
79    ///
80    /// # Return
81    /// Returns `bool` when the operation was successful.
82    /// This method might fail if the map doesn't exist, or the key was already inside of the map.
83    ///
84    /// # Safety
85    /// Do not execute this method if the internal GMS2 functions were not
86    /// registered using `DSMap::register_calls`.
87    pub unsafe fn add_double(&mut self, key: impl ToString, value: GMLDouble) -> bool {
88        // Will never fail if key is a valid String
89        let key_cstr = CString::new(
90            key.to_string()
91        ).unwrap();
92
93        (*FN_DS_MAP_ADD_DOUBLE)(
94            self.map_id,
95            key_cstr.as_ptr(),
96            value,
97        )
98    }
99
100    /// Adds a new `string` value to the map on a specific key.
101    ///
102    /// # Args
103    /// - `key`: The key of the value to add.
104    /// - `value`: The `string` value to add to the map.
105    ///
106    /// # Return
107    /// Returns `bool` when the operation was successful.
108    /// This method might fail if the map doesn't exist, or the key was already inside of the map.
109    ///
110    /// # Safety
111    /// Do not execute this method if the internal GMS2 functions were not
112    /// registered using `DSMap::register_calls`.
113    pub unsafe fn add_string(&mut self, key: impl ToString, value: impl ToString) -> bool {
114        // Will never fail if key is a valid String
115        let key_cstr = CString::new(
116            key.to_string()
117        ).unwrap();
118
119        // Will never fail if value is a valid String
120        let value_cstr = CString::new(
121            value.to_string()
122        ).unwrap();
123
124        (*FN_DS_MAP_ADD_STRING)(
125            self.map_id,
126            key_cstr.as_ptr(),
127            value_cstr.as_ptr(),
128        )
129    }
130
131    /// Adds a new raw data to the map on a specific key.
132    ///
133    /// # Args
134    /// - `key`: The key of the value to add.
135    /// - `value`: Pointer to the data.
136    ///
137    /// # Return
138    /// Returns `bool` when the operation was successful.
139    /// This method might fail if the map doesn't exist, or the key was already inside of the map.
140    ///
141    /// # Safety
142    /// Do not execute this method if the internal GMS2 functions were not
143    /// registered using `DSMap::register_calls`.
144    ///
145    /// Make sure the raw value that the pointer points to is valid and will not be dealocated by Rust.
146    pub unsafe fn add_raw(&mut self, key: impl ToString, value: *const u8) -> bool {
147        // Will never fail if key is a valid String
148        let key_cstr = CString::new(
149            key.to_string()
150        ).unwrap();
151
152        (*FN_DS_MAP_ADD_STRING)(
153            self.map_id,
154            key_cstr.as_ptr(),
155            value as *const _,
156        )
157    }
158
159    /// Triggers a specific async event inside of the GMS2 and passes the map into it.
160    ///
161    /// This map will be available in GMS2 as `async_load`.
162    ///
163    /// Once the map is dispatched it will be destroyed by the GMS2,
164    /// so any operation on it after this point is not possible.
165    ///
166    /// # Args
167    /// - `event`: Type of the event to trigger.
168    ///
169    /// # Safety
170    /// Do not execute this method if the internal GMS2 functions were not
171    /// registered using `DSMap::register_calls`.
172    pub unsafe fn dispatch(self, event: EventType) {
173        (*FN_EVENT_PERFORM_ASYNC)(self.map_id, event as c_int);
174    }
175}