aviutl2_macros/
lib.rs

1//! # aviutl2-macros
2//!
3//! [aviutl2-rs](https://docs.rs/aviutl2)のためのproc macroを提供するクレート。
4//! 詳細は[aviutl2-rs](https://docs.rs/aviutl2)のドキュメントを参照してください。
5
6mod filter_config_items;
7mod filter_config_select_items;
8mod from_script_module_param;
9mod generic_menus;
10mod into_script_module_return_value;
11mod module_functions;
12mod plugin;
13mod utils;
14
15/// `FilterConfigItems` を自動で実装するためのマクロ。
16///
17/// # Attributes
18///
19/// - structのフィールドはすべてちょうど1つの属性を持つ必要があります。
20///
21/// ## `track`
22///
23/// ```rust
24/// # #[derive(aviutl2_macros::FilterConfigItems)]
25/// # struct S {
26/// #[track(name = "サンプル整数", range = 0..=100, default = 50, step = 1.0)]
27/// int_field: i32,
28/// #[track(name = "サンプル小数", range = 0.0..=1.0, default = 0.5, step = 0.01)]
29/// float_field: f64,
30/// # }
31/// ```
32///
33/// - `name`: トラックバーの名前。省略した場合、フィールド名が使用されます。
34/// - `range`: トラックバーの範囲。閉区間で指定します(例: `0.0..=1.0`)。
35/// - `default`: トラックバーの初期値。
36/// - `step`: トラックバーのステップ値。`1.0`, `0.1`, `0.01`, `0.001` のいずれかを指定します。
37///
38/// - `range`、`default`は`step`で割り切れる値である必要があります。
39/// - 値の型はプリミティブ、厳密には`value as _`で変換可能な型である必要があります。
40///
41/// ## `check`
42///
43/// ```rust
44/// # #[derive(aviutl2_macros::FilterConfigItems)]
45/// # struct S {
46/// #[check(name = "サンプルチェックボックス", default = true)]
47/// bool_field: bool,
48/// # }
49/// ```
50///
51/// - `name`: チェックボックスの名前。省略した場合、フィールド名が使用されます。
52/// - `default`: チェックボックスの初期値。
53///
54/// - 値の型は`bool`である必要があります。
55///
56/// ## `color`
57///
58/// ```rust
59/// # #[derive(aviutl2_macros::FilterConfigItems)]
60/// # struct S {
61/// #[color(name = "サンプルカラー", default = 0x48b0d5)]
62/// color_field: aviutl2::filter::FilterConfigColorValue,
63/// #[color(name = "サンプルカラー2", default = "#48b0d5")]
64/// color_field2: aviutl2::filter::FilterConfigColorValue,
65/// #[color(name = "サンプルカラー3", default = (72, 176, 213))]
66/// color_field3: aviutl2::filter::FilterConfigColorValue,
67/// # }
68/// ```
69///
70/// - `name`: 色選択の名前。省略した場合、フィールド名が使用されます。
71/// - `default`: 色の初期値。`0xRRGGBB`形式の整数、`"#RRGGBB"`形式の文字列、または`(R, G, B)`形式のタプルで指定します。
72///
73/// - 値の型は`From<aviutl2::filter::FilterConfigColorValue>`を実装している必要があります。
74///
75/// ## `select`
76///
77/// ```rust
78/// # #[derive(aviutl2_macros::FilterConfigItems)]
79/// # struct S {
80/// #[select(
81///     name = "サンプルセレクトボックス",
82///     items = ["オプション1", "オプション2", "オプション3"],
83///     default = 0
84/// )]
85/// select_field: usize,
86/// # }
87/// ```
88///
89/// ```rust
90/// #[derive(aviutl2::filter::FilterConfigSelectItems)]
91/// enum MySelectItem {
92///    #[item(name = "Hoge")]
93///    Hoge,
94///    #[item(name = "Fuga")]
95///    Fuga,
96/// }
97///
98/// #[derive(aviutl2_macros::FilterConfigItems)]
99/// struct MyConfig {
100///     #[select(
101///         name = "サンプルセレクトボックス",
102///         items = MySelectItem,
103///         default = MySelectItem::Hoge
104///     )]
105///     select_field: MySelectItem,
106/// }
107/// ```
108///
109/// - `name`: セレクトボックスの名前。省略した場合、フィールド名が使用されます。
110/// - `items`: セレクトボックスの項目のリスト、または`aviutl2::filter::FilterConfigSelectItems`を実装したenumの名前。
111/// - `default`: セレクトボックスの初期値。`items`のインデックス、またはenumのVariantを指定します。
112///
113/// - 値の型は`default`が`items`のインデックスの場合は`usize`、
114///   `default`がenumのVariantの場合はそのenumである必要があります。
115///
116/// ## `file`
117///
118/// ```rust
119/// # #[derive(aviutl2_macros::FilterConfigItems)]
120/// # struct S {
121/// #[file(name = "サンプルファイル", filters = {
122///     "テキストファイル" => ["txt"],
123///     "すべてのファイル" => []
124/// })]
125/// file_field: Option<std::path::PathBuf>,
126/// # }
127/// ```
128///
129/// - `name`: ファイル選択の名前。省略した場合、フィールド名が使用されます。
130/// - `filters`: ファイルフィルタのリスト。キーがフィルタ名、値が拡張子のリストです。
131///
132/// - 値の型は`Option<std::path::PathBuf>`である必要があります。
133///
134/// # Example
135///
136/// ```rust
137/// #[derive(Debug, aviutl2::filter::FilterConfigItems)]
138/// struct FilterConfig {
139///     #[track(name = "サンプル整数", range = -100..=100, default = 0, step = 1.0)]
140///     sample_integer: i32,
141///     #[track(name = "サンプル小数", range = -1.0..=1.0, default = 0.0, step = 0.01)]
142///     sample_float: f64,
143///     #[check(name = "サンプルチェックボックス", default = true)]
144///     sample_checkbox: bool,
145///     #[select(
146///         name = "サンプルセレクトボックス",
147///         items = ["オプション1", "オプション2", "オプション3"],
148///         default = 0
149///     )]
150///     sample_select: usize,
151///     #[color(name = "サンプルカラー", default = 0x48b0d5)]
152///     sample_color: aviutl2::filter::FilterConfigColorValue,
153///     #[file(name = "サンプルファイル", filters = {
154///         "テキストファイル" => ["txt"],
155///         "すべてのファイル" => [],
156///     })]
157///     sample_file: Option<std::path::PathBuf>,
158/// }
159/// ```
160///
161/// # See Also
162///
163/// - [`FilterConfigSelectItems`]
164#[proc_macro_derive(FilterConfigItems, attributes(track, check, color, select, file))]
165pub fn filter_config_items(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
166    filter_config_items::filter_config_items(item.into())
167        .unwrap_or_else(|e| e)
168        .into()
169}
170
171/// `FilterConfigSelectItems` を自動で実装するためのマクロ。
172///
173/// # Attributes
174///
175/// - enumのフィールドはすべて最大1つのitem属性を持つことができます。
176/// - enumは値を持つことができません(Unit-only Enumである必要があります)。
177///
178/// ## `item`
179///
180/// ```rust
181/// # #[derive(aviutl2::filter::FilterConfigSelectItems)]
182/// # enum MySelectItem {
183/// #[item(name = "hoge")]
184/// Hoge,
185/// #[item(name = "fuga")]
186/// Fuga = 4,
187/// Piyo,
188/// # }
189/// ```
190///
191/// - `name`: AviUtl2上で表示されるテキスト。省略された場合はVariantの名前になります。
192///
193/// # Example
194///
195/// ```rust
196/// #[derive(Debug, aviutl2::filter::FilterConfigSelectItems)]
197/// enum MySelectItem {
198///     #[item(name = "Hoge")]
199///     Hoge,
200///     #[item(name = "Fuga")]
201///     Fuga,
202/// }
203/// ```
204#[proc_macro_derive(FilterConfigSelectItems, attributes(item))]
205pub fn filter_config_select_items(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
206    filter_config_select_items::filter_config_select_items(item.into())
207        .unwrap_or_else(|e| e)
208        .into()
209}
210
211/// `ScriptModuleFunctions` を実装するためのマクロ。
212///
213/// このマクロは`impl`ブロックに対して適用されます。
214/// `impl`ブロック内で定義された関数がスクリプトモジュールの関数として登録されます。
215///
216/// # Attributes
217///
218/// ### `direct`
219///
220/// 関数の引数を手動で処理する関数として登録します。
221/// 関数のシグネチャは以下のようになります。
222///
223/// ```rust
224/// # use aviutl2::module::IntoScriptModuleReturnValue;
225/// # #[aviutl2::plugin(ScriptModule)]
226/// # struct MyModule {
227/// #     counter: std::sync::atomic::AtomicI32,
228/// # }
229/// # impl aviutl2::module::ScriptModule for MyModule {
230/// #     fn new(_info: aviutl2::AviUtl2Info) -> aviutl2::AnyResult<Self> {
231/// #         unimplemented!()
232/// #     }
233/// #     fn plugin_info(&self) -> aviutl2::module::ScriptModuleTable {
234/// #         unimplemented!()
235/// #     }
236/// # }
237/// # #[aviutl2::module::functions]
238/// # impl MyModule {
239/// #     #[direct]
240/// fn function_name(params: &mut aviutl2::module::ScriptModuleCallHandle) -> ()
241/// #     {}
242/// # }
243/// ```
244///
245/// # Example
246///
247/// ```rust
248/// use aviutl2::module::IntoScriptModuleReturnValue;
249///
250/// #[aviutl2::plugin(ScriptModule)]
251/// struct MyModule {
252///     counter: std::sync::atomic::AtomicI32,
253/// }
254/// # impl aviutl2::module::ScriptModule for MyModule {
255/// #     fn new(_info: aviutl2::AviUtl2Info) -> aviutl2::AnyResult<Self> {
256/// #         unimplemented!()
257/// #     }
258/// #     fn plugin_info(&self) -> aviutl2::module::ScriptModuleTable {
259/// #         unimplemented!()
260/// #     }
261/// # }
262/// #[aviutl2::module::functions]
263/// impl MyModule {
264///     fn sum(a: i32, b: i32) -> i32 {
265///         a + b
266///     }
267///
268///     fn return_overload(a: i32) -> impl aviutl2::module::IntoScriptModuleReturnValue {
269///         if a % 2 == 0 {
270///             "Even".into_return_values().map_err(anyhow::Error::from)
271///         } else {
272///             ("Odd", a).into_return_values()
273///         }
274///     }
275///
276///     fn increment_counter(&self) -> i32 {
277///         self.counter.fetch_add(1, std::sync::atomic::Ordering::SeqCst) + 1
278///     }
279///
280///     #[direct]
281///     fn direct_sum(params: &mut aviutl2::module::ScriptModuleCallHandle) {
282///         let a: i32 = params.get_param(0).unwrap_or(0);
283///         let b: i32 = params.get_param(1).unwrap_or(0);
284///         params.push_result(a + b);
285///     }
286///
287///     #[direct]
288///     fn direct_sum_with_counter(
289///         &self,
290///         params: &mut aviutl2::module::ScriptModuleCallHandle,
291///     ) {
292///         let a: i32 = params.get_param(0).unwrap_or(0);
293///         let b: i32 = params.get_param(1).unwrap_or(0);
294///         let count = self.increment_counter();
295///         params.push_result((a + b, count));
296///     }
297/// }
298/// # fn main() {}
299/// ```
300#[proc_macro_attribute]
301pub fn module_functions(
302    _attr: proc_macro::TokenStream,
303    item: proc_macro::TokenStream,
304) -> proc_macro::TokenStream {
305    module_functions::module_functions(item.into())
306        .unwrap_or_else(|e| e)
307        .into()
308}
309
310/// `FromScriptModuleParam` を自動で実装するためのマクロ。
311///
312/// このマクロを利用するには、構造体の各フィールドが `aviutl2::module::FromScriptModuleParamValue`
313/// トレイトを実装している必要があります。
314///
315/// # Example
316///
317/// ```rust
318/// #[derive(aviutl2::module::FromScriptModuleParam)]
319/// struct MyStruct {
320///     foo: i32,
321///     bar: String,
322/// }
323/// ```
324#[proc_macro_derive(FromScriptModuleParam)]
325pub fn from_script_module_param(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
326    from_script_module_param::from_script_module_param(item.into())
327        .unwrap_or_else(|e| e)
328        .into()
329}
330
331/// `IntoScriptModuleReturnValue` を自動で実装するためのマクロ。
332///
333/// このマクロを利用するには、
334///
335/// - 構造体のすべてのフィールドが同じ`T`または`Option<T>`型、かつ
336/// - `std::collections::HashMap<String, T>`が`IntoScriptModuleReturnValue`を実装している
337///
338/// 必要があります。
339///
340/// # Example
341///
342/// ```rust
343/// #[derive(aviutl2::module::IntoScriptModuleReturnValue)]
344/// struct MyStruct {
345///     foo: Option<String>,
346///     bar: String,
347/// }
348/// ```
349///
350/// 以下は動きません:
351///
352/// ```rust,compile_fail
353/// #[derive(aviutl2::module::IntoScriptModuleReturnValue)]
354/// struct MyBadStruct {
355///    foo: String,
356///    bar: i32, // 異なる型
357/// }
358/// ```
359///
360/// # See Also
361///
362/// - [`FromScriptModuleParam`]
363#[proc_macro_derive(IntoScriptModuleReturnValue)]
364pub fn into_script_module_return_value(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
365    into_script_module_return_value::into_script_module_return_value(item.into())
366        .unwrap_or_else(|e| e)
367        .into()
368}
369
370/// プラグインを定義するためのマクロ。
371///
372/// # Attributes
373///
374/// - 引数には`InputPlugin`、`OutputPlugin`、`FilterPlugin`、`ScriptModule`、`GenericPlugin`のいずれかを指定します。
375///
376/// # Example
377///
378/// ```rust
379/// #[aviutl2::plugin(OutputPlugin)]
380/// struct MyOutputPlugin;
381///
382/// impl aviutl2::output::OutputPlugin for MyOutputPlugin {
383///     // ...
384/// #   fn new(_info: aviutl2::AviUtl2Info) -> aviutl2::AnyResult<Self> {
385/// #       todo!()
386/// #   }
387/// #
388/// #   fn plugin_info(&self) -> aviutl2::output::OutputPluginTable {
389/// #       todo!()
390/// #   }
391/// #
392/// #   fn output(&self, info: aviutl2::output::OutputInfo) -> aviutl2::AnyResult<()> {
393/// #       todo!()
394/// #   }
395/// }
396///
397/// aviutl2::register_output_plugin!(MyOutputPlugin);
398///
399/// # fn main() {}
400/// ```
401#[proc_macro_attribute]
402pub fn plugin(
403    attr: proc_macro::TokenStream,
404    item: proc_macro::TokenStream,
405) -> proc_macro::TokenStream {
406    plugin::plugin(attr.into(), item.into())
407        .unwrap_or_else(|e| e)
408        .into()
409}
410
411/// 汎用プラグインのメニュー登録実装を生成するマクロ。
412///
413/// このマクロは`impl`ブロックに対して適用されます。
414/// `impl`ブロック内で定義された関数が汎用プラグインのメニューとして登録されます。
415///
416/// ブロック内の関数はすべて以下のシグネチャのうちいずれかを持つ必要があります:
417/// ```rust
418/// # #[aviutl2::plugin(GenericPlugin)]
419/// # struct MyGenericPlugin;
420/// # impl aviutl2::generic::GenericPlugin for MyGenericPlugin {
421/// #     fn new(_info: aviutl2::AviUtl2Info) -> aviutl2::AnyResult<Self> {
422/// #         unimplemented!()
423/// #     }
424/// #     fn register(&mut self, _handle: &mut aviutl2::generic::HostAppHandle<'_>) {
425/// #         unimplemented!()
426/// #     }
427/// # }
428/// # type E = aviutl2::anyhow::Error;
429/// # #[aviutl2::generic::menus]
430/// # impl MyGenericPlugin {
431/// #     #[import(name = "")]
432/// fn func1(edit_handle: &mut aviutl2::generic::EditSection) -> ()
433/// #     {}
434/// #     #[export(name = "")]
435/// fn func2(edit_handle: &mut aviutl2::generic::EditSection) -> Result<(), E>
436/// #     { unimplemented!() }
437/// # }
438/// # fn test<E>() -> Result<(), E>
439/// where
440///     Box<dyn std::error::Error>: From<E>,
441/// # { unimplemented!() }
442/// ```
443///
444/// # Attributes
445///
446/// ### `import`
447///
448/// 汎用プラグインのインポートメニューとして登録します。
449///
450/// - `name`: メニューに表示される名前を指定します。
451/// - `error`: エラー発生時のハンドリング方法を指定します。`"alert"`、`"log"`、`"ignore"`のいずれかを指定します。
452///   - `"alert"`: エラー発生時にアラートダイアログを表示します。(デフォルト)
453///   - `"log"`: エラー発生時にログにエラーメッセージを出力します。
454///   - `"ignore"`: エラー発生時に何も行いません。
455///
456///
457/// ### `export`
458///
459/// 汎用プラグインのエクスポートメニューとして登録します。
460/// パラメーターは`import`属性と同様です。
461///
462/// ### `layer`
463///
464/// 汎用プラグインのレイヤーメニューとして登録します。
465/// パラメーターは`import`属性と同様です。
466///
467/// ### `object`
468///
469/// 汎用プラグインのオブジェクトメニューとして登録します。
470/// パラメーターは`import`属性と同様です。
471///
472/// # Example
473///
474/// ```rust
475/// #[aviutl2::plugin(GenericPlugin)]
476/// struct MyGenericPlugin;
477/// # impl aviutl2::generic::GenericPlugin for MyGenericPlugin {
478/// #     fn new(_info: aviutl2::AviUtl2Info) -> aviutl2::AnyResult<Self> {
479/// #         unimplemented!()
480/// #     }
481/// #     fn register(&mut self, _handle: &mut aviutl2::generic::HostAppHandle<'_>) {
482/// #         unimplemented!()
483/// #     }
484/// # }
485///
486/// #[aviutl2::generic::menus]
487/// impl MyGenericPlugin {
488///     #[import(name = ".txtファイルをインポート")]
489///     fn import_text(edit_handle: &mut aviutl2::generic::EditSection) -> aviutl2::AnyResult<()> {
490///         // ...
491/// #       Ok(())
492///     }
493///
494///     #[export(name = ".txtファイルをエクスポート")]
495///     fn export_text(edit_handle: &mut aviutl2::generic::EditSection) -> aviutl2::AnyResult<()> {
496///         // ...
497/// #       Ok(())
498///     }
499///
500///     #[layer(name = "レイヤーを複製")]
501///     fn duplicate_layer(edit_handle: &mut aviutl2::generic::EditSection) -> aviutl2::AnyResult<()> {
502///         // ...
503/// #       Ok(())
504///     }
505///
506///     #[object(name = "オブジェクトを削除")]
507///     fn delete_object(edit_handle: &mut aviutl2::generic::EditSection) -> aviutl2::AnyResult<()> {
508///         // ...
509/// #       Ok(())
510///     }
511/// }
512#[proc_macro_attribute]
513pub fn generic_menus(
514    _attr: proc_macro::TokenStream,
515    item: proc_macro::TokenStream,
516) -> proc_macro::TokenStream {
517    generic_menus::generic_menus(item.into())
518        .unwrap_or_else(|e| e)
519        .into()
520}