turing_api/
lib.rs

1use std::any::Any;
2use std::cell::RefCell;
3use std::collections::HashMap;
4use std::ffi::{c_char, CString};
5use once_cell::unsync::Lazy;
6use paste::paste;
7
8macro_rules! typed_ptr {
9    ( $name:ident ) => {
10        #[repr(C)]
11        #[derive(Copy, Clone)]
12        struct $name {
13            ptr: *mut c_char
14        }
15    };
16}
17
18typed_ptr!(_Color);
19typed_ptr!(_ColorNote);
20typed_ptr!(_BombNote);
21typed_ptr!(_ChainHeadNote);
22typed_ptr!(_ChainLinkNote);
23typed_ptr!(_ChainNote);
24typed_ptr!(_Arc);
25typed_ptr!(_Wall);
26typed_ptr!(_Saber);
27// typed_ptr!(_Player);
28typed_ptr!(_Vec2);
29typed_ptr!(_Vec3);
30typed_ptr!(_Vec4);
31typed_ptr!(_Quat);
32
33macro_rules! color_methods {
34    ( $tp:ty, $name:tt ) => {
35        paste! {
36            extern "C" {
37                fn [<_ $name _set_color>]($name: $tp, color: _Color);
38                fn [<_ $name _get_color>]($name: $tp) -> _Color;
39            }
40        }
41    }
42}
43
44macro_rules! position_methods {
45    ( $tp:ty, $name:tt ) => {
46        paste! {
47            extern "C" {
48                fn [<_ $name _set_position>]($name: $tp, pos: _Vec3);
49                fn [<_ $name _get_position>]($name: $tp) -> _Vec3;
50                fn [<_ $name _set_orientation>]($name: $tp, orientation: _Quat);
51                fn [<_ $name _get_orientation>]($name: $tp) -> _Quat;
52            }
53        }
54    }
55}
56
57macro_rules! gameplay_object_methods {
58    ( $tp:ty, $name:tt ) => {
59        paste! {
60            extern "C" {
61                fn [<_create_ $name>](beat: f32) -> $tp;
62                fn [<_beatmap_add_ $name>]($name: $tp);
63                fn [<_beatmap_remove_ $name>]($name: $tp);
64            }
65        }
66        position_methods! { $tp, $name }
67        color_methods! { $tp, $name }
68    };
69}
70
71macro_rules! attrs {
72    ( $tp:ty, $name:tt, $( $attr:ident: $attr_tp:ty ),* $(,)? ) => {
73        extern "C" {
74            paste! {
75                $(
76                fn [<_ $name _get_attr_ $attr>]($name: [<_ $tp>]) -> $attr_tp;
77                fn [<_ $name _set_attr_ $attr>]($name: [<_ $tp>], $attr: $attr_tp);
78                )*
79            }
80        }
81
82        impl $tp {
83            $(
84
85            paste! {
86                pub fn [<get_ $attr>](&self) -> $attr_tp {
87                    unsafe { [<_ $name _get_attr_ $attr>](self._inner) }
88                }
89                pub fn [<set_ $attr>](&self, $attr: $attr_tp) {
90                    unsafe { [<_ $name _set_attr_ $attr>](self._inner, $attr) }
91                }
92            }
93
94            )*
95        }
96    };
97}
98
99gameplay_object_methods! { _ColorNote, color_note }
100gameplay_object_methods! { _BombNote, bomb_note }
101gameplay_object_methods! { _Arc, arc }
102gameplay_object_methods! { _Wall, wall }
103gameplay_object_methods! { _ChainHeadNote, chain_head_note }
104gameplay_object_methods! { _ChainLinkNote, chain_link_note }
105gameplay_object_methods! { _ChainNote, chain_note }
106
107color_methods! { _Saber, saber }
108
109extern "C" {
110    fn _get_left_saber() -> _Saber;
111    fn _get_right_saber() -> _Saber;
112
113    fn _log(message: *const c_char);
114
115    // drops a host-managed object such as color notes, vectors, walls, etc
116    fn _drop_reference(ptr: *mut c_char);
117
118
119    fn _vec2_from_native(x: f32, y: f32) -> _Vec2;
120    fn _vec3_from_native(x: f32, y: f32, z: f32) -> _Vec3;
121    fn _vec4_from_native(x: f32, y: f32, z: f32, w: f32) -> _Vec4;
122    fn _quat_from_native(x: f32, y: f32, z: f32, w: f32) -> _Quat;
123
124    fn _color_set_rgb(color: _Color, r: f32, g: f32, b: f32);
125    fn _color_set_rgba(color: _Color, r: f32, g: f32, b: f32, a: f32);
126
127}
128
129macro_rules! cstr {
130    ( $str:expr ) => {
131        CString::new($str).unwrap()
132    };
133}
134
135// User facing definitions:
136
137pub struct Log {}
138impl Log {
139    pub fn info(message: &str) {
140        let s = format!("info: {}", message);
141        let c = cstr!(s);
142        unsafe { _log(c.as_ptr()) };
143    }
144
145    pub fn warning(message: &str) {
146        let s = format!("warning: {}", message);
147        let c = cstr!(s);
148        unsafe { _log(c.as_ptr()) };
149    }
150
151    pub fn error(message: &str) {
152        let s = format!("error: {}", message);
153        let c = cstr!(s);
154        unsafe { _log(c.as_ptr()) };
155    }
156
157    pub fn debug(message: &str) {
158        let s = format!("debug: {}", message);
159        let c = cstr!(s);
160        unsafe { _log(c.as_ptr()) };
161    }
162
163}
164
165macro_rules! wrapped {
166    ( $name:tt ) => {
167        pub struct $name {
168            _inner: paste! { [<_ $name>] }
169        }
170    };
171}
172
173macro_rules! instantiable_obj {
174    ( $ty:tt, $name:tt ) => {
175        wrapped! { $ty }
176        paste! {
177
178            pub fn [<create_ $name>](beat: f32) -> $ty {
179                unsafe { $ty { _inner: [<_create_ $name>](beat) } }
180            }
181
182            impl Beatmap {
183                pub fn [<add_ $name>]($name: $ty) {
184                    unsafe {
185                        [<_beatmap_add_ $name>]($name._inner);
186                    }
187                }
188            }
189        }
190    };
191}
192
193pub struct Beatmap;
194
195thread_local! {
196    static GLOBAL_MAP: Lazy<RefCell<HashMap<String, Box<dyn Any>>>> = Lazy::new(|| {
197        RefCell::new(HashMap::new())
198    });
199}
200
201pub struct Data;
202
203impl Data {
204
205    pub fn set_temp_value<T: Clone + 'static>(key: &str, v: T) {
206        GLOBAL_MAP.with(|map| {
207            map.borrow_mut().insert(key.to_string(), Box::new(v));
208        })
209    }
210
211    pub fn get_temp_value<T: Clone + 'static>(key: &str) -> Option<T> {
212        GLOBAL_MAP.with(|map| {
213            map.borrow().get(key).and_then(|v| v.downcast_ref::<T>()).cloned()
214        })
215    }
216
217    pub fn remove_temp_value(key: &str) {
218        GLOBAL_MAP.with(|map| {
219            map.borrow_mut().remove(key);
220        })
221    }
222
223}
224
225instantiable_obj! { ColorNote, color_note }
226instantiable_obj! { BombNote, bomb_note }
227instantiable_obj! { ChainHeadNote, chain_head_note }
228instantiable_obj! { ChainLinkNote, chain_link_note }
229instantiable_obj! { ChainNote, chain_note }
230instantiable_obj! { Arc, arc }
231instantiable_obj! { Wall, wall }
232
233wrapped! { Vec2 }
234
235
236wrapped! { Vec3 }
237wrapped! { Vec4 }
238wrapped! { Quat }
239wrapped! { Color }
240
241attrs! { Vec2, vec2, x: f32, y: f32 }
242attrs! { Vec3, vec3, x: f32, y: f32, z: f32 }
243attrs! { Vec4, vec4, x: f32, y: f32, z: f32, w: f32 }
244attrs! { Quat, quat, x: f32, y: f32, z: f32, w: f32 }
245attrs! { Color, color, r: f32, g: f32, b: f32, a: f32 }
246
247pub trait UnityConvertible {
248    type UnityType;
249    fn to_unity_type(self) -> Self::UnityType;
250    fn from_unity_type(t: Self::UnityType) -> Self;
251}
252
253impl UnityConvertible for glam::Vec2 {
254    type UnityType = Vec2;
255    fn to_unity_type(self) -> Self::UnityType {
256        Vec2 { _inner: unsafe { _vec2_from_native(self.x, self.y) } }
257    }
258    fn from_unity_type(t: Self::UnityType) -> Self {
259        glam::Vec2::new(t.get_x(), t.get_y())
260    }
261}
262
263impl UnityConvertible for glam::Vec3 {
264    type UnityType = Vec3;
265    fn to_unity_type(self) -> Self::UnityType {
266        Vec3 { _inner: unsafe { _vec3_from_native(self.x, self.y, self.z) } }
267    }
268    fn from_unity_type(t: Self::UnityType) -> Self {
269        glam::Vec3::new(t.get_x(), t.get_y(), t.get_z())
270    }
271}
272
273impl UnityConvertible for glam::Vec4 {
274    type UnityType = Vec4;
275    fn to_unity_type(self) -> Self::UnityType {
276        Vec4 { _inner: unsafe { _vec4_from_native(self.x, self.y, self.z, self.w) } }
277    }
278    fn from_unity_type(t: Self::UnityType) -> Self {
279        glam::Vec4::new(t.get_x(), t.get_y(), t.get_z(), t.get_w())
280    }
281}
282
283impl UnityConvertible for glam::Quat {
284    type UnityType = Quat;
285    fn to_unity_type(self) -> Self::UnityType {
286        Quat { _inner: unsafe { _quat_from_native(self.x, self.y, self.z, self.w) } }
287    }
288    fn from_unity_type(t: Self::UnityType) -> Self {
289        glam::Quat::from_xyzw(t.get_x(), t.get_y(), t.get_z(), t.get_w())
290    }
291}
292
293
294impl Color {
295    pub fn set_rgb(&self, r: f32, g: f32, b: f32) {
296        unsafe { _color_set_rgb(self._inner, r, g, b) };
297    }
298
299    pub fn set_rgba(&self, r: f32, g: f32, b: f32, a: f32) {
300        unsafe { _color_set_rgba(self._inner, r, g, b, a) };
301    }
302}
303