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}