Skip to main content

yog_event/
arg.rs

1//! What an action's argument may be given as: the type itself, or a form
2//! that's plainly the same value — text as any string, a position as an
3//! array or a tuple, bytes as a slice. A number is only itself, so a
4//! literal reads as the type the action takes (`give_item(p, id, 1)`).
5
6use std::borrow::Cow;
7
8use yog_core::{BlockPos, Point};
9use yog_data::Atom;
10
11/// An argument given as `Self` for a field of type `T`.
12pub trait Arg<T> {
13    fn arg(self) -> T;
14}
15
16impl<T> Arg<T> for T {
17    fn arg(self) -> T {
18        self
19    }
20}
21
22macro_rules! args {
23    ($($from:ty => $to:ty, |$v:ident| $make:expr;)*) => {
24        $(impl Arg<$to> for $from {
25            fn arg(self) -> $to {
26                let $v = self;
27                $make
28            }
29        })*
30    };
31}
32
33args! {
34    &str => String, |s| s.to_owned();
35    &String => String, |s| s.clone();
36    Cow<'_, str> => String, |s| s.into_owned();
37    Atom => String, |a| a.as_str().to_owned();
38    &Atom => String, |a| a.as_str().to_owned();
39    Option<&str> => Option<String>, |s| s.map(str::to_owned);
40    Option<&String> => Option<String>, |s| s.cloned();
41    &[u8] => Vec<u8>, |b| b.to_vec();
42    &Vec<u8> => Vec<u8>, |b| b.clone();
43    &[&str] => Vec<String>, |l| l.iter().map(|s| (*s).to_owned()).collect();
44    Vec<&str> => Vec<String>, |l| l.into_iter().map(str::to_owned).collect();
45    &[String] => Vec<String>, |l| l.to_vec();
46    [i32; 3] => BlockPos, |p| p.into();
47    (i32, i32, i32) => BlockPos, |p| p.into();
48    [f64; 3] => Point, |p| p.into();
49    (f64, f64, f64) => Point, |p| p.into();
50    BlockPos => Point, |p| p.into();
51}
52
53/// Bytes as an array (`&[on as u8]`).
54impl<const N: usize> Arg<Vec<u8>> for &[u8; N] {
55    fn arg(self) -> Vec<u8> {
56        self.to_vec()
57    }
58}
59
60#[cfg(test)]
61mod tests {
62    use super::*;
63
64    fn take<T>(v: impl Arg<T>) -> T {
65        v.arg()
66    }
67
68    #[test]
69    fn a_literal_is_the_number_taken_and_text_any_string() {
70        let n: u32 = take(1);
71        assert_eq!(n, 1);
72        let s: String = take("a");
73        assert_eq!(s, "a");
74        let p: BlockPos = take([1, 2, 3]);
75        assert_eq!(p, BlockPos::new(1, 2, 3));
76        let o: Option<String> = take(Some("u"));
77        assert_eq!(o.as_deref(), Some("u"));
78    }
79}