Skip to main content

yog_api/nanite/
java.rs

1//! Rust types as Java's: each one's descriptor and how its values cross.
2
3use yog_data::Value;
4
5use super::{Handle, Nanite};
6
7/// A Java type a nanite's member takes or gives.
8pub trait Java: Sized {
9    /// Its descriptor (`I`, `Ljava/lang/String;`).
10    fn desc() -> String;
11    fn to_value(&self) -> Value;
12    fn from_value(v: Value) -> Option<Self>;
13}
14
15/// What a member's call gives back, from its reply (`None`: it failed, or
16/// gave null): a number reads as 0 then, an `Option` as `None`.
17pub trait Reply: Sized {
18    /// Its descriptor as a return type.
19    fn desc() -> String;
20    fn from_reply(v: Option<Value>) -> Self;
21}
22
23/// The descriptors of Java's own types.
24const VOID: &str = "V";
25const STRING: &str = "Ljava/lang/String;";
26
27macro_rules! ints {
28    ($($t:ty => $desc:literal),* $(,)?) => {$(
29        impl Java for $t {
30            fn desc() -> String {
31                $desc.to_owned()
32            }
33            fn to_value(&self) -> Value {
34                Value::Int(i64::from(*self))
35            }
36            fn from_value(v: Value) -> Option<Self> {
37                match v {
38                    Value::Int(n) => <$t>::try_from(n).ok(),
39                    _ => None,
40                }
41            }
42        }
43    )*};
44}
45
46ints!(i8 => "B", i16 => "S", u16 => "C", i32 => "I", i64 => "J");
47
48macro_rules! floats {
49    ($($t:ty => $desc:literal),* $(,)?) => {$(
50        impl Java for $t {
51            fn desc() -> String {
52                $desc.to_owned()
53            }
54            fn to_value(&self) -> Value {
55                Value::Float(f64::from(*self))
56            }
57            fn from_value(v: Value) -> Option<Self> {
58                match v {
59                    // The narrowing is Java's own (a float handed back as a double).
60                    Value::Float(f) => Some(f as $t),
61                    Value::Int(n) => Some(n as $t),
62                    _ => None,
63                }
64            }
65        }
66    )*};
67}
68
69floats!(f32 => "F", f64 => "D");
70
71impl Java for bool {
72    fn desc() -> String {
73        "Z".to_owned()
74    }
75    fn to_value(&self) -> Value {
76        Value::Bool(*self)
77    }
78    fn from_value(v: Value) -> Option<Self> {
79        match v {
80            Value::Bool(b) => Some(b),
81            _ => None,
82        }
83    }
84}
85
86impl Java for String {
87    fn desc() -> String {
88        STRING.to_owned()
89    }
90    fn to_value(&self) -> Value {
91        Value::Str(self.clone())
92    }
93    fn from_value(v: Value) -> Option<Self> {
94        match v {
95            Value::Str(s) => Some(s),
96            _ => None,
97        }
98    }
99}
100
101/// A class's descriptor: `L<internal name>;`.
102pub(super) fn class_desc(class: &str) -> String {
103    format!("L{};", class.replace('.', "/"))
104}
105
106impl<T: Nanite> Java for T {
107    fn desc() -> String {
108        class_desc(T::CLASS)
109    }
110    fn to_value(&self) -> Value {
111        self.handle().to_value()
112    }
113    fn from_value(v: Value) -> Option<Self> {
114        Handle::from_value(v).map(T::from_handle)
115    }
116}
117
118/// Every Java value is a reply: missing reads as its default.
119macro_rules! replies {
120    ($($t:ty),* $(,)?) => {$(
121        impl Reply for $t {
122            fn desc() -> String {
123                <$t as Java>::desc()
124            }
125            fn from_reply(v: Option<Value>) -> Self {
126                v.and_then(<$t as Java>::from_value).unwrap_or_default()
127            }
128        }
129    )*};
130}
131
132replies!(i8, i16, u16, i32, i64, f32, f64, bool, String);
133
134impl Reply for () {
135    fn desc() -> String {
136        VOID.to_owned()
137    }
138    fn from_reply(_: Option<Value>) -> Self {}
139}
140
141/// An object (or a null) given back.
142impl<T: Java> Reply for Option<T> {
143    fn desc() -> String {
144        T::desc()
145    }
146    fn from_reply(v: Option<Value>) -> Self {
147        v.and_then(T::from_value)
148    }
149}
150
151/// A nullable object: `None` crosses as null.
152impl<T: Java> Java for Option<T> {
153    fn desc() -> String {
154        T::desc()
155    }
156    fn to_value(&self) -> Value {
157        self.as_ref().map_or(Value::Null, Java::to_value)
158    }
159    fn from_value(v: Value) -> Option<Self> {
160        Some(T::from_value(v))
161    }
162}