1use std::num::{
2 NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128, NonZeroIsize, NonZeroU8,
3 NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, NonZeroUsize,
4};
5use std::ptr::NonNull;
6
7#[derive(Debug)]
9pub struct ScriptModuleCallHandle {
10 pub(crate) internal: *mut aviutl2_sys::module2::SCRIPT_MODULE_PARAM,
11 pub(crate) read_section: crate::generic::ReadSection,
12}
13
14#[derive(thiserror::Error, Debug)]
16pub enum ScriptModuleCallHandleError<E: std::fmt::Debug = std::convert::Infallible> {
17 #[error("expected {expected:?}, but got {actual:?}")]
18 TypeMismatch {
19 expected: ParamType,
21 actual: ParamType,
23 },
24
25 #[error("key contains null byte")]
26 KeyContainsNullByte(std::ffi::NulError),
27
28 #[error("value contains null byte")]
29 ValueContainsNullByte(std::ffi::NulError),
30
31 #[error("too many elements")]
32 TooManyElements,
33
34 #[error("failed to convert value: {0}")]
35 ConversionError(E),
36}
37
38pub type ScriptModuleCallHandleResult<T, E = std::convert::Infallible> =
39 std::result::Result<T, ScriptModuleCallHandleError<E>>;
40
41impl ScriptModuleCallHandleError<std::convert::Infallible> {
42 fn into_conversion_error<E: std::fmt::Debug>(self) -> ScriptModuleCallHandleError<E> {
43 match self {
44 ScriptModuleCallHandleError::TypeMismatch { expected, actual } => {
45 ScriptModuleCallHandleError::TypeMismatch { expected, actual }
46 }
47 ScriptModuleCallHandleError::KeyContainsNullByte(error) => {
48 ScriptModuleCallHandleError::KeyContainsNullByte(error)
49 }
50 ScriptModuleCallHandleError::ValueContainsNullByte(error) => {
51 ScriptModuleCallHandleError::ValueContainsNullByte(error)
52 }
53 ScriptModuleCallHandleError::TooManyElements => {
54 ScriptModuleCallHandleError::TooManyElements
55 }
56 ScriptModuleCallHandleError::ConversionError(error) => match error {},
57 }
58 }
59}
60
61pub trait FromScriptModuleInteger: Sized {
63 type Error: std::fmt::Debug;
64
65 fn from_script_module_integer(value: i32) -> Result<Self, Self::Error>;
66}
67
68#[duplicate::duplicate_item(
69 Integer;
70 [i8];
71 [i16];
72 [isize];
73 [u8];
74 [u16];
75 [u32];
76 [u64];
77 [u128];
78 [usize];
79)]
80impl FromScriptModuleInteger for Integer {
81 type Error = <Self as TryFrom<i32>>::Error;
82
83 fn from_script_module_integer(value: i32) -> Result<Self, Self::Error> {
84 value.try_into()
85 }
86}
87impl FromScriptModuleInteger for i32 {
88 type Error = std::convert::Infallible;
89
90 fn from_script_module_integer(value: i32) -> Result<Self, Self::Error> {
91 Ok(value)
92 }
93}
94#[duplicate::duplicate_item(
95 Integer;
96 [i64];
97 [i128];
98)]
99impl FromScriptModuleInteger for Integer {
100 type Error = std::convert::Infallible;
101
102 fn from_script_module_integer(value: i32) -> Result<Self, Self::Error> {
103 Ok(value.into())
104 }
105}
106
107fn convert_script_module_integer<T>(value: i32) -> ScriptModuleCallHandleResult<T, T::Error>
108where
109 T: FromScriptModuleInteger,
110{
111 T::from_script_module_integer(value).map_err(ScriptModuleCallHandleError::ConversionError)
112}
113
114#[derive(Debug, Clone, Copy)]
116pub struct ScriptModuleFunctionCallback {
117 pub func: unsafe extern "C" fn(*mut aviutl2_sys::module2::SCRIPT_MODULE_PARAM),
118 pub userdata: *mut std::ffi::c_void,
119}
120
121pub struct ScriptModuleUserData<T: Send + Sync + 'static + AsScriptModuleUserData> {
123 data: std::sync::Arc<std::sync::Mutex<T>>,
124}
125
126struct MetaMethodFunctionTableEntry {
127 meta_method_functions: Box<[aviutl2_sys::module2::META_METHOD_FUNCTION]>,
128}
129unsafe impl Send for MetaMethodFunctionTableEntry {}
130unsafe impl Sync for MetaMethodFunctionTableEntry {}
131
132fn type_to_meta_method_functions<T: Send + Sync + 'static + AsScriptModuleUserData>()
135-> *const aviutl2_sys::module2::META_METHOD_FUNCTION {
136 static META_METHOD_FUNCTIONS: std::sync::LazyLock<
137 dashmap::DashMap<std::any::TypeId, MetaMethodFunctionTableEntry>,
138 > = std::sync::LazyLock::new(Default::default);
139
140 let type_id = std::any::TypeId::of::<T>();
141 META_METHOD_FUNCTIONS
142 .entry(type_id)
143 .or_insert_with(|| {
144 let last = T::META_METHOD_FUNCTIONS.last();
145 assert!(
146 last.is_some() && last.unwrap().method.is_null(),
147 "META_METHOD_FUNCTIONS must be null-terminated"
148 );
149 MetaMethodFunctionTableEntry {
150 meta_method_functions: T::META_METHOD_FUNCTIONS.to_vec().into_boxed_slice(),
151 }
152 })
153 .meta_method_functions
154 .as_ptr()
155}
156
157#[derive(Debug)]
159pub struct ErasedScriptModuleUserData {
160 pub meta_method_functions: *const aviutl2_sys::module2::META_METHOD_FUNCTION,
161 pub userdata: *mut std::ffi::c_void,
162}
163
164impl<T: Send + Sync + 'static + AsScriptModuleUserData> From<ScriptModuleUserData<T>>
165 for ErasedScriptModuleUserData
166{
167 fn from(meta_table: ScriptModuleUserData<T>) -> Self {
168 let data = Box::into_raw(Box::new(meta_table.data)) as *mut std::ffi::c_void;
169 let meta_method_functions = type_to_meta_method_functions::<T>();
170 ErasedScriptModuleUserData {
171 meta_method_functions,
172 userdata: data,
173 }
174 }
175}
176impl<T: Send + Sync + 'static + AsScriptModuleUserData> ScriptModuleUserData<T> {
177 pub fn new(data: T) -> Self {
179 ScriptModuleUserData {
180 data: std::sync::Arc::new(std::sync::Mutex::new(data)),
181 }
182 }
183
184 pub fn lock(
186 &self,
187 ) -> Result<std::sync::MutexGuard<'_, T>, std::sync::PoisonError<std::sync::MutexGuard<'_, T>>>
188 {
189 self.data.lock()
190 }
191}
192impl<T: Send + Sync + 'static + AsScriptModuleUserData> From<T> for ScriptModuleUserData<T> {
193 fn from(data: T) -> Self {
194 ScriptModuleUserData::new(data)
195 }
196}
197
198unsafe extern "C" fn dummy_meta_method_function(
199 _smp: *mut aviutl2_sys::module2::SCRIPT_MODULE_PARAM,
200) {
201 }
203unsafe extern "C" fn script_module_user_data_gc<
204 T: Send + Sync + 'static + AsScriptModuleUserData,
205>(
206 smp: *mut aviutl2_sys::module2::SCRIPT_MODULE_PARAM,
207) {
208 let userdata = unsafe { (*smp).userdata };
209 if !userdata.is_null() {
210 unsafe {
211 drop(Box::<std::sync::Arc<std::sync::Mutex<T>>>::from_raw(
212 userdata as *mut std::sync::Arc<std::sync::Mutex<T>>,
213 ));
214 }
215 }
216}
217
218pub trait AsScriptModuleUserData: Send + Sync + Sized + 'static {
224 const META_METHOD_FUNCTIONS: &'static [aviutl2_sys::module2::META_METHOD_FUNCTION] = &[
225 aviutl2_sys::module2::META_METHOD_FUNCTION {
226 method: c"__gc".as_ptr(),
227 func: script_module_user_data_gc::<Self>,
228 },
229 aviutl2_sys::module2::META_METHOD_FUNCTION {
230 method: std::ptr::null(),
231 func: dummy_meta_method_function,
232 },
233 ];
234}
235
236#[derive(Debug, Clone, Copy, PartialEq, Eq)]
242pub enum ParamType {
243 Nil,
244 Boolean,
245 LightUserdata,
246 Number,
247 String,
248 Table,
249 Function,
250 Userdata,
251 Thread,
252}
253
254#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
256pub enum GetParamError<T: std::fmt::Debug> {
257 #[error("expected {expected:?}, but got {actual:?}")]
258 TypeMismatch {
259 expected: ParamType,
261 actual: ParamType,
263 },
264 #[error("index {index} is out of bounds, {len} given")]
265 IndexOutOfBounds {
266 index: usize,
268 len: usize,
270 },
271 #[error("failed to convert value: {0}")]
272 ConversionError(T),
273}
274pub type GetParamResult<T, E = std::convert::Infallible> = std::result::Result<T, GetParamError<E>>;
275
276#[derive(Debug, thiserror::Error)]
278#[error("{message}")]
279pub struct ParamConversionError {
280 message: String,
281}
282
283impl ParamConversionError {
284 pub fn new(message: impl Into<String>) -> Self {
285 Self {
286 message: message.into(),
287 }
288 }
289}
290
291impl GetParamError<std::convert::Infallible> {
292 fn into_conversion_error<T: std::fmt::Debug>(self) -> GetParamError<T> {
293 match self {
294 GetParamError::TypeMismatch { expected, actual } => {
295 GetParamError::TypeMismatch { expected, actual }
296 }
297 GetParamError::IndexOutOfBounds { index, len } => {
298 GetParamError::IndexOutOfBounds { index, len }
299 }
300 GetParamError::ConversionError(error) => match error {},
301 }
302 }
303}
304
305impl ScriptModuleCallHandle {
306 pub unsafe fn from_raw(
312 ptr: *mut aviutl2_sys::module2::SCRIPT_MODULE_PARAM,
313 ) -> ScriptModuleCallHandle {
314 ScriptModuleCallHandle {
315 internal: ptr,
316 read_section: unsafe { crate::generic::ReadSection::from_raw((*ptr).edit) },
317 }
318 }
319
320 pub fn len(&self) -> usize {
322 unsafe { ((*self.internal).get_param_num)() as usize }
323 }
324
325 pub fn is_empty(&self) -> bool {
327 self.len() == 0
328 }
329
330 pub fn get_param_type(&self, index: usize) -> Option<ParamType> {
336 let param_type = unsafe { ((*self.internal).get_param_type)(index as i32) };
337 match param_type {
338 aviutl2_sys::module2::PARAM_TYPE::NONE => None,
339 aviutl2_sys::module2::PARAM_TYPE::NIL => Some(ParamType::Nil),
340 aviutl2_sys::module2::PARAM_TYPE::BOOLEAN => Some(ParamType::Boolean),
341 aviutl2_sys::module2::PARAM_TYPE::LIGHTUSERDATA => Some(ParamType::LightUserdata),
342 aviutl2_sys::module2::PARAM_TYPE::NUMBER => Some(ParamType::Number),
343 aviutl2_sys::module2::PARAM_TYPE::STRING => Some(ParamType::String),
344 aviutl2_sys::module2::PARAM_TYPE::TABLE => Some(ParamType::Table),
345 aviutl2_sys::module2::PARAM_TYPE::FUNCTION => Some(ParamType::Function),
346 aviutl2_sys::module2::PARAM_TYPE::USERDATA => Some(ParamType::Userdata),
347 aviutl2_sys::module2::PARAM_TYPE::THREAD => Some(ParamType::Thread),
348 }
349 }
350
351 fn assert_param_type(&self, index: usize, expected: ParamType) -> GetParamResult<()> {
352 let actual = self
353 .get_param_type(index)
354 .ok_or(GetParamError::IndexOutOfBounds {
355 index,
356 len: self.len(),
357 })?;
358 if actual != expected {
359 return Err(GetParamError::TypeMismatch { expected, actual });
360 }
361 Ok(())
362 }
363
364 fn assert_param_type_for_call(
365 &self,
366 index: usize,
367 expected: ParamType,
368 ) -> ScriptModuleCallHandleResult<()> {
369 let Some(actual) = self.get_param_type(index) else {
370 return Ok(());
371 };
372 if actual != expected {
373 return Err(ScriptModuleCallHandleError::TypeMismatch { expected, actual });
374 }
375 Ok(())
376 }
377
378 pub fn get_param<'a, T: FromScriptModuleParam<'a>>(
380 &'a self,
381 index: usize,
382 ) -> GetParamResult<T, T::Error> {
383 T::from_param(self, index)
384 }
385
386 pub fn get_param_int(&self, index: usize) -> GetParamResult<i32> {
388 self.assert_param_type(index, ParamType::Number)?;
389 Ok(unsafe { ((*self.internal).get_param_int)(index as i32) })
390 }
391
392 pub fn get_param_float(&self, index: usize) -> GetParamResult<f64> {
394 self.assert_param_type(index, ParamType::Number)?;
395 Ok(unsafe { ((*self.internal).get_param_double)(index as i32) })
396 }
397
398 pub fn get_param_str(&self, index: usize) -> GetParamResult<String> {
400 self.assert_param_type(index, ParamType::String)?;
401 unsafe {
402 let c_str = ((*self.internal).get_param_string)(index as i32);
403 assert!(!c_str.is_null(), "get_param_string returned null");
404 Ok(std::ffi::CStr::from_ptr(c_str)
405 .to_string_lossy()
406 .into_owned())
407 }
408 }
409
410 pub fn get_param_data<T>(&self, index: usize) -> GetParamResult<*mut T> {
412 let param_type = self
414 .get_param_type(index)
415 .ok_or(GetParamError::IndexOutOfBounds {
416 index,
417 len: self.len(),
418 })?;
419 if param_type != ParamType::LightUserdata && param_type != ParamType::Userdata {
420 return Err(GetParamError::TypeMismatch {
421 expected: ParamType::LightUserdata,
422 actual: param_type,
423 });
424 }
425 unsafe { Ok(((*self.internal).get_param_data)(index as i32) as *mut T) }
426 }
427
428 pub fn get_param_userdata<T: AsScriptModuleUserData>(
435 &self,
436 index: usize,
437 ) -> GetParamResult<ScriptModuleUserData<T>, ParamConversionError> {
438 self.assert_param_type(index, ParamType::Userdata)
439 .map_err(GetParamError::into_conversion_error)?;
440 let ptr = unsafe {
441 ((*self.internal).get_param_meta_table)(
442 index as i32,
443 type_to_meta_method_functions::<T>() as _,
444 )
445 };
446 if ptr.is_null() {
447 return Err(GetParamError::ConversionError(ParamConversionError::new(
448 "userdata type mismatch",
449 )));
450 }
451 let arc_ref = unsafe {
452 let boxed = &*(ptr as *const std::sync::Arc<std::sync::Mutex<T>>);
453 boxed.clone()
454 };
455 Ok(ScriptModuleUserData { data: arc_ref })
456 }
457
458 pub fn get_param_boolean(&self, index: usize) -> GetParamResult<bool> {
460 self.assert_param_type(index, ParamType::Boolean)?;
461 unsafe { Ok(((*self.internal).get_param_boolean)(index as i32)) }
462 }
463
464 pub fn get_param_table_int(
470 &self,
471 index: usize,
472 key: &str,
473 ) -> ScriptModuleCallHandleResult<i32> {
474 self.assert_param_type_for_call(index, ParamType::Table)?;
475 let c_key = std::ffi::CString::new(key)
476 .map_err(ScriptModuleCallHandleError::KeyContainsNullByte)?;
477 Ok(unsafe { ((*self.internal).get_param_table_int)(index as i32, c_key.as_ptr()) })
478 }
479
480 pub fn get_param_table_integer<T>(
482 &self,
483 index: usize,
484 key: &str,
485 ) -> ScriptModuleCallHandleResult<T, T::Error>
486 where
487 T: FromScriptModuleInteger,
488 {
489 let value = self
490 .get_param_table_int(index, key)
491 .map_err(ScriptModuleCallHandleError::into_conversion_error)?;
492 convert_script_module_integer(value)
493 }
494
495 pub fn get_param_table_float(
501 &self,
502 index: usize,
503 key: &str,
504 ) -> ScriptModuleCallHandleResult<f64> {
505 self.assert_param_type_for_call(index, ParamType::Table)?;
506 let c_key = std::ffi::CString::new(key)
507 .map_err(ScriptModuleCallHandleError::KeyContainsNullByte)?;
508 Ok(unsafe { ((*self.internal).get_param_table_double)(index as i32, c_key.as_ptr()) })
509 }
510
511 pub fn get_param_table_str(
513 &self,
514 index: usize,
515 key: &str,
516 ) -> ScriptModuleCallHandleResult<Option<String>> {
517 self.assert_param_type_for_call(index, ParamType::Table)?;
518 let c_key = std::ffi::CString::new(key)
519 .map_err(ScriptModuleCallHandleError::KeyContainsNullByte)?;
520 unsafe {
521 let c_str = ((*self.internal).get_param_table_string)(index as i32, c_key.as_ptr());
522 Ok(if c_str.is_null() {
523 None
524 } else {
525 Some(
526 std::ffi::CStr::from_ptr(c_str)
527 .to_string_lossy()
528 .into_owned(),
529 )
530 })
531 }
532 }
533
534 pub fn get_param_table_boolean(
540 &self,
541 index: usize,
542 key: &str,
543 ) -> ScriptModuleCallHandleResult<bool> {
544 self.assert_param_type_for_call(index, ParamType::Table)?;
545 let c_key = std::ffi::CString::new(key)
546 .map_err(ScriptModuleCallHandleError::KeyContainsNullByte)?;
547 Ok(unsafe { ((*self.internal).get_param_table_boolean)(index as i32, c_key.as_ptr()) })
548 }
549
550 pub fn get_param_array_len(&self, index: usize) -> usize {
552 unsafe { ((*self.internal).get_param_array_num)(index as i32) as usize }
553 }
554
555 pub fn get_param_array_int(&self, index: usize, array_index: usize) -> i32 {
557 unsafe { ((*self.internal).get_param_array_int)(index as i32, array_index as i32) }
558 }
559
560 pub fn get_param_array_float(&self, index: usize, array_index: usize) -> f64 {
562 unsafe { ((*self.internal).get_param_array_double)(index as i32, array_index as i32) }
563 }
564
565 pub fn get_param_array_str(&self, index: usize, array_index: usize) -> Option<String> {
567 unsafe {
568 let c_str = ((*self.internal).get_param_array_string)(index as i32, array_index as i32);
569 if c_str.is_null() {
570 None
571 } else {
572 Some(
573 std::ffi::CStr::from_ptr(c_str)
574 .to_string_lossy()
575 .into_owned(),
576 )
577 }
578 }
579 }
580
581 pub fn set_error(&mut self, message: &str) -> ScriptModuleCallHandleResult<()> {
583 let c_message = std::ffi::CString::new(message)
584 .map_err(ScriptModuleCallHandleError::ValueContainsNullByte)?;
585 unsafe {
586 ((*self.internal).set_error)(c_message.as_ptr());
587 }
588 Ok(())
589 }
590
591 pub fn push_result<T: IntoScriptModuleReturnValue>(
593 &mut self,
594 value: T,
595 ) -> Result<(), IntoScriptModuleReturnValueError<T::Err>> {
596 value.push_into(self)
597 }
598
599 pub fn push_result_int(&mut self, value: i32) {
601 unsafe {
602 ((*self.internal).push_result_int)(value);
603 }
604 }
605
606 pub fn push_result_float(&mut self, value: f64) {
608 unsafe {
609 ((*self.internal).push_result_double)(value);
610 }
611 }
612
613 pub fn push_result_str(&mut self, value: &str) -> ScriptModuleCallHandleResult<()> {
615 let c_value = std::ffi::CString::new(value)
616 .map_err(ScriptModuleCallHandleError::ValueContainsNullByte)?;
617 unsafe {
618 ((*self.internal).push_result_string)(c_value.as_ptr());
619 }
620 Ok(())
621 }
622
623 pub fn push_result_data<T>(&mut self, value: *const T) {
625 unsafe {
626 ((*self.internal).push_result_data)(value as *const std::ffi::c_void);
627 }
628 }
629
630 pub fn push_result_function(&mut self, callback: ScriptModuleFunctionCallback) {
636 unsafe {
637 ((*self.internal).push_result_function)(callback.func, callback.userdata);
638 }
639 }
640
641 pub fn push_result_meta_table<T: Into<ErasedScriptModuleUserData>>(&mut self, meta_table: T) {
643 unsafe {
644 let meta_table: ErasedScriptModuleUserData = meta_table.into();
645 ((*self.internal).push_result_meta_table)(
646 meta_table.meta_method_functions,
647 meta_table.userdata,
648 );
649 }
650 }
651
652 pub fn push_result_table_int<'a, T>(&mut self, table: T) -> ScriptModuleCallHandleResult<()>
654 where
655 T: std::iter::IntoIterator<Item = (&'a str, i32)>,
656 {
657 let mut keys = Vec::new();
658 let mut values = Vec::new();
659 for (key, value) in table {
660 let c_key = std::ffi::CString::new(key)
661 .map_err(ScriptModuleCallHandleError::KeyContainsNullByte)?;
662 keys.push(c_key);
663 values.push(value);
664 }
665 let key_ptrs: Vec<*const std::os::raw::c_char> = keys.iter().map(|k| k.as_ptr()).collect();
666 unsafe {
667 ((*self.internal).push_result_table_int)(
668 key_ptrs.as_ptr(),
669 values.as_ptr(),
670 key_ptrs.len() as i32,
671 );
672 }
673 Ok(())
674 }
675
676 pub fn push_result_table_float<'a, T>(&mut self, table: T) -> ScriptModuleCallHandleResult<()>
678 where
679 T: std::iter::IntoIterator<Item = (&'a str, f64)>,
680 {
681 let mut keys = Vec::new();
682 let mut values = Vec::new();
683 for (key, value) in table {
684 let c_key = std::ffi::CString::new(key)
685 .map_err(ScriptModuleCallHandleError::KeyContainsNullByte)?;
686 keys.push(c_key);
687 values.push(value);
688 }
689 let key_ptrs: Vec<*const std::os::raw::c_char> = keys.iter().map(|k| k.as_ptr()).collect();
690 unsafe {
691 ((*self.internal).push_result_table_double)(
692 key_ptrs.as_ptr(),
693 values.as_ptr(),
694 key_ptrs.len() as i32,
695 );
696 }
697 Ok(())
698 }
699
700 pub fn push_result_table_str<'a, T>(&mut self, table: T) -> ScriptModuleCallHandleResult<()>
702 where
703 T: std::iter::IntoIterator<Item = (&'a str, &'a str)>,
704 {
705 let mut keys = Vec::new();
706 let mut values = Vec::new();
707 for (key, value) in table {
708 let c_key = std::ffi::CString::new(key)
709 .map_err(ScriptModuleCallHandleError::KeyContainsNullByte)?;
710 let c_value = std::ffi::CString::new(value)
711 .map_err(ScriptModuleCallHandleError::ValueContainsNullByte)?;
712 keys.push(c_key);
713 values.push(c_value);
714 }
715 if keys.len() > i32::MAX as usize {
716 return Err(ScriptModuleCallHandleError::TooManyElements);
717 }
718 let key_ptrs: Vec<*const std::os::raw::c_char> = keys.iter().map(|k| k.as_ptr()).collect();
719 let value_ptrs: Vec<*const std::os::raw::c_char> =
720 values.iter().map(|v| v.as_ptr()).collect();
721 unsafe {
722 ((*self.internal).push_result_table_string)(
723 key_ptrs.as_ptr(),
724 value_ptrs.as_ptr(),
725 key_ptrs.len() as i32,
726 );
727 }
728 Ok(())
729 }
730
731 pub fn push_result_table_boolean<'a, T>(&mut self, table: T) -> ScriptModuleCallHandleResult<()>
733 where
734 T: std::iter::IntoIterator<Item = (&'a str, bool)>,
735 {
736 let mut keys = Vec::new();
737 let mut values = Vec::new();
738 for (key, value) in table {
739 let c_key = std::ffi::CString::new(key)
740 .map_err(ScriptModuleCallHandleError::KeyContainsNullByte)?;
741 keys.push(c_key);
742 values.push(value);
743 }
744 let key_ptrs: Vec<*const std::os::raw::c_char> = keys.iter().map(|k| k.as_ptr()).collect();
745 unsafe {
746 ((*self.internal).push_result_table_boolean)(
747 key_ptrs.as_ptr(),
748 values.as_ptr(),
749 key_ptrs.len() as i32,
750 );
751 }
752 Ok(())
753 }
754
755 pub fn push_result_array_int(&mut self, values: &[i32]) -> ScriptModuleCallHandleResult<()> {
757 if values.len() > i32::MAX as usize {
758 return Err(ScriptModuleCallHandleError::TooManyElements);
759 }
760 unsafe {
761 ((*self.internal).push_result_array_int)(values.as_ptr(), values.len() as i32);
762 }
763 Ok(())
764 }
765
766 pub fn push_result_array_float(&mut self, values: &[f64]) -> ScriptModuleCallHandleResult<()> {
768 if values.len() > i32::MAX as usize {
769 return Err(ScriptModuleCallHandleError::TooManyElements);
770 }
771 unsafe {
772 ((*self.internal).push_result_array_double)(values.as_ptr(), values.len() as i32);
773 }
774 Ok(())
775 }
776
777 pub fn push_result_array_str(&mut self, values: &[&str]) -> ScriptModuleCallHandleResult<()> {
779 let c_values: Vec<std::ffi::CString> = values
780 .iter()
781 .map(|s| std::ffi::CString::new(*s))
782 .collect::<Result<_, _>>()
783 .map_err(ScriptModuleCallHandleError::ValueContainsNullByte)?;
784 if c_values.len() > i32::MAX as usize {
785 return Err(ScriptModuleCallHandleError::TooManyElements);
786 }
787 let c_value_ptrs: Vec<*const std::os::raw::c_char> =
788 c_values.iter().map(|s| s.as_ptr()).collect();
789 unsafe {
790 ((*self.internal).push_result_array_string)(
791 c_value_ptrs.as_ptr(),
792 c_value_ptrs.len() as i32,
793 );
794 }
795 Ok(())
796 }
797
798 pub fn push_result_array_boolean(
800 &mut self,
801 values: &[bool],
802 ) -> ScriptModuleCallHandleResult<()> {
803 if values.len() > i32::MAX as usize {
804 return Err(ScriptModuleCallHandleError::TooManyElements);
805 }
806 unsafe {
807 ((*self.internal).push_result_array_boolean)(values.as_ptr(), values.len() as i32);
808 }
809 Ok(())
810 }
811
812 pub fn push_result_boolean(&mut self, value: bool) {
814 unsafe {
815 ((*self.internal).push_result_boolean)(value);
816 }
817 }
818
819 pub fn read_section(&self) -> &crate::generic::ReadSection {
821 &self.read_section
822 }
823}
824
825pub trait FromScriptModuleParam<'a>: Sized {
832 type Error: std::error::Error;
833
834 fn from_param(
835 param: &'a crate::module::ScriptModuleCallHandle,
836 index: usize,
837 ) -> GetParamResult<Self, Self::Error>;
838}
839
840pub use aviutl2_macros::FromScriptModuleParam;
841
842impl<'a> FromScriptModuleParam<'a> for &'a crate::generic::ReadSection {
843 type Error = std::convert::Infallible;
844
845 fn from_param(
846 param: &'a crate::module::ScriptModuleCallHandle,
847 _index: usize,
848 ) -> GetParamResult<Self> {
849 Ok(param.read_section())
850 }
851}
852
853impl<'a> FromScriptModuleParam<'a> for i32 {
854 type Error = std::convert::Infallible;
855
856 fn from_param(param: &'a ScriptModuleCallHandle, index: usize) -> GetParamResult<Self> {
857 param.get_param_int(index)
858 }
859}
860#[duplicate::duplicate_item(
861 Integer Failable;
862 [i8] [true];
863 [i16] [true];
864 [i64] [false];
865 [i128] [false];
866 [isize] [false];
867 [u8] [true];
868 [u16] [true];
869 [u32] [true];
870 [u64] [false];
871 [u128] [false];
872 [usize] [false];
873)]
874impl<'a> FromScriptModuleParam<'a> for Integer {
875 type Error = std::num::TryFromIntError;
876
877 fn from_param(
878 param: &'a ScriptModuleCallHandle,
879 index: usize,
880 ) -> GetParamResult<Self, Self::Error> {
881 let value = param
882 .get_param_int(index)
883 .map_err(GetParamError::into_conversion_error)?;
884 comptime_if::comptime_if!(
885 if failable where (failable = Failable) {
886 value.try_into().map_err(GetParamError::ConversionError)
887 } else {
888 Ok(value as Integer)
889 }
890 )
891 }
892}
893impl<'a> FromScriptModuleParam<'a> for f64 {
894 type Error = std::convert::Infallible;
895
896 fn from_param(param: &'a ScriptModuleCallHandle, index: usize) -> GetParamResult<Self> {
897 param.get_param_float(index)
898 }
899}
900impl<'a> FromScriptModuleParam<'a> for f32 {
901 type Error = std::convert::Infallible;
902
903 fn from_param(param: &'a ScriptModuleCallHandle, index: usize) -> GetParamResult<Self> {
904 param.get_param_float(index).map(|value| value as f32)
905 }
906}
907impl<'a> FromScriptModuleParam<'a> for bool {
908 type Error = std::convert::Infallible;
909
910 fn from_param(param: &'a ScriptModuleCallHandle, index: usize) -> GetParamResult<Self> {
911 param.get_param_boolean(index)
912 }
913}
914impl<'a> FromScriptModuleParam<'a> for String {
915 type Error = std::convert::Infallible;
916
917 fn from_param(param: &'a ScriptModuleCallHandle, index: usize) -> GetParamResult<Self> {
918 param.get_param_str(index)
919 }
920}
921impl<'a, T> FromScriptModuleParam<'a> for *mut T {
922 type Error = std::convert::Infallible;
923
924 fn from_param(param: &'a ScriptModuleCallHandle, index: usize) -> GetParamResult<Self> {
925 param.get_param_data(index)
926 }
927}
928impl<'a, T> FromScriptModuleParam<'a> for *const T {
929 type Error = std::convert::Infallible;
930
931 fn from_param(param: &'a ScriptModuleCallHandle, index: usize) -> GetParamResult<Self> {
932 Ok(param.get_param_data(index)? as _)
933 }
934}
935impl<'a, T> FromScriptModuleParam<'a> for NonNull<T> {
936 type Error = ParamConversionError;
937
938 fn from_param(
939 param: &'a ScriptModuleCallHandle,
940 index: usize,
941 ) -> GetParamResult<Self, Self::Error> {
942 let ptr = param
943 .get_param_data(index)
944 .map_err(GetParamError::into_conversion_error)?;
945 NonNull::new(ptr).ok_or_else(|| {
946 GetParamError::ConversionError(ParamConversionError::new("value is null"))
947 })
948 }
949}
950impl<'a, T: Send + Sync + 'static + AsScriptModuleUserData> FromScriptModuleParam<'a>
951 for ScriptModuleUserData<T>
952{
953 type Error = ParamConversionError;
954
955 fn from_param(
956 param: &'a ScriptModuleCallHandle,
957 index: usize,
958 ) -> GetParamResult<Self, Self::Error> {
959 param.get_param_userdata(index)
960 }
961}
962#[duplicate::duplicate_item(
963 Integer NonZero Failable;
964 [i8] [NonZeroI8] [true];
965 [i16] [NonZeroI16] [true];
966 [i64] [NonZeroI64] [false];
967 [i128] [NonZeroI128] [false];
968 [isize] [NonZeroIsize] [false];
969 [u8] [NonZeroU8] [true];
970 [u16] [NonZeroU16] [true];
971 [u32] [NonZeroU32] [true];
972 [u64] [NonZeroU64] [false];
973 [u128] [NonZeroU128] [false];
974 [usize] [NonZeroUsize] [false];
975)]
976impl<'a> FromScriptModuleParam<'a> for NonZero {
977 type Error = ParamConversionError;
978
979 fn from_param(
980 param: &'a ScriptModuleCallHandle,
981 index: usize,
982 ) -> GetParamResult<Self, Self::Error> {
983 let value = param
984 .get_param_int(index)
985 .map_err(GetParamError::into_conversion_error)?;
986 let value: Integer = comptime_if::comptime_if!(
987 if failable where (failable = Failable) {
988 value
989 .try_into()
990 .map_err(|error: std::num::TryFromIntError| GetParamError::ConversionError(ParamConversionError::new(error.to_string())))?
991 } else {
992 value as Integer
993 }
994 );
995 NonZero::new(value).ok_or_else(|| {
996 GetParamError::ConversionError(ParamConversionError::new("value is zero"))
997 })
998 }
999}
1000impl<'a> FromScriptModuleParam<'a> for NonZeroI32 {
1001 type Error = ParamConversionError;
1002
1003 fn from_param(
1004 param: &'a ScriptModuleCallHandle,
1005 index: usize,
1006 ) -> GetParamResult<Self, Self::Error> {
1007 let value = param
1008 .get_param_int(index)
1009 .map_err(GetParamError::into_conversion_error)?;
1010 NonZeroI32::new(value).ok_or_else(|| {
1011 GetParamError::ConversionError(ParamConversionError::new("value is zero"))
1012 })
1013 }
1014}
1015
1016impl<'a, T> FromScriptModuleParam<'a> for Option<T>
1017where
1018 T: FromScriptModuleParam<'a>,
1019{
1020 type Error = T::Error;
1021
1022 fn from_param(
1023 param: &'a ScriptModuleCallHandle,
1024 index: usize,
1025 ) -> GetParamResult<Self, Self::Error> {
1026 match param.get_param_type(index) {
1027 None | Some(ParamType::Nil) => Ok(None),
1028 Some(_) => T::from_param(param, index).map(Some),
1029 }
1030 }
1031}
1032impl<'a> FromScriptModuleParam<'a> for () {
1033 type Error = std::convert::Infallible;
1034
1035 fn from_param(param: &'a ScriptModuleCallHandle, index: usize) -> GetParamResult<Self> {
1036 param
1037 .get_param_type(index)
1038 .map(|_| ())
1039 .ok_or(GetParamError::IndexOutOfBounds {
1040 index,
1041 len: param.len(),
1042 })
1043 }
1044}
1045
1046pub struct ScriptModuleParamArray<'a> {
1048 index: usize,
1049 ptr: *mut aviutl2_sys::module2::SCRIPT_MODULE_PARAM,
1050 marker: std::marker::PhantomData<&'a ()>,
1051}
1052
1053impl std::fmt::Debug for ScriptModuleParamArray<'_> {
1054 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1055 f.debug_struct("ScriptModuleParamArray")
1056 .field("index", &self.index)
1057 .field("len", &self.len())
1058 .finish()
1059 }
1060}
1061
1062impl<'a> ScriptModuleParamArray<'a> {
1063 pub fn len(&self) -> usize {
1065 unsafe { ((*self.ptr).get_param_array_num)(self.index as i32) as usize }
1066 }
1067
1068 pub fn is_empty(&self) -> bool {
1070 self.len() == 0
1071 }
1072
1073 pub fn get_int(&self, array_index: usize) -> i32 {
1075 unsafe { ((*self.ptr).get_param_array_int)(self.index as i32, array_index as i32) }
1076 }
1077
1078 pub fn get_float(&self, array_index: usize) -> f64 {
1080 unsafe { ((*self.ptr).get_param_array_double)(self.index as i32, array_index as i32) }
1081 }
1082
1083 pub fn get_str(&self, array_index: usize) -> Option<String> {
1085 unsafe {
1086 let c_str = ((*self.ptr).get_param_array_string)(self.index as i32, array_index as i32);
1087 if c_str.is_null() {
1088 None
1089 } else {
1090 Some(
1091 std::ffi::CStr::from_ptr(c_str)
1092 .to_string_lossy()
1093 .into_owned(),
1094 )
1095 }
1096 }
1097 }
1098}
1099
1100impl<'a> FromScriptModuleParam<'a> for ScriptModuleParamArray<'a> {
1101 type Error = std::convert::Infallible;
1102
1103 fn from_param(param: &'a ScriptModuleCallHandle, index: usize) -> GetParamResult<Self> {
1104 param.assert_param_type(index, ParamType::Table)?;
1105 Ok(ScriptModuleParamArray {
1106 index,
1107 ptr: param.internal,
1108 marker: std::marker::PhantomData,
1109 })
1110 }
1111}
1112
1113#[derive(Debug)]
1115pub struct ScriptModuleParamTable<'a> {
1116 index: usize,
1117 ptr: *mut aviutl2_sys::module2::SCRIPT_MODULE_PARAM,
1118 marker: std::marker::PhantomData<&'a ()>,
1119}
1120
1121impl<'a> ScriptModuleParamTable<'a> {
1122 pub fn get_int(&self, key: &str) -> i32 {
1124 let c_key = std::ffi::CString::new(key).unwrap();
1125 unsafe { ((*self.ptr).get_param_table_int)(self.index as i32, c_key.as_ptr()) }
1126 }
1127
1128 pub fn get_float(&self, key: &str) -> f64 {
1130 let c_key = std::ffi::CString::new(key).unwrap();
1131 unsafe { ((*self.ptr).get_param_table_double)(self.index as i32, c_key.as_ptr()) }
1132 }
1133
1134 pub fn get_str(&self, key: &str) -> Option<String> {
1136 let c_key = std::ffi::CString::new(key).unwrap();
1137 unsafe {
1138 let c_str = ((*self.ptr).get_param_table_string)(self.index as i32, c_key.as_ptr());
1139 if c_str.is_null() {
1140 None
1141 } else {
1142 Some(
1143 std::ffi::CStr::from_ptr(c_str)
1144 .to_string_lossy()
1145 .into_owned(),
1146 )
1147 }
1148 }
1149 }
1150
1151 pub fn get_boolean(&self, key: &str) -> bool {
1153 let c_key = std::ffi::CString::new(key).unwrap();
1154 unsafe { ((*self.ptr).get_param_table_boolean)(self.index as i32, c_key.as_ptr()) }
1155 }
1156}
1157
1158impl<'a> FromScriptModuleParam<'a> for ScriptModuleParamTable<'a> {
1159 type Error = std::convert::Infallible;
1160
1161 fn from_param(param: &'a ScriptModuleCallHandle, index: usize) -> GetParamResult<Self> {
1162 param.assert_param_type(index, ParamType::Table)?;
1163 Ok(ScriptModuleParamTable {
1164 index,
1165 ptr: param.internal,
1166 marker: std::marker::PhantomData,
1167 })
1168 }
1169}
1170
1171impl<'a> FromScriptModuleParam<'a> for Vec<String> {
1172 type Error = ParamConversionError;
1173
1174 fn from_param(
1175 param: &'a ScriptModuleCallHandle,
1176 index: usize,
1177 ) -> GetParamResult<Self, Self::Error> {
1178 let array = ScriptModuleParamArray::from_param(param, index)
1179 .map_err(GetParamError::into_conversion_error)?;
1180 let mut result = Vec::new();
1181 for i in 0..array.len() {
1182 let value = array.get_str(i).ok_or_else(|| {
1183 GetParamError::ConversionError(ParamConversionError::new(format!(
1184 "array element #{i} is not a string"
1185 )))
1186 })?;
1187 result.push(value);
1188 }
1189 Ok(result)
1190 }
1191}
1192impl<'a> FromScriptModuleParam<'a> for Vec<i32> {
1193 type Error = std::convert::Infallible;
1194
1195 fn from_param(param: &'a ScriptModuleCallHandle, index: usize) -> GetParamResult<Self> {
1196 let array = ScriptModuleParamArray::from_param(param, index)?;
1197 let mut result = Vec::new();
1198 for i in 0..array.len() {
1199 result.push(array.get_int(i));
1200 }
1201 Ok(result)
1202 }
1203}
1204#[duplicate::duplicate_item(
1205 Integer Failable;
1206 [i8] [true];
1207 [i16] [true];
1208 [i64] [false];
1209 [i128] [false];
1210 [isize] [false];
1211 [u8] [true];
1212 [u16] [true];
1213 [u32] [true];
1214 [u64] [true];
1215 [u128] [true];
1216 [usize] [true];
1217)]
1218impl<'a> FromScriptModuleParam<'a> for Vec<Integer> {
1219 type Error = std::num::TryFromIntError;
1220
1221 fn from_param(
1222 param: &'a ScriptModuleCallHandle,
1223 index: usize,
1224 ) -> GetParamResult<Self, Self::Error> {
1225 let array = ScriptModuleParamArray::from_param(param, index)
1226 .map_err(GetParamError::into_conversion_error)?;
1227 let mut result = Vec::new();
1228 for i in 0..array.len() {
1229 let value = array.get_int(i);
1230 comptime_if::comptime_if!(
1231 if failable where (failable = Failable) {
1232 result.push(value.try_into().map_err(GetParamError::ConversionError)?);
1233 } else {
1234 result.push(value as Integer);
1235 }
1236 );
1237 }
1238 Ok(result)
1239 }
1240}
1241impl<'a> FromScriptModuleParam<'a> for Vec<f64> {
1242 type Error = std::convert::Infallible;
1243
1244 fn from_param(param: &'a ScriptModuleCallHandle, index: usize) -> GetParamResult<Self> {
1245 let array = ScriptModuleParamArray::from_param(param, index)?;
1246 let mut result = Vec::new();
1247 for i in 0..array.len() {
1248 result.push(array.get_float(i));
1249 }
1250 Ok(result)
1251 }
1252}
1253impl<'a> FromScriptModuleParam<'a> for Vec<f32> {
1254 type Error = std::convert::Infallible;
1255
1256 fn from_param(param: &'a ScriptModuleCallHandle, index: usize) -> GetParamResult<Self> {
1257 let array = ScriptModuleParamArray::from_param(param, index)?;
1258 let mut result = Vec::new();
1259 for i in 0..array.len() {
1260 result.push(array.get_float(i) as f32);
1261 }
1262 Ok(result)
1263 }
1264}
1265
1266pub trait FromScriptModuleParamTable<'a>: Sized {
1268 type Error: std::error::Error;
1269
1270 fn from_param_table(
1271 param: &'a crate::module::ScriptModuleParamTable,
1272 key: &str,
1273 ) -> GetParamResult<Self, Self::Error>;
1274}
1275
1276impl<'a> FromScriptModuleParamTable<'a> for i32 {
1277 type Error = std::convert::Infallible;
1278
1279 fn from_param_table(param: &'a ScriptModuleParamTable, key: &str) -> GetParamResult<Self> {
1280 Ok(param.get_int(key))
1281 }
1282}
1283#[duplicate::duplicate_item(
1284 Integer Failable;
1285 [i8] [true];
1286 [i16] [true];
1287 [i64] [false];
1288 [i128] [false];
1289 [isize] [false];
1290 [u8] [true];
1291 [u16] [true];
1292 [u32] [true];
1293 [u64] [false];
1294 [u128] [false];
1295 [usize] [false];
1296)]
1297impl<'a> FromScriptModuleParamTable<'a> for Integer {
1298 type Error = std::num::TryFromIntError;
1299
1300 fn from_param_table(
1301 param: &'a ScriptModuleParamTable,
1302 key: &str,
1303 ) -> GetParamResult<Self, Self::Error> {
1304 let value = param.get_int(key);
1305 comptime_if::comptime_if!(
1306 if failable where (failable = Failable) {
1307 value.try_into().map_err(GetParamError::ConversionError)
1308 } else {
1309 Ok(value as Integer)
1310 }
1311 )
1312 }
1313}
1314impl<'a> FromScriptModuleParamTable<'a> for f64 {
1315 type Error = std::convert::Infallible;
1316
1317 fn from_param_table(param: &'a ScriptModuleParamTable, key: &str) -> GetParamResult<Self> {
1318 Ok(param.get_float(key))
1319 }
1320}
1321impl<'a> FromScriptModuleParamTable<'a> for f32 {
1322 type Error = std::convert::Infallible;
1323
1324 fn from_param_table(param: &'a ScriptModuleParamTable, key: &str) -> GetParamResult<Self> {
1325 Ok(param.get_float(key) as f32)
1326 }
1327}
1328impl<'a> FromScriptModuleParamTable<'a> for String {
1329 type Error = ParamConversionError;
1330
1331 fn from_param_table(
1332 param: &'a ScriptModuleParamTable,
1333 key: &str,
1334 ) -> GetParamResult<Self, Self::Error> {
1335 param.get_str(key).ok_or_else(|| {
1336 GetParamError::ConversionError(ParamConversionError::new(format!(
1337 "key `{key}` is not a string"
1338 )))
1339 })
1340 }
1341}
1342impl<'a> FromScriptModuleParamTable<'a> for bool {
1343 type Error = std::convert::Infallible;
1344
1345 fn from_param_table(param: &'a ScriptModuleParamTable, key: &str) -> GetParamResult<Self> {
1346 Ok(param.get_boolean(key))
1347 }
1348}
1349impl<'a, T: FromScriptModuleParamTable<'a>> FromScriptModuleParamTable<'a> for Option<T> {
1350 type Error = T::Error;
1351
1352 fn from_param_table(
1353 param: &'a ScriptModuleParamTable,
1354 key: &str,
1355 ) -> GetParamResult<Self, Self::Error> {
1356 match T::from_param_table(param, key) {
1357 Ok(value) => Ok(Some(value)),
1358 Err(GetParamError::ConversionError(_)) => Ok(None),
1359 Err(error) => Err(error),
1360 }
1361 }
1362}
1363
1364#[derive(Debug)]
1366pub enum ScriptModuleReturnValue {
1367 Int(i32),
1368 Float(f64),
1369 String(String),
1370 Boolean(bool),
1371 Data(*const std::ffi::c_void),
1372 StringArray(Vec<String>),
1373 IntArray(Vec<i32>),
1374 FloatArray(Vec<f64>),
1375 IntTable(std::collections::HashMap<String, i32>),
1376 FloatTable(std::collections::HashMap<String, f64>),
1377 StringTable(std::collections::HashMap<String, String>),
1378 Function(ScriptModuleFunctionCallback),
1379 MetaTable(ErasedScriptModuleUserData),
1380}
1381
1382#[derive(thiserror::Error, Debug)]
1384pub enum IntoScriptModuleReturnValueError<T> {
1385 #[error("failed to convert value: {0}")]
1386 ConversionFailed(#[source] T),
1387 #[error("failed to push return value: {0}")]
1388 PushFailed(#[from] ScriptModuleCallHandleError),
1389}
1390
1391pub trait IntoScriptModuleReturnValue
1398where
1399 Self: Sized,
1400{
1401 type Err: Send + Sync + 'static + Into<Box<dyn std::error::Error + Send + Sync + 'static>>;
1402
1403 fn into_return_values(self) -> Result<Vec<crate::module::ScriptModuleReturnValue>, Self::Err>;
1404 fn push_into(
1405 self,
1406 param: &mut crate::module::ScriptModuleCallHandle,
1407 ) -> Result<(), crate::module::IntoScriptModuleReturnValueError<Self::Err>> {
1408 for value in self
1409 .into_return_values()
1410 .map_err(IntoScriptModuleReturnValueError::ConversionFailed)?
1411 {
1412 match value {
1413 ScriptModuleReturnValue::Int(v) => {
1414 param.push_result_int(v);
1415 }
1416 ScriptModuleReturnValue::Float(v) => {
1417 param.push_result_float(v);
1418 }
1419 ScriptModuleReturnValue::String(v) => {
1420 param.push_result_str(&v)?;
1421 }
1422 ScriptModuleReturnValue::Boolean(v) => {
1423 param.push_result_boolean(v);
1424 }
1425 ScriptModuleReturnValue::Data(v) => {
1426 param.push_result_data(v);
1427 }
1428 ScriptModuleReturnValue::Function(v) => {
1429 param.push_result_function(v);
1430 }
1431 ScriptModuleReturnValue::MetaTable(v) => {
1432 param.push_result_meta_table(v);
1433 }
1434 ScriptModuleReturnValue::StringArray(v) => {
1435 let strs: Vec<&str> = v.iter().map(|s| s.as_str()).collect();
1436 param.push_result_array_str(&strs)?
1437 }
1438 ScriptModuleReturnValue::IntArray(v) => param.push_result_array_int(&v)?,
1439 ScriptModuleReturnValue::FloatArray(v) => param.push_result_array_float(&v)?,
1440 ScriptModuleReturnValue::IntTable(v) => {
1441 let table = v.iter().map(|(k, v)| (k.as_str(), *v));
1442 param.push_result_table_int(table)?;
1443 }
1444 ScriptModuleReturnValue::FloatTable(v) => {
1445 let table = v.iter().map(|(k, v)| (k.as_str(), *v));
1446 param.push_result_table_float(table)?;
1447 }
1448 ScriptModuleReturnValue::StringTable(v) => {
1449 let table = v.iter().map(|(k, v)| (k.as_str(), v.as_str()));
1450 param.push_result_table_str(table)?;
1451 }
1452 };
1453 }
1454 Ok(())
1455 }
1456}
1457pub use aviutl2_macros::IntoScriptModuleReturnValue;
1458
1459impl<T> IntoScriptModuleReturnValue for *const T {
1460 type Err = std::convert::Infallible;
1461
1462 fn into_return_values(self) -> Result<Vec<ScriptModuleReturnValue>, Self::Err> {
1463 Ok(vec![ScriptModuleReturnValue::Data(
1464 self as *const std::ffi::c_void,
1465 )])
1466 }
1467}
1468
1469impl IntoScriptModuleReturnValue for ScriptModuleFunctionCallback {
1470 type Err = std::convert::Infallible;
1471
1472 fn into_return_values(self) -> Result<Vec<ScriptModuleReturnValue>, Self::Err> {
1473 Ok(vec![ScriptModuleReturnValue::Function(self)])
1474 }
1475}
1476
1477impl<T: Into<ErasedScriptModuleUserData>> IntoScriptModuleReturnValue for T {
1478 type Err = std::convert::Infallible;
1479
1480 fn into_return_values(self) -> Result<Vec<ScriptModuleReturnValue>, Self::Err> {
1481 Ok(vec![ScriptModuleReturnValue::MetaTable(self.into())])
1482 }
1483}
1484
1485impl IntoScriptModuleReturnValue for i32 {
1486 type Err = std::convert::Infallible;
1487
1488 fn into_return_values(self) -> Result<Vec<ScriptModuleReturnValue>, Self::Err> {
1489 Ok(vec![ScriptModuleReturnValue::Int(self)])
1490 }
1491}
1492#[duplicate::duplicate_item(
1493 Integer;
1494 [i8];
1495 [i16];
1496 [u8];
1497 [u16];
1498)]
1499impl IntoScriptModuleReturnValue for Integer {
1500 type Err = std::convert::Infallible;
1501
1502 fn into_return_values(self) -> Result<Vec<ScriptModuleReturnValue>, Self::Err> {
1503 Ok(vec![ScriptModuleReturnValue::Int(self as i32)])
1504 }
1505}
1506#[duplicate::duplicate_item(
1507 Integer;
1508 [i64];
1509 [i128];
1510 [isize];
1511 [u32];
1512 [u64];
1513 [u128];
1514 [usize];
1515)]
1516impl IntoScriptModuleReturnValue for Integer {
1517 type Err = std::num::TryFromIntError;
1518
1519 fn into_return_values(self) -> Result<Vec<ScriptModuleReturnValue>, Self::Err> {
1520 Ok(vec![ScriptModuleReturnValue::Int(self.try_into()?)])
1521 }
1522}
1523impl IntoScriptModuleReturnValue for f64 {
1524 type Err = std::convert::Infallible;
1525 fn into_return_values(self) -> Result<Vec<ScriptModuleReturnValue>, Self::Err> {
1526 Ok(vec![ScriptModuleReturnValue::Float(self)])
1527 }
1528}
1529impl IntoScriptModuleReturnValue for f32 {
1530 type Err = std::convert::Infallible;
1531 fn into_return_values(self) -> Result<Vec<ScriptModuleReturnValue>, Self::Err> {
1532 Ok(vec![ScriptModuleReturnValue::Float(self as f64)])
1533 }
1534}
1535impl IntoScriptModuleReturnValue for bool {
1536 type Err = std::convert::Infallible;
1537 fn into_return_values(self) -> Result<Vec<ScriptModuleReturnValue>, Self::Err> {
1538 Ok(vec![ScriptModuleReturnValue::Boolean(self)])
1539 }
1540}
1541impl IntoScriptModuleReturnValue for &str {
1542 type Err = std::convert::Infallible;
1543 fn into_return_values(self) -> Result<Vec<ScriptModuleReturnValue>, Self::Err> {
1544 Ok(vec![ScriptModuleReturnValue::String(self.to_string())])
1545 }
1546}
1547impl IntoScriptModuleReturnValue for String {
1548 type Err = std::convert::Infallible;
1549 fn into_return_values(self) -> Result<Vec<ScriptModuleReturnValue>, Self::Err> {
1550 Ok(vec![ScriptModuleReturnValue::String(self)])
1551 }
1552}
1553
1554impl IntoScriptModuleReturnValue for ScriptModuleReturnValue {
1555 type Err = std::convert::Infallible;
1556 fn into_return_values(self) -> Result<Vec<ScriptModuleReturnValue>, Self::Err> {
1557 Ok(vec![self])
1558 }
1559}
1560
1561impl IntoScriptModuleReturnValue for Vec<ScriptModuleReturnValue> {
1562 type Err = std::convert::Infallible;
1563
1564 fn into_return_values(self) -> Result<Vec<ScriptModuleReturnValue>, Self::Err> {
1565 Ok(self)
1566 }
1567}
1568
1569impl<T: IntoScriptModuleReturnValue> IntoScriptModuleReturnValue for Option<T> {
1570 type Err = T::Err;
1571 fn into_return_values(self) -> Result<Vec<ScriptModuleReturnValue>, Self::Err> {
1572 if let Some(value) = self {
1573 value.into_return_values()
1574 } else {
1575 Ok(Vec::new())
1576 }
1577 }
1578}
1579impl<T, const N: usize> IntoScriptModuleReturnValue for [T; N]
1580where
1581 Vec<T>: IntoScriptModuleReturnValue,
1582{
1583 type Err = <Vec<T> as IntoScriptModuleReturnValue>::Err;
1584
1585 fn into_return_values(self) -> Result<Vec<ScriptModuleReturnValue>, Self::Err> {
1586 let vec: Vec<T> = self.into();
1587 vec.into_return_values()
1588 }
1589}
1590impl<T: IntoScriptModuleReturnValue, E> IntoScriptModuleReturnValue for Result<T, E>
1591where
1592 E: Into<Box<dyn std::error::Error + Send + Sync + 'static>>,
1593{
1594 type Err = T::Err;
1595
1596 fn into_return_values(
1597 self,
1598 ) -> Result<
1599 Vec<ScriptModuleReturnValue>,
1600 <std::result::Result<T, E> as IntoScriptModuleReturnValue>::Err,
1601 > {
1602 match self {
1603 Ok(value) => value.into_return_values(),
1604 Err(_) => Ok(Vec::new()),
1605 }
1606 }
1607 fn push_into(
1608 self,
1609 param: &mut ScriptModuleCallHandle,
1610 ) -> Result<
1611 (),
1612 IntoScriptModuleReturnValueError<
1613 <std::result::Result<T, E> as IntoScriptModuleReturnValue>::Err,
1614 >,
1615 > {
1616 match self {
1617 Ok(value) => value.push_into(param)?,
1618 Err(err) => {
1619 let e: Box<dyn std::error::Error + 'static> = err.into();
1620 let e = e.to_string();
1621 param.set_error(&e)?
1622 }
1623 }
1624 Ok(())
1625 }
1626}
1627
1628impl IntoScriptModuleReturnValue for () {
1629 type Err = std::convert::Infallible;
1630 fn into_return_values(self) -> Result<Vec<ScriptModuleReturnValue>, Self::Err> {
1631 Ok(Vec::new())
1632 }
1633}
1634
1635macro_rules! impl_into_script_module_return_value_for_tuple {
1636 ($($name:ident),+) => {
1637 impl<$($name),+> IntoScriptModuleReturnValue for ($($name,)+)
1638 where
1639 $($name: IntoScriptModuleReturnValue),+
1640 {
1641 type Err = anyhow::Error;
1642
1643 fn into_return_values(self) -> Result<Vec<ScriptModuleReturnValue>, Self::Err> {
1644 let mut vec = Vec::new();
1645 #[allow(non_snake_case)]
1646 let ($($name,)+) = self;
1647 $(
1648 vec.extend(
1649 $name.into_return_values()
1650 .map_err(|e| anyhow::Error::from_boxed(e.into()))?
1651 );
1652 )+
1653 Ok(vec)
1654 }
1655 }
1656 };
1657}
1658impl_into_script_module_return_value_for_tuple!(T1);
1659impl_into_script_module_return_value_for_tuple!(T1, T2);
1660impl_into_script_module_return_value_for_tuple!(T1, T2, T3);
1661impl_into_script_module_return_value_for_tuple!(T1, T2, T3, T4);
1662impl_into_script_module_return_value_for_tuple!(T1, T2, T3, T4, T5);
1663impl_into_script_module_return_value_for_tuple!(T1, T2, T3, T4, T5, T6);
1664impl_into_script_module_return_value_for_tuple!(T1, T2, T3, T4, T5, T6, T7);
1665impl_into_script_module_return_value_for_tuple!(T1, T2, T3, T4, T5, T6, T7, T8);
1666impl_into_script_module_return_value_for_tuple!(T1, T2, T3, T4, T5, T6, T7, T8, T9);
1667impl_into_script_module_return_value_for_tuple!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10);
1668
1669impl IntoScriptModuleReturnValue for Vec<String> {
1670 type Err = std::convert::Infallible;
1671 fn into_return_values(self) -> Result<Vec<ScriptModuleReturnValue>, Self::Err> {
1672 Ok(vec![ScriptModuleReturnValue::StringArray(self)])
1673 }
1674}
1675impl IntoScriptModuleReturnValue for Vec<&str> {
1676 type Err = std::convert::Infallible;
1677 fn into_return_values(self) -> Result<Vec<ScriptModuleReturnValue>, Self::Err> {
1678 Ok(vec![ScriptModuleReturnValue::StringArray(
1679 self.iter().map(|s| s.to_string()).collect(),
1680 )])
1681 }
1682}
1683impl IntoScriptModuleReturnValue for Vec<i32> {
1684 type Err = std::convert::Infallible;
1685 fn into_return_values(self) -> Result<Vec<ScriptModuleReturnValue>, Self::Err> {
1686 Ok(vec![ScriptModuleReturnValue::IntArray(self)])
1687 }
1688}
1689#[duplicate::duplicate_item(
1690 Integer;
1691 [i8];
1692 [i16];
1693 [u8];
1694 [u16];
1695)]
1696impl IntoScriptModuleReturnValue for Vec<Integer> {
1697 type Err = std::convert::Infallible;
1698 fn into_return_values(self) -> Result<Vec<ScriptModuleReturnValue>, Self::Err> {
1699 Ok(vec![ScriptModuleReturnValue::IntArray(
1700 self.into_iter().map(|value| value as i32).collect(),
1701 )])
1702 }
1703}
1704#[duplicate::duplicate_item(
1705 Integer;
1706 [i64];
1707 [i128];
1708 [isize];
1709 [u32];
1710 [u64];
1711 [u128];
1712 [usize];
1713)]
1714impl IntoScriptModuleReturnValue for Vec<Integer> {
1715 type Err = std::num::TryFromIntError;
1716 fn into_return_values(self) -> Result<Vec<ScriptModuleReturnValue>, Self::Err> {
1717 Ok(vec![ScriptModuleReturnValue::IntArray(
1718 self.into_iter()
1719 .map(i32::try_from)
1720 .collect::<Result<_, _>>()?,
1721 )])
1722 }
1723}
1724impl IntoScriptModuleReturnValue for Vec<f64> {
1725 type Err = std::convert::Infallible;
1726 fn into_return_values(self) -> Result<Vec<ScriptModuleReturnValue>, Self::Err> {
1727 Ok(vec![ScriptModuleReturnValue::FloatArray(self)])
1728 }
1729}
1730impl IntoScriptModuleReturnValue for Vec<f32> {
1731 type Err = std::convert::Infallible;
1732 fn into_return_values(self) -> Result<Vec<ScriptModuleReturnValue>, Self::Err> {
1733 Ok(vec![ScriptModuleReturnValue::FloatArray(
1734 self.into_iter().map(f64::from).collect(),
1735 )])
1736 }
1737}
1738impl<T> IntoScriptModuleReturnValue for &[T]
1739where
1740 Vec<T>: IntoScriptModuleReturnValue,
1741 T: Clone,
1742{
1743 type Err = <Vec<T> as IntoScriptModuleReturnValue>::Err;
1744 fn into_return_values(self) -> Result<Vec<ScriptModuleReturnValue>, Self::Err> {
1745 let vec: Vec<T> = self.to_vec();
1746 vec.into_return_values()
1747 }
1748}
1749
1750impl IntoScriptModuleReturnValue for std::collections::HashMap<String, i32> {
1751 type Err = std::convert::Infallible;
1752 fn into_return_values(self) -> Result<Vec<ScriptModuleReturnValue>, Self::Err> {
1753 Ok(vec![ScriptModuleReturnValue::IntTable(self)])
1754 }
1755}
1756#[duplicate::duplicate_item(
1757 Integer;
1758 [i8];
1759 [i16];
1760 [u8];
1761 [u16];
1762)]
1763impl IntoScriptModuleReturnValue for std::collections::HashMap<String, Integer> {
1764 type Err = std::convert::Infallible;
1765 fn into_return_values(self) -> Result<Vec<ScriptModuleReturnValue>, Self::Err> {
1766 Ok(vec![ScriptModuleReturnValue::IntTable(
1767 self.into_iter()
1768 .map(|(key, value)| (key, value as i32))
1769 .collect(),
1770 )])
1771 }
1772}
1773#[duplicate::duplicate_item(
1774 Integer;
1775 [i64];
1776 [i128];
1777 [isize];
1778 [u32];
1779 [u64];
1780 [u128];
1781 [usize];
1782)]
1783impl IntoScriptModuleReturnValue for std::collections::HashMap<String, Integer> {
1784 type Err = std::num::TryFromIntError;
1785 fn into_return_values(self) -> Result<Vec<ScriptModuleReturnValue>, Self::Err> {
1786 Ok(vec![ScriptModuleReturnValue::IntTable(
1787 self.into_iter()
1788 .map(|(key, value)| Ok((key, value.try_into()?)))
1789 .collect::<Result<_, Self::Err>>()?,
1790 )])
1791 }
1792}
1793impl IntoScriptModuleReturnValue for std::collections::HashMap<String, f64> {
1794 type Err = std::convert::Infallible;
1795 fn into_return_values(self) -> Result<Vec<ScriptModuleReturnValue>, Self::Err> {
1796 Ok(vec![ScriptModuleReturnValue::FloatTable(self)])
1797 }
1798}
1799impl IntoScriptModuleReturnValue for std::collections::HashMap<String, f32> {
1800 type Err = std::convert::Infallible;
1801 fn into_return_values(self) -> Result<Vec<ScriptModuleReturnValue>, Self::Err> {
1802 Ok(vec![ScriptModuleReturnValue::FloatTable(
1803 self.into_iter()
1804 .map(|(key, value)| (key, f64::from(value)))
1805 .collect(),
1806 )])
1807 }
1808}
1809impl IntoScriptModuleReturnValue for std::collections::HashMap<String, String> {
1810 type Err = std::convert::Infallible;
1811 fn into_return_values(self) -> Result<Vec<ScriptModuleReturnValue>, Self::Err> {
1812 Ok(vec![ScriptModuleReturnValue::StringTable(self)])
1813 }
1814}
1815
1816#[doc(hidden)]
1817pub mod __table_converter {
1818 pub trait ToOptionalTableEntry {
1819 type Value;
1820 fn to_optional(&self) -> Option<Self::Value>;
1821 }
1822
1823 impl<T: Clone> ToOptionalTableEntry for Option<T> {
1824 type Value = T;
1825 fn to_optional(&self) -> Option<Self::Value> {
1826 self.clone()
1827 }
1828 }
1829 #[duplicate::duplicate_item(
1830 Number;
1831 [i8];
1832 [i16];
1833 [i32];
1834 [i64];
1835 [i128];
1836 [isize];
1837 [u8];
1838 [u16];
1839 [u32];
1840 [u64];
1841 [u128];
1842 [usize];
1843 [f32];
1844 [f64];
1845 )]
1846 impl ToOptionalTableEntry for Number {
1847 type Value = Number;
1848 fn to_optional(&self) -> Option<Self::Value> {
1849 Some(*self)
1850 }
1851 }
1852 impl ToOptionalTableEntry for String {
1853 type Value = String;
1854 fn to_optional(&self) -> Option<Self::Value> {
1855 Some(self.clone())
1856 }
1857 }
1858}
1859
1860#[doc(hidden)]
1861pub fn __push_return_value<T>(param: &mut crate::module::ScriptModuleCallHandle, value: T)
1862where
1863 T: crate::module::IntoScriptModuleReturnValue,
1864{
1865 let res = value.push_into(param);
1866 let _ = res
1867 .map_err(|e| -> Box<dyn std::error::Error + Send + Sync + 'static> {
1868 match e {
1869 crate::module::IntoScriptModuleReturnValueError::PushFailed(e) => Box::new(e),
1870 crate::module::IntoScriptModuleReturnValueError::ConversionFailed(e) => e.into(),
1871 }
1872 })
1873 .push_into(param);
1874}
1875
1876#[cfg(test)]
1877mod tests {
1878 use super::*;
1879
1880 fn assert_from_param<T>()
1881 where
1882 for<'a> T: FromScriptModuleParam<'a>,
1883 {
1884 }
1885
1886 fn assert_into_return_value<T: IntoScriptModuleReturnValue>() {}
1887
1888 fn assert_table_entry<T: __table_converter::ToOptionalTableEntry>() {}
1889
1890 fn assert_zero_is_convertible<T>()
1891 where
1892 T: FromScriptModuleInteger,
1893 {
1894 assert!(convert_script_module_integer::<T>(0).is_ok());
1895 }
1896
1897 #[test]
1898 fn converts_table_integer_to_all_numeric_types() {
1899 assert_zero_is_convertible::<i8>();
1900 assert_zero_is_convertible::<i16>();
1901 assert_zero_is_convertible::<i32>();
1902 assert_zero_is_convertible::<i64>();
1903 assert_zero_is_convertible::<i128>();
1904 assert_zero_is_convertible::<isize>();
1905 assert_zero_is_convertible::<u8>();
1906 assert_zero_is_convertible::<u16>();
1907 assert_zero_is_convertible::<u32>();
1908 assert_zero_is_convertible::<u64>();
1909 assert_zero_is_convertible::<u128>();
1910 assert_zero_is_convertible::<usize>();
1911 }
1912
1913 #[test]
1914 fn implements_numeric_collection_traits() {
1915 macro_rules! assert_integer_traits {
1916 ($($integer:ty),+ $(,)?) => {
1917 $(
1918 assert_from_param::<Vec<$integer>>();
1919 assert_into_return_value::<Vec<$integer>>();
1920 assert_into_return_value::<std::collections::HashMap<String, $integer>>();
1921 assert_table_entry::<$integer>();
1922 )+
1923 };
1924 }
1925
1926 assert_integer_traits!(
1927 i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize
1928 );
1929 assert_from_param::<Vec<f32>>();
1930 assert_from_param::<Vec<f64>>();
1931 assert_into_return_value::<Vec<f32>>();
1932 assert_into_return_value::<Vec<f64>>();
1933 assert_into_return_value::<std::collections::HashMap<String, f32>>();
1934 assert_into_return_value::<std::collections::HashMap<String, f64>>();
1935 assert_table_entry::<f32>();
1936 assert_table_entry::<f64>();
1937 }
1938
1939 #[test]
1940 fn converts_numeric_collections_to_internal_types() {
1941 let values = Vec::<u16>::from([0, u16::MAX])
1942 .into_return_values()
1943 .unwrap();
1944 assert!(matches!(
1945 values.as_slice(),
1946 [ScriptModuleReturnValue::IntArray(values)]
1947 if values == &vec![0, u16::MAX as i32]
1948 ));
1949
1950 let values = Vec::<f32>::from([1.5, -2.25]).into_return_values().unwrap();
1951 assert!(matches!(
1952 values.as_slice(),
1953 [ScriptModuleReturnValue::FloatArray(values)]
1954 if values == &vec![1.5, -2.25]
1955 ));
1956
1957 let values = std::collections::HashMap::from([("value".to_string(), 1.5_f32)])
1958 .into_return_values()
1959 .unwrap();
1960 assert!(matches!(
1961 values.as_slice(),
1962 [ScriptModuleReturnValue::FloatTable(values)]
1963 if values.get("value") == Some(&1.5)
1964 ));
1965 }
1966
1967 #[test]
1968 fn reports_numeric_collection_conversion_errors() {
1969 assert!(
1970 Vec::from([i64::from(i32::MAX) + 1])
1971 .into_return_values()
1972 .is_err()
1973 );
1974 assert!(
1975 std::collections::HashMap::from([("value".to_string(), u64::MAX)])
1976 .into_return_values()
1977 .is_err()
1978 );
1979 }
1980
1981 #[test]
1982 fn reports_table_integer_conversion_errors() {
1983 assert!(matches!(
1984 convert_script_module_integer::<i8>(i8::MAX as i32 + 1),
1985 Err(ScriptModuleCallHandleError::ConversionError(_))
1986 ));
1987 assert!(matches!(
1988 convert_script_module_integer::<u32>(-1),
1989 Err(ScriptModuleCallHandleError::ConversionError(_))
1990 ));
1991 }
1992
1993 #[test]
1994 fn preserves_existing_error_when_changing_conversion_error_type() {
1995 let error: ScriptModuleCallHandleError<ParamConversionError> =
1996 ScriptModuleCallHandleError::TypeMismatch {
1997 expected: ParamType::Table,
1998 actual: ParamType::Number,
1999 }
2000 .into_conversion_error();
2001
2002 assert!(matches!(
2003 error,
2004 ScriptModuleCallHandleError::TypeMismatch {
2005 expected: ParamType::Table,
2006 actual: ParamType::Number,
2007 }
2008 ));
2009 }
2010}