bevy_mod_scripting_bindings/function/
into.rs1use super::{DynamicScriptFunction, DynamicScriptFunctionMut, Union, V};
4use crate::{ReflectReference, ScriptValue, VariadicTuple, WorldExtensions, error::InteropError};
5use bevy_mod_scripting_world::WorldGuard;
6use bevy_platform::collections::HashMap;
7use bevy_reflect::Reflect;
8use std::{borrow::Cow, collections::VecDeque, ffi::OsString, path::PathBuf};
9
10pub trait IntoScript {
12 fn into_script(self, world: WorldGuard) -> Result<ScriptValue, InteropError>;
14
15 fn into_script_inline_error(self, world: WorldGuard) -> ScriptValue
17 where
18 Self: Sized,
19 {
20 self.into_script(world).unwrap_or_else(ScriptValue::Error)
21 }
22}
23
24impl IntoScript for ScriptValue {
25 fn into_script(self, _world: WorldGuard) -> Result<ScriptValue, InteropError> {
26 Ok(self)
27 }
28}
29
30#[profiling::all_functions]
31impl IntoScript for () {
32 fn into_script(self, _world: WorldGuard) -> Result<ScriptValue, InteropError> {
33 Ok(ScriptValue::Unit)
34 }
35}
36
37#[profiling::all_functions]
38impl IntoScript for DynamicScriptFunctionMut {
39 fn into_script(self, _world: WorldGuard) -> Result<ScriptValue, InteropError> {
40 Ok(ScriptValue::FunctionMut(self))
41 }
42}
43
44#[profiling::all_functions]
45impl IntoScript for DynamicScriptFunction {
46 fn into_script(self, _world: WorldGuard) -> Result<ScriptValue, InteropError> {
47 Ok(ScriptValue::Function(self))
48 }
49}
50
51#[profiling::all_functions]
52impl IntoScript for bool {
53 fn into_script(self, _world: WorldGuard) -> Result<ScriptValue, InteropError> {
54 Ok(ScriptValue::Bool(self))
55 }
56}
57
58macro_rules! impl_into_with_downcast {
59 ($variant:tt as $cast:ty [$($ty:ty),*]) => {
60 $(
61 #[profiling::all_functions]
62 impl IntoScript for $ty {
63 fn into_script(self, _world: WorldGuard) -> Result<ScriptValue, InteropError> {
64 Ok(ScriptValue::$variant(self as $cast))
65 }
66 }
67 )*
68 }
69
70}
71
72impl_into_with_downcast!(Integer as i64 [i8, i16, i32, i64, i128, u8, u16, u32, u64, u128, usize, isize]);
73impl_into_with_downcast!(Float as f64 [f32, f64]);
74
75macro_rules! impl_into_stringlike {
76 ($id:ident,[ $(($ty:ty => $conversion:expr)),*]) => {
77 $(
78 #[profiling::all_functions]
79 impl IntoScript for $ty {
80 fn into_script(self, _world: WorldGuard) -> Result<ScriptValue, InteropError> {
81 let $id = self;
82 let converted: String = $conversion;
83 Ok(ScriptValue::String(converted.into()))
84 }
85 }
86 )*
87 }
88}
89
90impl_into_stringlike!(
91 s,
92 [
93 (String => s),
94 (char => s.to_string()),
95 (PathBuf => s.to_string_lossy().to_string()),
96 (OsString => s.into_string().map_err(|e| InteropError::unsupported_operation(None, Some(Box::new(e)), "Could not convert OsString to String".to_owned()))?)
97 ]
98);
99
100#[profiling::all_functions]
101impl IntoScript for &'static str {
102 fn into_script(self, _world: WorldGuard) -> Result<ScriptValue, InteropError> {
103 Ok(ScriptValue::String(Cow::Borrowed(self)))
104 }
105}
106
107#[profiling::all_functions]
108impl IntoScript for ReflectReference {
109 fn into_script(self, _world: WorldGuard) -> Result<ScriptValue, InteropError> {
110 Ok(ScriptValue::Reference(self))
111 }
112}
113
114#[profiling::all_functions]
115impl<T: Reflect> IntoScript for V<T> {
116 fn into_script(self, world: WorldGuard) -> Result<ScriptValue, InteropError> {
117 let boxed = Box::new(self.0);
118 let allocator = world.allocator();
119 let mut allocator = allocator.write();
120
121 Ok(ScriptValue::Reference(
122 ReflectReference::new_allocated_boxed(boxed, &mut allocator),
123 ))
124 }
125}
126
127#[profiling::all_functions]
128impl<T: IntoScript> IntoScript for Option<T> {
129 fn into_script(self, world: WorldGuard) -> Result<ScriptValue, InteropError> {
130 match self {
131 Some(val) => val.into_script(world),
132 None => Ok(ScriptValue::Unit),
133 }
134 }
135}
136
137#[profiling::all_functions]
138impl<T: IntoScript> IntoScript for Vec<T> {
139 fn into_script(self, world: WorldGuard) -> Result<ScriptValue, InteropError> {
140 let mut values = VecDeque::with_capacity(self.len());
141 for val in self {
142 values.push_back(val.into_script(world.clone())?);
143 }
144 Ok(ScriptValue::List(values))
145 }
146}
147
148#[profiling::all_functions]
149impl<T: IntoScript> IntoScript for VecDeque<T> {
150 fn into_script(self, world: WorldGuard) -> Result<ScriptValue, InteropError> {
151 let mut values = VecDeque::with_capacity(self.len());
152 for val in self {
153 values.push_back(val.into_script(world.clone())?);
154 }
155 Ok(ScriptValue::List(values))
156 }
157}
158
159#[profiling::all_functions]
160impl<T: IntoScript, const N: usize> IntoScript for [T; N] {
161 fn into_script(self, world: WorldGuard) -> Result<ScriptValue, InteropError> {
162 let mut values = VecDeque::with_capacity(N);
163 for val in self {
164 values.push_back(val.into_script(world.clone())?);
165 }
166 Ok(ScriptValue::List(values))
167 }
168}
169
170#[profiling::all_functions]
171impl<T1: IntoScript, T2: IntoScript> IntoScript for Union<T1, T2> {
172 fn into_script(self, world: WorldGuard) -> Result<ScriptValue, InteropError> {
173 match self.into_left() {
174 Ok(left) => left.into_script(world),
175 Err(right) => right.into_script(world),
176 }
177 }
178}
179
180#[profiling::all_functions]
181impl<V: IntoScript> IntoScript for HashMap<String, V> {
182 fn into_script(self, world: WorldGuard) -> Result<ScriptValue, InteropError> {
183 let mut map = HashMap::new();
184 for (key, value) in self {
185 map.insert(key, value.into_script(world.clone())?);
186 }
187 Ok(ScriptValue::Map(map))
188 }
189}
190
191#[profiling::all_functions]
192impl<V: IntoScript> IntoScript for std::collections::HashMap<String, V> {
193 fn into_script(self, world: WorldGuard) -> Result<ScriptValue, InteropError> {
194 let mut map = HashMap::new();
195 for (key, value) in self {
196 map.insert(key, value.into_script(world.clone())?);
197 }
198 Ok(ScriptValue::Map(map))
199 }
200}
201
202#[profiling::all_functions]
203impl IntoScript for InteropError {
204 fn into_script(self, _world: WorldGuard) -> Result<ScriptValue, InteropError> {
205 Ok(ScriptValue::Error(self))
206 }
207}
208
209impl IntoScript for VariadicTuple {
210 fn into_script(self, _world: WorldGuard) -> Result<ScriptValue, InteropError> {
211 Ok(ScriptValue::Tuple(self))
212 }
213}
214
215macro_rules! impl_into_script_tuple {
216 ($( $ty:ident ),* ) => {
217 #[allow(non_snake_case)]
218 #[profiling::all_functions]
219 impl<$($ty: IntoScript),*> IntoScript for ($($ty,)*) {
220 fn into_script(self, world: WorldGuard) -> Result<ScriptValue, InteropError> {
221 let ($($ty,)*) = self;
222 Ok(ScriptValue::Tuple(crate::script_value::VariadicTuple(VecDeque::from_iter([$($ty.into_script(world.clone())?),*].into_iter()))))
223 }
224 }
225}
226}
227
228variadics_please::all_tuples!(impl_into_script_tuple, 1, 14, T);