1use crate::bus::DeviceBus;
5use crate::call::Call;
6use crate::error::Result;
7use crate::types::{Direction, ImportFileInfo, RobotActionResult, RotationDirection};
8use erased_serde::Serialize as ErasedSerialize;
9use serde::de::DeserializeOwned;
10use uuid::Uuid;
11
12macro_rules! interface {
14 (
15 $(#[$outer:meta])*
16 $vis:vis trait $trait_name:ident {
17 $(const $assoc_const:ident : $assoc_ty:ty;)*
18
19 $(
20 $(#[$inner:meta])*
21 fn $fn_name:ident $(<$($generic:ident),+ $(,)?>)? (&self $(, $($param_name:ident : $param_ty:ty),* $(,)?)?) $(-> $ret_ty:ty)?;
22 )*
23 }
24 ) => {
25
26 $(#[$outer])*
27 $vis trait $trait_name: $crate::device::RpcDevice {
28 $(
29 const $assoc_const: $assoc_ty;
30 )*
31
32 $(
33 $(#[$inner])*
34 #[allow(unused_parens)]
35 fn $fn_name$(<$($generic),+>)?(&self, $($($param_name: $param_ty),*)?) -> $crate::error::Result<($($ret_ty)?)>
36 where ($($ret_ty)?): ::serde::de::DeserializeOwned + 'static;
37 )*
38 }
39 };
40}
41
42#[macro_export]
44macro_rules! device {
45 (
46 #[device(identifier = $identifier:literal)]
47 $(#[$doc:meta])*
48 $vis:vis struct $device_name:ident;
49
50 $(
51 impl $trait_name:ident {
52 $(
53 #[device(invoke = $invoke_name:literal)]
54 fn $fn_name:ident $(<$($generic:ident),+ $(,)?>)? (&self $(, $($param_name:ident : $param_ty:ty),* $(,)?)?) $(-> $ret_ty:ty)?;
55 )+
56 }
57 )+
58
59 ) => {
60 $(#[$doc])*
61 $vis struct $device_name(::uuid::Uuid, $crate::bus::DeviceBus);
62
63 impl $crate::device::RpcDevice for $device_name {
64 const IDENTIFIER: &'static ::core::primitive::str = $identifier;
65
66 fn new(id: ::uuid::Uuid, bus: &$crate::bus::DeviceBus) -> Self {
67 Self(id, bus.clone())
68 }
69
70 fn id(&self) -> ::uuid::Uuid {
71 self.0
72 }
73
74 fn bus(&self) -> &$crate::bus::DeviceBus {
75 &self.1
76 }
77 }
78
79 $(
80 impl $trait_name for $device_name {
81 $(
82 #[allow(non_snake_case)]
83 #[allow(unused_parens)]
84 fn $fn_name$(<$($generic),+>)?(&self, $($($param_name: $param_ty),*)?) -> $crate::error::Result<($($ret_ty)?)>
85 where ($($ret_ty)?): ::serde::de::DeserializeOwned + 'static
86 {
87 $crate::device::invoke(self.0, &self.1, $invoke_name, &[$($(&$param_name as &dyn ::erased_serde::Serialize),*)?])
88 }
89 )+
90 }
91 )+
92 };
93}
94
95#[doc(hidden)]
99#[inline(never)]
100pub fn invoke<R: DeserializeOwned + 'static>(
101 id: Uuid,
102 bus: &DeviceBus,
103 method_name: &str,
104 params: &[&dyn ErasedSerialize],
105) -> Result<R> {
106 let call = Call::invoke(id, method_name, params);
107
108 bus.call(call).map(|r| r.0)
109}
110
111pub trait RpcDevice {
112 const IDENTIFIER: &'static str;
113
114 fn new(id: Uuid, bus: &DeviceBus) -> Self;
115 fn id(&self) -> Uuid;
116 fn bus(&self) -> &DeviceBus;
117}
118
119interface! {
120 pub trait EnergyStorageInterface {
122 fn get_energy_stored(&self) -> i32;
124
125 fn get_max_energy_stored(&self) -> i32;
127
128 fn can_extract_energy(&self) -> bool;
131
132 fn can_receive_energy(&self) -> bool;
134 }
135}
136
137interface! {
138 pub trait ItemHandlerInterface {
140 fn get_item_slot_count(&self) -> i32;
143
144 fn get_item_slot_limit(&self, slot: i32) -> i32;
147
148 fn get_item_stack_in_slot<T>(&self, slot: i32) -> T;
151 }
152}
153
154interface! {
155 pub trait RedstoneInterface {
157 fn get_redstone_input(&self, side: Direction) -> i32;
160
161 fn get_redstone_output(&self, side: Direction) -> i32;
164
165 fn set_redstone_output(&self, side: Direction, val: i32);
168 }
169}
170
171interface! {
172 pub trait SoundInterface {
174 fn find_sound(&self, name: &str) -> Box<[String]>;
177
178 fn play_sound(&self, name: &str, volume: f64, pitch: f64);
180 }
181}
182
183interface! {
184 pub trait FileImportExportInterface {
186 fn request_import_file(&self) -> bool;
188
189 fn begin_import_file(&self) -> Option<ImportFileInfo>;
193
194 fn read_import_file(&self) -> Option<Vec<u8>>;
199
200 fn begin_export_file(&self, name: &str);
202
203 fn write_export_file(&self, data: &[u8]);
205
206 fn finish_export_file(&self);
208
209 fn reset(&self);
211 }
212}
213
214interface! {
215 pub trait BlockOperationsInterface {
217 fn excavate(&self, side: Direction) -> bool;
220
221 fn place(&self, side: Direction) -> bool;
223
224 fn durability(&self) -> i32;
227
228 fn repair(&self) -> bool;
231 }
232}
233
234interface! {
235 pub trait InventoryOperationsInterface {
237 fn move_item(&self, from: i32, into: i32, count: i32);
240
241 fn drop_item(&self, count: i32, side: Direction) -> i32;
244
245 fn drop_item_into(&self, into: i32, count: i32, side: Direction) -> i32;
249
250 fn take_item(&self, count: i32, side: Direction) -> i32;
253
254 fn take_item_from(&self, from: i32, count: i32, side: Direction) -> i32;
257 }
258}
259
260interface! {
261 pub trait RobotInterface {
263 fn get_energy_stored(&self) -> i32;
265
266 fn get_energy_capacity(&self) -> i32;
268
269 fn get_selected_slot(&self) -> i32;
271
272 fn set_selected_slot(&self, slot: i32);
274
275 fn get_stack_in_slot<T>(&self, slot: i32) -> T;
277
278 fn queue_move(&self, direction: Direction) -> bool;
281
282 fn queue_turn(&self, direction: RotationDirection) -> bool;
285
286 fn get_last_action_id(&self) -> i32;
288
289 fn get_queued_action_count(&self) -> i32;
291
292 fn get_action_result(&self, id: i32) -> RobotActionResult;
294 }
295}
296
297device! {
298 #[device(identifier = "redstone")]
299 pub struct RedstoneDevice;
301
302 impl RedstoneInterface {
303 #[device(invoke = "getRedstoneInput")]
304 fn get_redstone_input(&self, side: Direction) -> i32;
305
306 #[device(invoke = "getRedstoneOutput")]
307 fn get_redstone_output(&self, side: Direction) -> i32;
308
309 #[device(invoke = "setRedstoneOutput")]
310 fn set_redstone_output(&self, side: Direction, val: i32);
311 }
312}
313
314device! {
315 #[device(identifier = "sound")]
316 pub struct SoundCard;
318
319 impl SoundInterface {
320 #[device(invoke = "findSound")]
321 fn find_sound(&self, name: &str) -> Box<[String]>;
322
323 #[device(invoke = "playSound")]
324 fn play_sound(&self, name: &str, volume: f64, pitch: f64);
325 }
326}
327
328device! {
329 #[device(identifier = "file_import_export")]
330 pub struct FileImportExportCard;
332
333 impl FileImportExportInterface {
334 #[device(invoke = "requestImportFile")]
335 fn request_import_file(&self) -> bool;
336
337 #[device(invoke = "beginImportFile")]
338 fn begin_import_file(&self) -> Option<ImportFileInfo>;
339
340 #[device(invoke = "readImportFile")]
341 fn read_import_file(&self) -> Option<Vec<u8>>;
342
343 #[device(invoke = "beginExportFile")]
344 fn begin_export_file(&self, name: &str);
345
346 #[device(invoke = "writeExportFile")]
347 fn write_export_file(&self, data: &[u8]);
348
349 #[device(invoke = "finishExportFile")]
350 fn finish_export_file(&self);
351
352 #[device(invoke = "reset")]
353 fn reset(&self);
354 }
355}
356
357device! {
358 #[device(identifier = "inventory_operations")]
359 pub struct InventoryOperationsModule;
361
362 impl InventoryOperationsInterface {
363 #[device(invoke = "move")]
364 fn move_item(&self, from: i32, into: i32, count: i32);
365
366 #[device(invoke = "drop")]
367 fn drop_item(&self, count: i32, side: Direction) -> i32;
368
369 #[device(invoke = "dropInto")]
370 fn drop_item_into(&self, into: i32, count: i32, side: Direction) -> i32;
371
372 #[device(invoke = "take")]
373 fn take_item(&self, count: i32, side: Direction) -> i32;
374
375 #[device(invoke = "takeFrom")]
376 fn take_item_from(&self, from: i32, count: i32, side: Direction) -> i32;
377 }
378}
379
380device! {
381 #[device(identifier = "block_operations")]
382 pub struct BlockOperationsModule;
384
385 impl BlockOperationsInterface {
386 #[device(invoke = "excavate")]
387 fn excavate(&self, side: Direction) -> bool;
388
389 #[device(invoke = "place")]
390 fn place(&self, side: Direction) -> bool;
391
392 #[device(invoke = "durability")]
393 fn durability(&self) -> i32;
394
395 #[device(invoke = "repair")]
396 fn repair(&self) -> bool;
397 }
398}
399
400device! {
401 #[device(identifier = "robot")]
402 pub struct RobotDevice;
403
404 impl RobotInterface {
405 #[device(invoke = "getEnergyStored")]
406 fn get_energy_stored(&self) -> i32;
407
408 #[device(invoke = "getEnergyCapacity")]
409 fn get_energy_capacity(&self) -> i32;
410
411 #[device(invoke = "getSelectedSlot")]
412 fn get_selected_slot(&self) -> i32;
413
414 #[device(invoke = "setSelectedSlot")]
415 fn set_selected_slot(&self, slot: i32);
416
417 #[device(invoke = "getStackInSlot")]
418 fn get_stack_in_slot<T>(&self, slot: i32) -> T;
419
420 #[device(invoke = "move")]
421 fn queue_move(&self, direction: Direction) -> bool;
422
423 #[device(invoke = "turn")]
424 fn queue_turn(&self, direction: RotationDirection) -> bool;
425
426 #[device(invoke = "getLastActionId")]
427 fn get_last_action_id(&self) -> i32;
428
429 #[device(invoke = "getQueuedActionCount")]
430 fn get_queued_action_count(&self) -> i32;
431
432 #[device(invoke = "getActionResult")]
433 fn get_action_result(&self, id: i32) -> RobotActionResult;
434 }
435}