Skip to main content

aviutl2\filter/
config.rs

1use crate::common::LeakManager;
2use aviutl2_sys::plugin2::EDIT_SECTION;
3use parking_lot::lock_api::RawRwLock;
4use std::mem::MaybeUninit;
5use std::{ffi::c_void, ptr::NonNull};
6
7/// [`Vec<FilterConfigItem>`] と相互変換するためのトレイト。
8/// 基本的にはこのトレイトを手動で実装する必要はありません。
9/// [`macro@filter_config_items`] マクロを使用してください。
10///
11/// <div class="warning">
12///
13/// このcrateは[`Vec<FilterConfigItem>`]との相互変換が可能であれば十分に機能します。
14/// このトレイトを手動で実装する必要はありません。
15///
16/// </div>
17///
18/// # See Also
19///
20/// [`macro@filter_config_items`]
21pub trait FilterConfigItems: Sized {
22    /// [`Vec<FilterConfigItem>`] に変換します。
23    fn to_config_items() -> Vec<crate::filter::FilterConfigItem>;
24
25    /// [`Vec<FilterConfigItem>`] から変換します。
26    ///
27    /// # Panics
28    ///
29    /// `items` の内容が不正な場合、パニックします。
30    fn from_config_items(items: &[crate::filter::FilterConfigItem]) -> Self;
31}
32#[doc(inline)]
33pub use aviutl2_macros::filter_config_items;
34
35/// `&[FilterConfigItem]` に対する拡張トレイト。
36pub trait FilterConfigItemSliceExt {
37    /// `&[FilterConfigItem]` から指定した構造体に変換します。
38    fn to_struct<T: crate::filter::FilterConfigItems>(&self) -> T;
39}
40
41impl FilterConfigItemSliceExt for &[FilterConfigItem] {
42    fn to_struct<T: FilterConfigItems>(&self) -> T {
43        T::from_config_items(self)
44    }
45}
46
47/// フィルタの設定。
48#[allow(clippy::large_enum_variant)]
49#[derive(Debug, Clone)]
50pub enum FilterConfigItem {
51    /// トラックバー。
52    Track(FilterConfigTrack),
53    /// チェックボックス。
54    Check(FilterConfigCheck),
55    /// セクションごとのチェックボックス。
56    CheckSection(FilterConfigCheckSection),
57    /// 色選択。
58    Color(FilterConfigColor),
59    /// 選択リスト。
60    Select(FilterConfigSelect),
61    /// ファイル選択。
62    File(FilterConfigFile),
63    /// 文字列。
64    String(FilterConfigString),
65    /// テキスト。
66    Text(FilterConfigText),
67    /// フォルダ選択。
68    Folder(FilterConfigFolder),
69    /// 汎用データ。
70    ///
71    /// # Note
72    ///
73    /// Undoポイントの作成や編集済みフラグの設定はされません。
74    Data(ErasedFilterConfigData),
75    /// グループ。
76    Group(FilterConfigGroup),
77    /// セパレーター。
78    Separator(FilterConfigSeparator),
79    /// ボタン。
80    Button(FilterConfigButton),
81    /// トラックバーグループ。
82    TrackGroup(FilterConfigTrackGroup),
83    /// 非表示条件。
84    HideRule(FilterConfigHideRule),
85}
86
87#[derive(Debug, Clone, PartialEq)]
88pub(crate) enum FilterConfigItemValue {
89    Track(f64),
90    Check(bool),
91    CheckSection(bool),
92    Color(FilterConfigColorValue),
93    Select(i32),
94    File(String),
95    String(String),
96    Text(String),
97    Folder(String),
98    Data {
99        value: *mut std::ffi::c_void,
100        size: usize,
101    },
102    Group,
103    Separator,
104    Button,
105    TrackGroup,
106    HideRule,
107}
108
109impl FilterConfigItem {
110    /// 設定名を取得します。
111    ///
112    /// # Note
113    ///
114    /// `FilterConfigItem::Group` の場合、`name` が `None` のときは空文字列を返します。
115    pub fn name(&self) -> &str {
116        match self {
117            FilterConfigItem::Track(item) => &item.name,
118            FilterConfigItem::Check(item) => &item.name,
119            FilterConfigItem::Color(item) => &item.name,
120            FilterConfigItem::Select(item) => &item.name,
121            FilterConfigItem::File(item) => &item.name,
122            FilterConfigItem::String(item) => &item.name,
123            FilterConfigItem::Text(item) => &item.name,
124            FilterConfigItem::Folder(item) => &item.name,
125            FilterConfigItem::Data(item) => &item.name,
126            FilterConfigItem::Group(item) => item.name.as_deref().unwrap_or(""),
127            FilterConfigItem::Separator(item) => &item.name,
128            FilterConfigItem::Button(item) => &item.name,
129            FilterConfigItem::CheckSection(item) => &item.name,
130            FilterConfigItem::TrackGroup(item) => &item.name,
131            FilterConfigItem::HideRule(item) => &item.name,
132        }
133    }
134
135    pub(crate) fn to_raw(&self, leak_manager: &LeakManager) -> aviutl2_sys::filter2::FILTER_ITEM {
136        match self {
137            FilterConfigItem::Track(item) => aviutl2_sys::filter2::FILTER_ITEM {
138                track: aviutl2_sys::filter2::FILTER_ITEM_TRACK {
139                    r#type: leak_manager.leak_as_wide_string("track2"),
140                    name: leak_manager.leak_as_wide_string(&item.name),
141                    value: item.value,
142                    s: *item.range.start(),
143                    e: *item.range.end(),
144                    step: item.step,
145                    zero_display: item
146                        .zero_display
147                        .as_ref()
148                        .map_or(std::ptr::null(), |s| leak_manager.leak_as_wide_string(s)),
149                    slider_ratio: item.slider_ratio,
150                },
151            },
152            FilterConfigItem::Check(item) => aviutl2_sys::filter2::FILTER_ITEM {
153                check: aviutl2_sys::filter2::FILTER_ITEM_CHECK {
154                    r#type: leak_manager.leak_as_wide_string("check"),
155                    name: leak_manager.leak_as_wide_string(&item.name),
156                    value: item.value,
157                },
158            },
159            FilterConfigItem::Color(item) => aviutl2_sys::filter2::FILTER_ITEM {
160                color: aviutl2_sys::filter2::FILTER_ITEM_COLOR {
161                    r#type: leak_manager.leak_as_wide_string("color"),
162                    name: leak_manager.leak_as_wide_string(&item.name),
163                    value: item.value.into(),
164                },
165            },
166            FilterConfigItem::Select(item) => {
167                let mut raw_items: Vec<aviutl2_sys::filter2::FILTER_ITEM_SELECT_ITEM> = item
168                    .items
169                    .iter()
170                    .map(|i| aviutl2_sys::filter2::FILTER_ITEM_SELECT_ITEM {
171                        name: leak_manager.leak_as_wide_string(&i.name),
172                        value: i.value,
173                    })
174                    .collect();
175                raw_items.push(aviutl2_sys::filter2::FILTER_ITEM_SELECT_ITEM {
176                    name: std::ptr::null(),
177                    value: 0,
178                }); // 終端用
179                let raw_items_ptrs = leak_manager.leak_value_vec(raw_items);
180                aviutl2_sys::filter2::FILTER_ITEM {
181                    select: aviutl2_sys::filter2::FILTER_ITEM_SELECT {
182                        r#type: leak_manager.leak_as_wide_string("select"),
183                        name: leak_manager.leak_as_wide_string(&item.name),
184                        value: item.value,
185                        items: raw_items_ptrs,
186                    },
187                }
188            }
189            FilterConfigItem::File(item) => {
190                let raw_filters = crate::common::format_file_filters(&item.filters);
191                aviutl2_sys::filter2::FILTER_ITEM {
192                    file: aviutl2_sys::filter2::FILTER_ITEM_FILE {
193                        r#type: leak_manager.leak_as_wide_string("file"),
194                        name: leak_manager.leak_as_wide_string(&item.name),
195                        value: leak_manager.leak_as_wide_string(&item.value),
196                        filefilter: leak_manager.leak_as_wide_string(&raw_filters),
197                    },
198                }
199            }
200            FilterConfigItem::String(item) => aviutl2_sys::filter2::FILTER_ITEM {
201                string: aviutl2_sys::filter2::FILTER_ITEM_STRING {
202                    r#type: leak_manager.leak_as_wide_string("string"),
203                    name: leak_manager.leak_as_wide_string(&item.name),
204                    value: leak_manager.leak_as_wide_string(&item.value),
205                },
206            },
207            FilterConfigItem::Text(item) => aviutl2_sys::filter2::FILTER_ITEM {
208                text: aviutl2_sys::filter2::FILTER_ITEM_TEXT {
209                    r#type: leak_manager.leak_as_wide_string("text"),
210                    name: leak_manager.leak_as_wide_string(&item.name),
211                    value: leak_manager.leak_as_wide_string(&item.value),
212                },
213            },
214            FilterConfigItem::Folder(item) => aviutl2_sys::filter2::FILTER_ITEM {
215                folder: aviutl2_sys::filter2::FILTER_ITEM_FOLDER {
216                    r#type: leak_manager.leak_as_wide_string("folder"),
217                    name: leak_manager.leak_as_wide_string(&item.name),
218                    value: leak_manager.leak_as_wide_string(&item.value),
219                },
220            },
221            FilterConfigItem::Data(item) => {
222                let mut data = aviutl2_sys::filter2::FILTER_ITEM_DATA {
223                    r#type: leak_manager.leak_as_wide_string("data"),
224                    name: leak_manager.leak_as_wide_string(&item.name),
225                    value: std::ptr::null_mut(),
226                    size: item.size as i32,
227                    default_value: [MaybeUninit::new(0); 16 * 1024],
228                };
229                assert!(
230                    item.size <= 16 * 1024,
231                    "FilterConfigData size must be <= 16 KiB"
232                );
233                unsafe {
234                    // SAFETY:
235                    // - item.size <= 16KiBかつ、
236                    // - item.default_value()はitem.size分のデータを持っている
237                    std::ptr::copy_nonoverlapping(
238                        item.default_value().as_ptr(),
239                        data.default_value.as_mut_ptr() as *mut u8,
240                        item.size,
241                    );
242                }
243
244                aviutl2_sys::filter2::FILTER_ITEM { data }
245            }
246            FilterConfigItem::Group(item) => aviutl2_sys::filter2::FILTER_ITEM {
247                group: aviutl2_sys::filter2::FILTER_ITEM_GROUP {
248                    r#type: leak_manager.leak_as_wide_string("group"),
249                    name: leak_manager.leak_as_wide_string(item.name.as_deref().unwrap_or("")),
250                    default_visible: item.opened,
251                },
252            },
253            FilterConfigItem::Separator(item) => aviutl2_sys::filter2::FILTER_ITEM {
254                separator: aviutl2_sys::filter2::FILTER_ITEM_SEPARATOR {
255                    r#type: leak_manager.leak_as_wide_string("separator"),
256                    name: leak_manager.leak_as_wide_string(&item.name),
257                },
258            },
259            FilterConfigItem::Button(item) => aviutl2_sys::filter2::FILTER_ITEM {
260                button: aviutl2_sys::filter2::FILTER_ITEM_BUTTON {
261                    r#type: leak_manager.leak_as_wide_string("button"),
262                    name: leak_manager.leak_as_wide_string(&item.name),
263                    callback: item.callback,
264                },
265            },
266            FilterConfigItem::CheckSection(filter_config_check_section) => {
267                aviutl2_sys::filter2::FILTER_ITEM {
268                    check_section: aviutl2_sys::filter2::FILTER_ITEM_CHECK_SECTION {
269                        r#type: leak_manager.leak_as_wide_string("checksection2"),
270                        name: leak_manager.leak_as_wide_string(&filter_config_check_section.name),
271                        value: filter_config_check_section.value,
272                        multi_section: filter_config_check_section.multi_section,
273                    },
274                }
275            }
276            FilterConfigItem::TrackGroup(filter_config_track_group) => {
277                let mut tracks = Vec::new();
278                for item in &filter_config_track_group.tracks {
279                    let raw = FilterConfigItem::to_raw(
280                        &FilterConfigItem::Track(item.clone()),
281                        leak_manager,
282                    );
283                    tracks.push(leak_manager.leak(raw));
284                }
285                tracks.push(std::ptr::null_mut());
286
287                let pointers = leak_manager.leak_value_vec(tracks);
288
289                aviutl2_sys::filter2::FILTER_ITEM {
290                    track_group: aviutl2_sys::filter2::FILTER_ITEM_TRACK_GROUP {
291                        r#type: leak_manager.leak_as_wide_string("trackgroup"),
292                        name: leak_manager.leak_as_wide_string(&filter_config_track_group.name),
293                        tracks: pointers as _,
294                    },
295                }
296            }
297            FilterConfigItem::HideRule(filter_config_hide_rule) => {
298                aviutl2_sys::filter2::FILTER_ITEM {
299                    hide_rule: aviutl2_sys::filter2::FILTER_ITEM_HIDE_RULE {
300                        r#type: leak_manager.leak_as_wide_string("hiderule"),
301                        name: leak_manager.leak_as_wide_string(&filter_config_hide_rule.name),
302                        condition_name: filter_config_hide_rule
303                            .condition_name
304                            .as_ref()
305                            .map_or(std::ptr::null(), |s| leak_manager.leak_as_wide_string(s)),
306                        condition_operator:
307                            aviutl2_sys::filter2::FILTER_ITEM_HIDE_RULE_OPERATOR::from(
308                                filter_config_hide_rule.condition_operator,
309                            ),
310                        condition_value: filter_config_hide_rule.condition_value,
311                    },
312                }
313            }
314        }
315    }
316
317    /// # Safety
318    ///
319    /// `raw` は有効なポインタである必要があります。
320    pub(crate) unsafe fn get_value(
321        raw: *const aviutl2_sys::filter2::FILTER_ITEM,
322    ) -> FilterConfigItemValue {
323        let item_type = unsafe {
324            crate::common::load_wide_string(
325                // SAFETY: aviutl2_sys::filter2::FILTER_ITEM の最初のメンバーはLPCWSTRなので問題ないはず
326                *(raw.cast::<aviutl2_sys::common::LPCWSTR>()),
327            )
328        };
329        match item_type.as_str() {
330            "track" | "track2" => {
331                let raw_track = unsafe { &(*raw).track };
332                FilterConfigItemValue::Track(raw_track.value)
333            }
334            "check" => {
335                let raw_check = unsafe { &(*raw).check };
336                FilterConfigItemValue::Check(raw_check.value)
337            }
338            "color" => {
339                let raw_color = unsafe { &(*raw).color };
340                FilterConfigItemValue::Color(raw_color.value.into())
341            }
342            "select" => {
343                let raw_select = unsafe { &(*raw).select };
344                FilterConfigItemValue::Select(raw_select.value)
345            }
346            "file" => {
347                let raw_file = unsafe { &(*raw).file };
348                let value = unsafe { crate::common::load_wide_string(raw_file.value) };
349                FilterConfigItemValue::File(value)
350            }
351            "string" => {
352                let raw_string = unsafe { &(*raw).string };
353                let value = unsafe { crate::common::load_wide_string(raw_string.value) };
354                FilterConfigItemValue::String(value)
355            }
356            "text" => {
357                let raw_text = unsafe { &(*raw).text };
358                let value = unsafe { crate::common::load_wide_string(raw_text.value) };
359                FilterConfigItemValue::Text(value)
360            }
361            "folder" => {
362                let raw_folder = unsafe { &(*raw).folder };
363                let value = unsafe { crate::common::load_wide_string(raw_folder.value) };
364                FilterConfigItemValue::Folder(value)
365            }
366            "data" => {
367                // NOTE:
368                // `&(*raw).data`だと最後の方がアクセス違反になりかねないメモリを指す可能性があるのでしない
369                let raw_size = unsafe { (*raw).data.size };
370                let raw_data = unsafe { (*raw).data.value };
371                let size =
372                    usize::try_from(raw_size).expect("FILTER_ITEM_DATA size must not be negative");
373                assert!(
374                    size <= 16 * 1024,
375                    "FILTER_ITEM_DATA size must be 16 KiB or less"
376                );
377                FilterConfigItemValue::Data {
378                    value: raw_data,
379                    size,
380                }
381            }
382            "group" => FilterConfigItemValue::Group,
383            "separator" => FilterConfigItemValue::Separator,
384            "button" => FilterConfigItemValue::Button,
385            "checksection" | "checksection2" => {
386                let raw_check_section = unsafe { &(*raw).check_section };
387                FilterConfigItemValue::CheckSection(raw_check_section.value)
388            }
389            "trackgroup" => FilterConfigItemValue::TrackGroup,
390            "hiderule" => FilterConfigItemValue::HideRule,
391            _ => panic!("Unknown filter config item type: {}", item_type),
392        }
393    }
394
395    /// # Safety
396    ///
397    /// `raw` は有効なポインタである必要があります。
398    pub(crate) unsafe fn should_apply_from_raw(
399        &self,
400        raw: *const aviutl2_sys::filter2::FILTER_ITEM,
401    ) -> bool {
402        let value = unsafe { Self::get_value(raw) };
403        match (self, value) {
404            (FilterConfigItem::Track(item), FilterConfigItemValue::Track(v)) => item.value != v,
405            (FilterConfigItem::Check(item), FilterConfigItemValue::Check(v)) => item.value != v,
406            (FilterConfigItem::Color(item), FilterConfigItemValue::Color(v)) => item.value != v,
407            (FilterConfigItem::Select(item), FilterConfigItemValue::Select(v)) => item.value != v,
408            (FilterConfigItem::File(item), FilterConfigItemValue::File(v)) => item.value != v,
409            (FilterConfigItem::String(item), FilterConfigItemValue::String(v)) => item.value != v,
410            (FilterConfigItem::Text(item), FilterConfigItemValue::Text(v)) => item.value != v,
411            (FilterConfigItem::Folder(item), FilterConfigItemValue::Folder(v)) => item.value != v,
412            (FilterConfigItem::Data(item), FilterConfigItemValue::Data { value, size }) => {
413                let size_changed = item.size != size;
414                let ptr_changed = match (item.value, NonNull::new(value)) {
415                    (Some(old), Some(new)) => old != new,
416                    (None, None) => false,
417                    _ => true,
418                };
419
420                let binding_changed = item.variable_state.as_ref().is_some_and(|state| {
421                    let state = state.read();
422                    !matches!(
423                        *state,
424                        VariableLengthDataBacking::Host(pointer)
425                            if std::ptr::eq(
426                                pointer.as_ptr(),
427                                raw.cast_mut().cast::<aviutl2_sys::filter2::FILTER_ITEM_DATA>()
428                            )
429                    )
430                });
431
432                size_changed || ptr_changed || binding_changed
433            }
434            (FilterConfigItem::Group(_), FilterConfigItemValue::Group) => false,
435            (FilterConfigItem::Separator(_), FilterConfigItemValue::Separator) => false,
436            (FilterConfigItem::Button(_), FilterConfigItemValue::Button) => false,
437            (FilterConfigItem::CheckSection(item), FilterConfigItemValue::CheckSection(v)) => {
438                item.value != v
439            }
440            (FilterConfigItem::TrackGroup(_), FilterConfigItemValue::TrackGroup) => false,
441            (FilterConfigItem::HideRule(_), FilterConfigItemValue::HideRule) => false,
442            _ => {
443                panic!("Mismatched filter config item type");
444            }
445        }
446    }
447
448    /// # Safety
449    ///
450    /// `raw` は有効なポインタである必要があります。
451    pub(crate) unsafe fn apply_from_raw(&mut self, raw: *const aviutl2_sys::filter2::FILTER_ITEM) {
452        let value = unsafe { Self::get_value(raw) };
453        match (self, value) {
454            (FilterConfigItem::Track(item), FilterConfigItemValue::Track(v)) => {
455                item.value = v;
456            }
457            (FilterConfigItem::Check(item), FilterConfigItemValue::Check(v)) => {
458                item.value = v;
459            }
460            (FilterConfigItem::Color(item), FilterConfigItemValue::Color(v)) => {
461                item.value = v;
462            }
463            (FilterConfigItem::Select(item), FilterConfigItemValue::Select(v)) => {
464                item.value = v;
465            }
466            (FilterConfigItem::File(item), FilterConfigItemValue::File(v)) => {
467                item.value = v;
468            }
469            (FilterConfigItem::String(item), FilterConfigItemValue::String(v)) => {
470                item.value = v;
471            }
472            (FilterConfigItem::Text(item), FilterConfigItemValue::Text(v)) => {
473                item.value = v;
474            }
475            (FilterConfigItem::Folder(item), FilterConfigItemValue::Folder(v)) => {
476                item.value = v;
477            }
478            (FilterConfigItem::Data(item), FilterConfigItemValue::Data { value, size }) => {
479                item.size = size;
480                item.value = NonNull::new(value);
481                if let Some(state) = &item.variable_state {
482                    let raw = NonNull::new(
483                        raw.cast_mut()
484                            .cast::<aviutl2_sys::filter2::FILTER_ITEM_DATA>(),
485                    )
486                    .expect("FILTER_ITEM_DATA pointer must not be null");
487                    *state.write() = VariableLengthDataBacking::Host(raw);
488                }
489            }
490            (FilterConfigItem::Group(_), FilterConfigItemValue::Group) => {
491                // グループは値を持たないので何もしない
492            }
493            (FilterConfigItem::Separator(_), FilterConfigItemValue::Separator) => {
494                // セパレーターは値を持たないので何もしない
495            }
496            (FilterConfigItem::Button(_), FilterConfigItemValue::Button) => {
497                // ボタンは値を持たないので何もしない
498            }
499            (FilterConfigItem::CheckSection(item), FilterConfigItemValue::CheckSection(v)) => {
500                item.value = v;
501            }
502            (FilterConfigItem::TrackGroup(_), FilterConfigItemValue::TrackGroup) => {
503                // トラックバーグループは値を持たないので何もしない
504            }
505            (FilterConfigItem::HideRule(_), FilterConfigItemValue::HideRule) => {
506                // 非表示条件は値を持たないので何もしない
507            }
508            _ => {
509                panic!("Mismatched filter config item type");
510            }
511        }
512    }
513}
514
515/// トラックバー。
516#[derive(Debug, Clone)]
517pub struct FilterConfigTrack {
518    /// 設定名。
519    pub name: String,
520
521    /// 設定値。
522    pub value: f64,
523
524    /// 設定値の範囲。
525    pub range: std::ops::RangeInclusive<f64>,
526
527    /// 設定値の単位。
528    pub step: f64,
529
530    /// 0のときに表示する文字列。
531    pub zero_display: Option<String>,
532
533    /// スライダーの値の範囲に対するつまみの操作範囲の割合。
534    pub slider_ratio: f64,
535}
536
537/// チェックボックス。
538#[derive(Debug, Clone)]
539pub struct FilterConfigCheck {
540    /// 設定名。
541    pub name: String,
542
543    /// 設定値。
544    pub value: bool,
545}
546
547/// セクションごとのチェックボックス。
548#[derive(Debug, Clone)]
549pub struct FilterConfigCheckSection {
550    /// 設定名。
551    pub name: String,
552
553    /// 設定値。
554    pub value: bool,
555
556    /// デフォルトでセクションごとのチェックボックスにするかどうか。
557    pub multi_section: bool,
558}
559
560/// 色選択。
561#[derive(Debug, Clone)]
562pub struct FilterConfigColor {
563    /// 設定名。
564    pub name: String,
565    /// 設定値。
566    pub value: FilterConfigColorValue,
567}
568
569/// 色選択の設定値の色。
570#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
571pub struct FilterConfigColorValue(pub u32);
572impl FilterConfigColorValue {
573    /// 色をRGB形式の各成分に分解して取得します。
574    pub fn to_rgb(&self) -> (u8, u8, u8) {
575        let r = ((self.0 >> 16) & 0xFF) as u8;
576        let g = ((self.0 >> 8) & 0xFF) as u8;
577        let b = (self.0 & 0xFF) as u8;
578        (r, g, b)
579    }
580
581    /// RGB形式の各成分から色を作成します。
582    pub fn from_rgb(r: u8, g: u8, b: u8) -> Self {
583        let value = (r as u32) << 16 | (g as u32) << 8 | (b as u32);
584        FilterConfigColorValue(value)
585    }
586}
587impl From<u32> for FilterConfigColorValue {
588    fn from(value: u32) -> Self {
589        FilterConfigColorValue(value)
590    }
591}
592impl From<FilterConfigColorValue> for u32 {
593    fn from(value: FilterConfigColorValue) -> Self {
594        value.0
595    }
596}
597impl From<aviutl2_sys::filter2::FILTER_ITEM_COLOR_VALUE> for FilterConfigColorValue {
598    fn from(value: aviutl2_sys::filter2::FILTER_ITEM_COLOR_VALUE) -> Self {
599        unsafe { FilterConfigColorValue(value.code) }
600    }
601}
602impl From<FilterConfigColorValue> for aviutl2_sys::filter2::FILTER_ITEM_COLOR_VALUE {
603    fn from(value: FilterConfigColorValue) -> Self {
604        aviutl2_sys::filter2::FILTER_ITEM_COLOR_VALUE { code: value.0 }
605    }
606}
607impl std::fmt::Display for FilterConfigColorValue {
608    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
609        let (r, g, b) = self.to_rgb();
610        write!(f, "#{:02X}{:02X}{:02X}", r, g, b)
611    }
612}
613impl std::fmt::LowerHex for FilterConfigColorValue {
614    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
615        write!(f, "{:06x}", self.0 & 0xFFFFFF)
616    }
617}
618impl std::fmt::UpperHex for FilterConfigColorValue {
619    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
620        write!(f, "{:06X}", self.0 & 0xFFFFFF)
621    }
622}
623
624/// 選択リスト。
625#[derive(Debug, Clone)]
626pub struct FilterConfigSelect {
627    /// 設定名。
628    pub name: String,
629    /// 設定値。
630    pub value: i32,
631    /// 選択肢リスト。
632    pub items: Vec<FilterConfigSelectItem>,
633}
634
635/// 選択リストの選択肢。
636#[derive(Debug, Clone)]
637pub struct FilterConfigSelectItem {
638    /// 選択肢の名前。
639    pub name: String,
640    /// 選択肢の値。
641    pub value: i32,
642}
643
644/// `[Vec<FilterConfigSelectItem>]`に変換したり、AviUtl2側の値から変換するためのトレイト。
645///
646/// 基本的にはこのトレイトを手動で実装する必要はありません。
647/// [`derive@FilterConfigSelectItems`] マクロを使用してください。
648///
649/// <div class="warning">
650///
651/// [`FilterConfigSelect`]は[`Vec<FilterConfigSelectItems>`]との相互変換が可能であれば十分に機能します。
652/// このトレイトを手動で実装する必要はありません。
653///
654/// </div>
655///
656/// # See Also
657///
658/// [derive@FilterConfigSelectItems]
659pub trait FilterConfigSelectItems {
660    /// [`Vec<FilterConfigSelectItem>`] に変換します。
661    fn to_select_items() -> Vec<crate::filter::FilterConfigSelectItem>;
662
663    /// [`i32`] から変換します。
664    ///
665    /// # Panics
666    ///
667    /// `item` の内容が不正な場合、パニックします。
668    fn from_select_item_value(item: i32) -> Self;
669
670    /// [`i32`] へ変換します。
671    fn to_select_item_value(&self) -> i32;
672}
673
674#[doc(inline)]
675pub use aviutl2_macros::FilterConfigSelectItems;
676
677/// ファイル選択。
678#[derive(Debug, Clone)]
679pub struct FilterConfigFile {
680    /// 設定名。
681    pub name: String,
682    /// 設定値。
683    pub value: String,
684    /// ファイルフィルタ。
685    pub filters: Vec<crate::common::FileFilter>,
686}
687
688/// ボタン。
689#[derive(Debug, Clone)]
690pub struct FilterConfigButton {
691    /// 設定名。
692    pub name: String,
693    /// コールバック関数。
694    pub callback: extern "C" fn(*mut EDIT_SECTION),
695}
696
697/// 文字列。
698#[derive(Debug, Clone)]
699pub struct FilterConfigString {
700    /// 設定名。
701    pub name: String,
702    /// 設定値。
703    pub value: String,
704}
705
706/// テキスト。
707#[derive(Debug, Clone)]
708pub struct FilterConfigText {
709    /// 設定名。
710    pub name: String,
711    /// 設定値。
712    pub value: String,
713}
714
715/// フォルダ選択。
716#[derive(Debug, Clone)]
717pub struct FilterConfigFolder {
718    /// 設定名。
719    pub name: String,
720    /// 設定値。
721    pub value: String,
722}
723
724/// 型を消去した汎用データ。
725///
726/// # Warning
727///
728/// この型は型が全くついていません。
729/// 基本的には[`FilterConfigData`]を使用してください。
730#[derive(Debug, Clone)]
731pub struct ErasedFilterConfigData {
732    /// 設定名。
733    pub name: String,
734    /// データのサイズ。
735    ///
736    /// # Note
737    ///
738    /// 16KiBを超えるデータはサポートされません。
739    pub size: usize,
740    /// 現在の値を指すポインタ。
741    pub value: Option<NonNull<std::ffi::c_void>>,
742    default_value: [u8; 16 * 1024],
743    variable_state: Option<std::sync::Arc<parking_lot::RwLock<VariableLengthDataBacking>>>,
744}
745
746impl ErasedFilterConfigData {
747    /// 新しく作成します。
748    /// `value` は `None` になります。
749    ///
750    /// # Panics
751    ///
752    /// Tが16KiBを超える場合、パニックします。
753    pub fn new<T: Copy + Default + 'static>(name: String) -> Self {
754        Self::with_default_value(name, T::default())
755    }
756
757    /// デフォルト値を指定して新しく作成します。
758    /// `value` は `None` になります。
759    ///
760    /// # Panics
761    ///
762    /// Tが16KiBを超える場合、パニックします。
763    pub fn with_default_value<T: Copy + 'static>(name: String, default_value: T) -> Self {
764        assert!(
765            std::mem::size_of::<T>() <= 16 * 1024,
766            "FilterConfigData<T> size must be <= 16 KiB"
767        );
768        let size = std::mem::size_of::<T>();
769        let mut default_value_bytes = [0u8; 16 * 1024];
770        let default_value_ptr = (&raw const default_value).cast::<u8>();
771        default_value_bytes[..size]
772            .copy_from_slice(unsafe { std::slice::from_raw_parts(default_value_ptr, size) });
773
774        ErasedFilterConfigData {
775            name,
776            size,
777            value: None,
778            default_value: default_value_bytes,
779            variable_state: None,
780        }
781    }
782
783    /// デフォルト値のスライスを取得します。
784    pub fn default_value(&self) -> &[u8] {
785        &self.default_value[..self.size]
786    }
787
788    /// 型付きの汎用データに変換します。
789    ///
790    /// # Safety
791    ///
792    /// - `self` を消去する前の型Tと同じ型で呼び出す必要があります。
793    /// - Tのサイズが`self.size`と一致している必要があります。
794    /// - `self.value`が指すポインタが有効である必要があります。
795    /// - `self.default_value`はTとして有効なデータである必要があります。
796    pub unsafe fn into_typed<T: Copy + 'static>(self) -> FilterConfigData<T> {
797        let expected_size = std::mem::size_of::<T>();
798        assert_eq!(
799            self.size, expected_size,
800            "Size mismatch when converting ErasedFilterConfigData to FilterConfigData<T>"
801        );
802        let value = self
803            .value
804            .map(|v| NonNull::new(v.as_ptr().cast::<T>()).unwrap());
805        let default_value_ptr = self.default_value.as_ptr().cast::<T>();
806        let default_value = unsafe { *default_value_ptr };
807        FilterConfigData {
808            name: self.name,
809            value,
810            default_value,
811        }
812    }
813}
814
815/// 汎用データ。
816///
817/// [`VariableLengthFilterConfigData`]と違い、サイズが固定されています。
818///
819/// # Note
820///
821/// Tのサイズが変わったとき、値はデフォルト値にリセットされます。
822#[derive(Debug, Clone)]
823pub struct FilterConfigData<T: Copy + 'static> {
824    /// 設定名。
825    pub name: String,
826    /// 設定値。
827    pub value: Option<NonNull<T>>,
828    /// デフォルト値。
829    pub default_value: T,
830}
831
832impl<T: Copy + 'static> FilterConfigData<T> {
833    /// 型を消去した汎用データに変換します。
834    ///
835    /// # Panics
836    ///
837    /// Tが1024バイトを超える場合、パニックします。
838    pub fn erase_type(&self) -> ErasedFilterConfigData {
839        assert!(
840            std::mem::size_of::<T>() <= 16 * 1024,
841            "FilterConfigData<T> size must be <= 16 KiB"
842        );
843        let size = std::mem::size_of::<T>();
844        let mut default_value = [0u8; 16 * 1024];
845        let default_value_ptr = (&raw const self.default_value).cast::<u8>();
846        default_value[..size]
847            .copy_from_slice(unsafe { std::slice::from_raw_parts(default_value_ptr, size) });
848
849        ErasedFilterConfigData {
850            name: self.name.clone(),
851            size,
852            value: self
853                .value
854                .map(|v| NonNull::new(v.as_ptr().cast::<c_void>()).unwrap()),
855            default_value,
856            variable_state: None,
857        }
858    }
859}
860
861impl<T: Copy + 'static> From<FilterConfigData<T>> for ErasedFilterConfigData {
862    fn from(value: FilterConfigData<T>) -> Self {
863        value.erase_type()
864    }
865}
866
867/// 可変長の汎用データ。
868///
869/// [`FilterConfigData`]と違い、サイズを変更することができます。
870/// 必要に応じて、`bytemuck`などのクレートを使用して型変換してください。
871#[derive(Debug, Clone)]
872pub struct VariableLengthFilterConfigData {
873    /// 設定名。
874    pub name: String,
875    /// 設定値。
876    pub value: Option<NonNull<[u8]>>,
877    /// データのサイズ。
878    pub size: usize,
879    /// デフォルト値。
880    pub default_value: Vec<u8>,
881}
882
883impl VariableLengthFilterConfigData {
884    /// 新しく作成します。
885    ///
886    /// # Panics
887    ///
888    /// `size` が16KiBを超える場合、パニックします。
889    pub fn new(name: String, size: usize) -> Self {
890        Self::with_default_value(name, vec![0u8; size])
891    }
892
893    /// デフォルト値を指定して新しく作成します。
894    ///
895    /// # Panics
896    ///
897    /// `default_value.len()` が16KiBを超える場合、パニックします。
898    pub fn with_default_value(name: String, default_value: Vec<u8>) -> Self {
899        assert!(
900            default_value.len() <= 16 * 1024,
901            "VariableLengthFilterConfigData default_value size must be <= 16 KiB"
902        );
903        let size = default_value.len();
904        VariableLengthFilterConfigData {
905            name,
906            value: None,
907            size,
908            default_value,
909        }
910    }
911}
912impl From<VariableLengthFilterConfigData> for ErasedFilterConfigData {
913    fn from(value: VariableLengthFilterConfigData) -> Self {
914        let size = value.size;
915        let mut default_value = [0u8; 16 * 1024];
916        assert!(
917            size <= 16 * 1024,
918            "VariableLengthFilterConfigData size must be <= 16 KiB"
919        );
920        assert_eq!(
921            size,
922            value.default_value.len(),
923            "VariableLengthFilterConfigData size must match default_value length"
924        );
925        default_value[..size].copy_from_slice(&value.default_value);
926        let backing = match value.value {
927            Some(value) => VariableLengthDataBacking::Borrowed {
928                pointer: value.as_ptr().cast(),
929                size,
930            },
931            None => VariableLengthDataBacking::Owned(value.default_value),
932        };
933
934        ErasedFilterConfigData {
935            name: value.name,
936            size,
937            value: None,
938            default_value,
939            variable_state: Some(std::sync::Arc::new(parking_lot::RwLock::new(backing))),
940        }
941    }
942}
943
944/// グループ。
945#[derive(Debug, Clone)]
946pub struct FilterConfigGroup {
947    /// 設定名。
948    /// Noneの場合、グループの終端として扱われます。
949    pub name: Option<String>,
950
951    /// デフォルトで開いているかどうか。
952    pub opened: bool,
953}
954
955impl FilterConfigGroup {
956    /// グループの開始を表す設定を作成します。
957    pub fn start(name: String) -> Self {
958        Self::start_with_opened(name, true)
959    }
960
961    /// `opened` を指定してグループの開始を表す設定を作成します。
962    pub fn start_with_opened(name: String, opened: bool) -> Self {
963        FilterConfigGroup {
964            name: Some(name),
965            opened,
966        }
967    }
968
969    /// グループの終了を表す設定を作成します。
970    pub fn end() -> Self {
971        FilterConfigGroup {
972            name: None,
973            opened: false,
974        }
975    }
976}
977
978/// セパレーター。
979#[derive(Debug, Clone)]
980pub struct FilterConfigSeparator {
981    /// セパレーターに表示するテキスト。
982    pub name: String,
983}
984
985static HANDLES: std::sync::LazyLock<dashmap::DashMap<usize, parking_lot::RawRwLock>> =
986    std::sync::LazyLock::new(dashmap::DashMap::new);
987static OWNED_REFERENCES: std::sync::LazyLock<
988    std::sync::Arc<dashmap::DashMap<usize, std::sync::atomic::AtomicUsize>>,
989> = std::sync::LazyLock::new(|| std::sync::Arc::new(dashmap::DashMap::new()));
990
991#[derive(Debug)]
992enum VariableLengthDataBacking {
993    Borrowed { pointer: *mut u8, size: usize },
994    Owned(Vec<u8>),
995    Host(NonNull<aviutl2_sys::filter2::FILTER_ITEM_DATA>),
996}
997
998unsafe impl Send for VariableLengthDataBacking {}
999unsafe impl Sync for VariableLengthDataBacking {}
1000
1001impl VariableLengthDataBacking {
1002    fn as_slice(&self) -> &[u8] {
1003        match self {
1004            Self::Borrowed { pointer, size } => unsafe {
1005                std::slice::from_raw_parts(non_null_slice_pointer(*pointer, *size), *size)
1006            },
1007            Self::Owned(value) => value,
1008            Self::Host(raw) => {
1009                let raw = unsafe { raw.as_ref() };
1010                let size =
1011                    usize::try_from(raw.size).expect("FILTER_ITEM_DATA size must not be negative");
1012                assert!(size <= 16 * 1024, "FILTER_ITEM_DATA size must be <= 16 KiB");
1013                unsafe {
1014                    std::slice::from_raw_parts(non_null_slice_pointer(raw.value.cast(), size), size)
1015                }
1016            }
1017        }
1018    }
1019
1020    fn as_mut_slice(&mut self) -> &mut [u8] {
1021        match self {
1022            Self::Borrowed { pointer, size } => unsafe {
1023                std::slice::from_raw_parts_mut(non_null_slice_pointer(*pointer, *size), *size)
1024            },
1025            Self::Owned(value) => value,
1026            Self::Host(raw) => {
1027                let raw = unsafe { raw.as_mut() };
1028                let size =
1029                    usize::try_from(raw.size).expect("FILTER_ITEM_DATA size must not be negative");
1030                assert!(size <= 16 * 1024, "FILTER_ITEM_DATA size must be <= 16 KiB");
1031                unsafe {
1032                    std::slice::from_raw_parts_mut(
1033                        non_null_slice_pointer(raw.value.cast(), size),
1034                        size,
1035                    )
1036                }
1037            }
1038        }
1039    }
1040}
1041
1042fn non_null_slice_pointer(pointer: *mut u8, size: usize) -> *mut u8 {
1043    if size == 0 {
1044        NonNull::<u8>::dangling().as_ptr()
1045    } else {
1046        assert!(
1047            !pointer.is_null(),
1048            "filter config data pointer must not be null"
1049        );
1050        pointer
1051    }
1052}
1053
1054/// フィルタプラグインで可変長の汎用データ項目を使うためのハンドル。
1055#[derive(Debug, Clone)]
1056pub struct VariableLengthFilterConfigDataHandle {
1057    inner: std::sync::Arc<parking_lot::RwLock<VariableLengthDataBacking>>,
1058}
1059
1060impl VariableLengthFilterConfigDataHandle {
1061    #[doc(hidden)]
1062    pub fn __from_erased(erased: &ErasedFilterConfigData) -> Self {
1063        Self {
1064            inner: erased
1065                .variable_state
1066                .as_ref()
1067                .expect("expected variable-length filter config data")
1068                .clone(),
1069        }
1070    }
1071
1072    #[doc(hidden)]
1073    pub fn __new_owned(value: Vec<u8>) -> Self {
1074        assert!(
1075            value.len() <= 16 * 1024,
1076            "VariableLengthFilterConfigData size must be <= 16 KiB"
1077        );
1078        Self {
1079            inner: std::sync::Arc::new(parking_lot::RwLock::new(VariableLengthDataBacking::Owned(
1080                value,
1081            ))),
1082        }
1083    }
1084
1085    /// データを読み取るためのロックを取得する。
1086    pub fn read(&self) -> VariableLengthFilterConfigDataReadGuard<'_> {
1087        VariableLengthFilterConfigDataReadGuard {
1088            inner: self.inner.read(),
1089        }
1090    }
1091
1092    /// データを読み取るためのロックの取得を試みる。
1093    pub fn try_read(&self) -> Option<VariableLengthFilterConfigDataReadGuard<'_>> {
1094        self.inner
1095            .try_read()
1096            .map(|inner| VariableLengthFilterConfigDataReadGuard { inner })
1097    }
1098
1099    /// データを書き込むためのロックを取得する。
1100    pub fn write(&self) -> VariableLengthFilterConfigDataWriteGuard<'_> {
1101        VariableLengthFilterConfigDataWriteGuard {
1102            inner: self.inner.write(),
1103        }
1104    }
1105
1106    /// データを書き込むためのロックの取得を試みる。
1107    pub fn try_write(&self) -> Option<VariableLengthFilterConfigDataWriteGuard<'_>> {
1108        self.inner
1109            .try_write()
1110            .map(|inner| VariableLengthFilterConfigDataWriteGuard { inner })
1111    }
1112
1113    pub(crate) fn try_resize(
1114        &mut self,
1115        size: usize,
1116        resize: impl FnOnce(*mut c_void, i32),
1117    ) -> crate::filter::FilterProcResult<()> {
1118        if size > 16 * 1024 {
1119            return Err(crate::filter::FilterProcError::ValueOutOfRange);
1120        }
1121        let size =
1122            i32::try_from(size).map_err(|_| crate::filter::FilterProcError::ValueOutOfRange)?;
1123        let mut backing = self
1124            .inner
1125            .try_write()
1126            .ok_or(crate::filter::FilterProcError::FilterConfigDataLocked)?;
1127        let VariableLengthDataBacking::Host(raw) = &mut *backing else {
1128            return Err(crate::filter::FilterProcError::FilterConfigDataNotBound);
1129        };
1130        resize(raw.as_ptr().cast(), size);
1131        let backing = &mut *backing;
1132        match backing {
1133            VariableLengthDataBacking::Host(raw) => {
1134                unsafe { raw.as_mut() }.size = size;
1135            }
1136            VariableLengthDataBacking::Borrowed {
1137                pointer: _,
1138                size: s,
1139            } => {
1140                *s = size as usize;
1141            }
1142            VariableLengthDataBacking::Owned(vec) => {
1143                vec.resize(size as usize, 0);
1144            }
1145        }
1146        Ok(())
1147    }
1148}
1149
1150/// 可変長の汎用データを読み取るためのガード。
1151pub struct VariableLengthFilterConfigDataReadGuard<'handle> {
1152    inner: parking_lot::RwLockReadGuard<'handle, VariableLengthDataBacking>,
1153}
1154
1155impl std::ops::Deref for VariableLengthFilterConfigDataReadGuard<'_> {
1156    type Target = [u8];
1157
1158    fn deref(&self) -> &Self::Target {
1159        self.inner.as_slice()
1160    }
1161}
1162
1163/// 可変長の汎用データを書き込むためのガード。
1164pub struct VariableLengthFilterConfigDataWriteGuard<'handle> {
1165    inner: parking_lot::RwLockWriteGuard<'handle, VariableLengthDataBacking>,
1166}
1167
1168impl std::ops::Deref for VariableLengthFilterConfigDataWriteGuard<'_> {
1169    type Target = [u8];
1170
1171    fn deref(&self) -> &Self::Target {
1172        self.inner.as_slice()
1173    }
1174}
1175
1176impl std::ops::DerefMut for VariableLengthFilterConfigDataWriteGuard<'_> {
1177    fn deref_mut(&mut self) -> &mut Self::Target {
1178        self.inner.as_mut_slice()
1179    }
1180}
1181
1182/// フィルタプラグインで固定長の汎用データ項目を使うためのハンドル。
1183/// RwLockのような仕組みで安全にデータを扱うことができます。
1184#[derive(Debug)]
1185pub struct FilterConfigDataHandle<T: Copy> {
1186    pub(crate) inner: *mut T,
1187}
1188
1189unsafe impl<T: Send + Sync + Copy> Send for FilterConfigDataHandle<T> {}
1190unsafe impl<T: Send + Sync + Copy> Sync for FilterConfigDataHandle<T> {}
1191
1192impl<T: Copy> Clone for FilterConfigDataHandle<T> {
1193    fn clone(&self) -> Self {
1194        if !self.inner.is_null() {
1195            let addr = self.inner as usize;
1196            if let Some(entry) = OWNED_REFERENCES.get(&addr) {
1197                entry.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
1198            }
1199        }
1200        Self { inner: self.inner }
1201    }
1202}
1203impl<T: Copy> Drop for FilterConfigDataHandle<T> {
1204    fn drop(&mut self) {
1205        if !self.inner.is_null() {
1206            let addr = self.inner as usize;
1207            if let Some(entry) = OWNED_REFERENCES.get(&addr) {
1208                let prev = entry.fetch_sub(1, std::sync::atomic::Ordering::SeqCst);
1209                if prev == 1 {
1210                    unsafe {
1211                        let _boxed = Box::from_raw(self.inner);
1212                    }
1213                    // NOTE: ここでdropしないとdeadlockする
1214                    drop(entry);
1215                    OWNED_REFERENCES.remove(&addr);
1216                }
1217            }
1218        }
1219    }
1220}
1221
1222impl<T: Copy> FilterConfigDataHandle<T> {
1223    #[doc(hidden)]
1224    pub fn __generics_default_value() -> T
1225    where
1226        T: Default,
1227    {
1228        T::default()
1229    }
1230
1231    #[doc(hidden)]
1232    pub fn __from_erased(erased: &ErasedFilterConfigData) -> Self {
1233        Self {
1234            inner: erased.value.map_or(std::ptr::null_mut(), |v| v.as_ptr()) as *mut T,
1235        }
1236    }
1237
1238    #[doc(hidden)]
1239    pub fn __new_owned(value: T) -> Self {
1240        let boxed = Box::new(value);
1241        let pointer = Box::into_raw(boxed);
1242        let addr = pointer as *mut () as usize;
1243        OWNED_REFERENCES.insert(addr, std::sync::atomic::AtomicUsize::new(1));
1244        Self { inner: pointer }
1245    }
1246
1247    #[inline]
1248    fn inner_ptr(&self) -> Option<*mut T> {
1249        if self.inner.is_null() {
1250            None
1251        } else {
1252            Some(self.inner)
1253        }
1254    }
1255
1256    #[inline]
1257    fn inner_addr(&self) -> Option<usize> {
1258        self.inner_ptr().map(|inner| inner as *mut () as usize)
1259    }
1260
1261    /// データを読み取るためのロックを取得する。
1262    pub fn read<'handle>(&'handle self) -> FilterConfigDataReadGuard<'handle, T> {
1263        let inner = self
1264            .inner_ptr()
1265            .expect("FilterConfigDataHandle::read called with a null inner pointer");
1266        let addr = self
1267            .inner_addr()
1268            .expect("FilterConfigDataHandle::read called with a null inner pointer");
1269        let lock = HANDLES
1270            .entry(addr)
1271            .or_insert_with(|| parking_lot::RawRwLock::INIT);
1272        let lock = lock.value();
1273
1274        lock.lock_shared();
1275        FilterConfigDataReadGuard::new(inner)
1276    }
1277
1278    /// データを読み取るためのロックの取得を試みる。
1279    /// ロックが取得できなかった場合は `None` を返します。
1280    pub fn try_read<'handle>(&'handle self) -> Option<FilterConfigDataReadGuard<'handle, T>> {
1281        let inner = self.inner_ptr()?;
1282        let addr = self.inner_addr()?;
1283        let lock = HANDLES
1284            .entry(addr)
1285            .or_insert_with(|| parking_lot::RawRwLock::INIT);
1286        let lock = lock.value();
1287
1288        if lock.try_lock_shared() {
1289            Some(FilterConfigDataReadGuard::new(inner))
1290        } else {
1291            None
1292        }
1293    }
1294
1295    /// データを書き込むためのロックを取得する。
1296    pub fn write<'handle>(&'handle self) -> FilterConfigDataWriteGuard<'handle, T> {
1297        let addr = self.inner as *mut () as usize;
1298        let lock = HANDLES
1299            .entry(addr)
1300            .or_insert_with(|| parking_lot::RawRwLock::INIT);
1301        let lock = lock.value();
1302        lock.lock_exclusive();
1303        FilterConfigDataWriteGuard::new(self.inner)
1304    }
1305
1306    /// データを書き込むためのロックの取得を試みる。
1307    /// ロックが取得できなかった場合は `None` を返します。
1308    pub fn try_write<'handle>(&'handle self) -> Option<FilterConfigDataWriteGuard<'handle, T>> {
1309        let addr = self.inner as *mut () as usize;
1310        let lock = HANDLES
1311            .entry(addr)
1312            .or_insert_with(|| parking_lot::RawRwLock::INIT);
1313        let lock = lock.value();
1314        if lock.try_lock_exclusive() {
1315            Some(FilterConfigDataWriteGuard::new(self.inner))
1316        } else {
1317            None
1318        }
1319    }
1320
1321    /// 内部のポインタを取得する。
1322    ///
1323    /// # Warning
1324    ///
1325    /// このポインタを直接操作するとデータ競合が発生する可能性があります。
1326    pub fn as_ptr(&self) -> *mut T {
1327        self.inner
1328    }
1329}
1330
1331#[doc(hidden)]
1332pub trait FilterConfigDataHandleType: Sized {
1333    type Value;
1334
1335    fn __default_value() -> Self::Value
1336    where
1337        Self::Value: Default,
1338    {
1339        Self::Value::default()
1340    }
1341
1342    fn __to_erased(name: String, value: Self::Value) -> ErasedFilterConfigData;
1343    fn __from_erased_data(data: &ErasedFilterConfigData) -> Self;
1344    fn __new_owned_data(value: Self::Value) -> Self;
1345}
1346
1347impl<T: Copy + 'static> FilterConfigDataHandleType for FilterConfigDataHandle<T> {
1348    type Value = T;
1349
1350    fn __to_erased(name: String, value: Self::Value) -> ErasedFilterConfigData {
1351        ErasedFilterConfigData::with_default_value(name, value)
1352    }
1353
1354    fn __from_erased_data(data: &ErasedFilterConfigData) -> Self {
1355        Self::__from_erased(data)
1356    }
1357
1358    fn __new_owned_data(value: Self::Value) -> Self {
1359        Self::__new_owned(value)
1360    }
1361}
1362
1363impl FilterConfigDataHandleType for VariableLengthFilterConfigDataHandle {
1364    type Value = Vec<u8>;
1365
1366    fn __to_erased(name: String, value: Self::Value) -> ErasedFilterConfigData {
1367        VariableLengthFilterConfigData::with_default_value(name, value).into()
1368    }
1369
1370    fn __from_erased_data(data: &ErasedFilterConfigData) -> Self {
1371        Self::__from_erased(data)
1372    }
1373
1374    fn __new_owned_data(value: Self::Value) -> Self {
1375        Self::__new_owned(value)
1376    }
1377}
1378
1379/// トラックバーグループ。
1380///
1381/// # Note
1382///
1383/// SDKではトラックグループのトラックは同じFILTER_ITEM_TRACKへのポインタを渡すことが想定されていますが、
1384/// 実装上の都合で同じ内容の別のFILTER_ITEM_TRACKへのポインタを渡すようになっています。
1385/// (これをちゃんとやろうとするとかなり複雑になるため...)
1386#[derive(Debug, Clone)]
1387pub struct FilterConfigTrackGroup {
1388    /// グループ名。
1389    pub name: String,
1390    /// トラックバーのリスト。
1391    pub tracks: Vec<FilterConfigTrack>,
1392}
1393
1394#[doc(hidden)]
1395#[expect(private_bounds)]
1396pub fn __string_to_pathbuf_or_option_pathbuf<T: StringToPathBufOrOptionPathBuf>(s: &str) -> T {
1397    T::__string_to_pathbuf_or_option_pathbuf(s)
1398}
1399
1400trait StringToPathBufOrOptionPathBuf: Sized {
1401    fn __string_to_pathbuf_or_option_pathbuf(s: &str) -> Self;
1402}
1403impl StringToPathBufOrOptionPathBuf for std::path::PathBuf {
1404    fn __string_to_pathbuf_or_option_pathbuf(s: &str) -> Self {
1405        std::path::PathBuf::from(s)
1406    }
1407}
1408impl StringToPathBufOrOptionPathBuf for Option<std::path::PathBuf> {
1409    fn __string_to_pathbuf_or_option_pathbuf(s: &str) -> Self {
1410        if s.is_empty() {
1411            None
1412        } else {
1413            Some(std::path::PathBuf::from(s))
1414        }
1415    }
1416}
1417
1418/// フィルタプラグインのデータを読み取るためのガード。
1419pub struct FilterConfigDataReadGuard<'handle, T: Copy> {
1420    pub(crate) inner: *mut T,
1421    _handle: std::marker::PhantomData<&'handle FilterConfigDataHandle<T>>,
1422}
1423unsafe impl<T: Send + Sync + Copy> Send for FilterConfigDataReadGuard<'_, T> {}
1424unsafe impl<T: Send + Sync + Copy> Sync for FilterConfigDataReadGuard<'_, T> {}
1425impl<T: Copy> FilterConfigDataReadGuard<'_, T> {
1426    fn new<'handle>(inner: *mut T) -> FilterConfigDataReadGuard<'handle, T> {
1427        FilterConfigDataReadGuard {
1428            inner,
1429            _handle: std::marker::PhantomData,
1430        }
1431    }
1432}
1433impl<T: Copy> Drop for FilterConfigDataReadGuard<'_, T> {
1434    fn drop(&mut self) {
1435        let addr = self.inner as *mut () as usize;
1436        if let Some(entry) = HANDLES.get(&addr) {
1437            let lock = entry.value();
1438            unsafe { lock.unlock_shared() };
1439        }
1440    }
1441}
1442impl<T: Copy> std::convert::AsRef<T> for FilterConfigDataReadGuard<'_, T> {
1443    fn as_ref(&self) -> &T {
1444        unsafe { &*self.inner }
1445    }
1446}
1447impl<T: Copy> std::ops::Deref for FilterConfigDataReadGuard<'_, T> {
1448    type Target = T;
1449
1450    fn deref(&self) -> &Self::Target {
1451        self.as_ref()
1452    }
1453}
1454
1455/// フィルタプラグインのデータを書き込むためのガード。
1456pub struct FilterConfigDataWriteGuard<'handle, T: Copy> {
1457    pub(crate) inner: *mut T,
1458    _handle: std::marker::PhantomData<&'handle FilterConfigDataHandle<T>>,
1459}
1460
1461unsafe impl<T: Send + Sync + Copy> Send for FilterConfigDataWriteGuard<'_, T> {}
1462unsafe impl<T: Send + Sync + Copy> Sync for FilterConfigDataWriteGuard<'_, T> {}
1463impl<T: Copy> FilterConfigDataWriteGuard<'_, T> {
1464    fn new<'handle>(inner: *mut T) -> FilterConfigDataWriteGuard<'handle, T> {
1465        FilterConfigDataWriteGuard {
1466            inner,
1467            _handle: std::marker::PhantomData,
1468        }
1469    }
1470}
1471impl<T: Copy> Drop for FilterConfigDataWriteGuard<'_, T> {
1472    fn drop(&mut self) {
1473        let addr = self.inner as *mut () as usize;
1474        if let Some(entry) = HANDLES.get(&addr) {
1475            let lock = entry.value();
1476            unsafe { lock.unlock_exclusive() };
1477        }
1478    }
1479}
1480impl<T: Copy> std::convert::AsMut<T> for FilterConfigDataWriteGuard<'_, T> {
1481    fn as_mut(&mut self) -> &mut T {
1482        unsafe { &mut *self.inner }
1483    }
1484}
1485impl<T: Copy> std::ops::Deref for FilterConfigDataWriteGuard<'_, T> {
1486    type Target = T;
1487    fn deref(&self) -> &Self::Target {
1488        unsafe { &*self.inner }
1489    }
1490}
1491impl<T: Copy> std::ops::DerefMut for FilterConfigDataWriteGuard<'_, T> {
1492    fn deref_mut(&mut self) -> &mut Self::Target {
1493        self.as_mut()
1494    }
1495}
1496
1497/// 非表示条件の演算子。
1498#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1499pub enum FilterConfigHideRuleOperator {
1500    /// 等しい(`==`)。
1501    Equal,
1502    /// 等しくない(`!=`)。
1503    NotEqual,
1504    /// より大きい(`>`)。
1505    Greater,
1506    /// より小さい(`<`)。
1507    Less,
1508}
1509
1510impl From<FilterConfigHideRuleOperator> for aviutl2_sys::filter2::FILTER_ITEM_HIDE_RULE_OPERATOR {
1511    fn from(value: FilterConfigHideRuleOperator) -> Self {
1512        match value {
1513            FilterConfigHideRuleOperator::Equal => {
1514                aviutl2_sys::filter2::FILTER_ITEM_HIDE_RULE_OPERATOR::EQUAL
1515            }
1516            FilterConfigHideRuleOperator::NotEqual => {
1517                aviutl2_sys::filter2::FILTER_ITEM_HIDE_RULE_OPERATOR::NOT_EQUAL
1518            }
1519            FilterConfigHideRuleOperator::Greater => {
1520                aviutl2_sys::filter2::FILTER_ITEM_HIDE_RULE_OPERATOR::GREATER
1521            }
1522            FilterConfigHideRuleOperator::Less => {
1523                aviutl2_sys::filter2::FILTER_ITEM_HIDE_RULE_OPERATOR::LESS
1524            }
1525        }
1526    }
1527}
1528
1529/// 非表示条件。
1530#[derive(Debug, Clone)]
1531pub struct FilterConfigHideRule {
1532    /// 非表示にする設定名。
1533    ///
1534    /// # Note
1535    ///
1536    /// - 設定値を持たない設定(グループ、セパレーターなど)には対応していません。
1537    pub name: String,
1538    /// 非表示にする条件の設定名。
1539    /// Noneの場合は常に非表示になります。
1540    ///
1541    /// # Note
1542    ///
1543    /// - 以下の設定タイプのみに対応しています:
1544    ///   - [`FilterConfigItem::Check`]:オンの場合は`1`、オフの場合は`0`として扱われます。
1545    ///   - [`FilterConfigItem::CheckSection`]:セクションごとに変化する場合は`2`、セクションが変化しない場合は[`FilterConfigItem::Check`]と同じ扱いになります。
1546    ///   - [`FilterConfigItem::Select`]:設定値がそのまま扱われます。
1547    ///   - [`FilterConfigItem::File`]、[`FilterConfigItem::Folder`]:設定されている場合は`1`、設定されていない場合は`0`として扱われます。
1548    /// - `"filter"`を指定した場合はフィルタオブジェクトかどうかを判定します。
1549    pub condition_name: Option<String>,
1550    /// 非表示にする条件の演算子。
1551    pub condition_operator: FilterConfigHideRuleOperator,
1552    /// 非表示にする条件の値。
1553    pub condition_value: i32,
1554}
1555
1556#[cfg(test)]
1557mod tests {
1558    use super::*;
1559
1560    #[test]
1561    fn value_less_filter_config_items_are_no_op_when_applying_raw_values() {
1562        let leak_manager = LeakManager::new();
1563        let mut items = [
1564            FilterConfigItem::Separator(FilterConfigSeparator {
1565                name: "Separator".to_string(),
1566            }),
1567            FilterConfigItem::HideRule(FilterConfigHideRule {
1568                name: "Target".to_string(),
1569                condition_name: None,
1570                condition_operator: FilterConfigHideRuleOperator::Equal,
1571                condition_value: 0,
1572            }),
1573        ];
1574
1575        for item in &mut items {
1576            let raw = item.to_raw(&leak_manager);
1577            assert!(!unsafe { item.should_apply_from_raw(&raw) });
1578            unsafe { item.apply_from_raw(&raw) };
1579        }
1580    }
1581
1582    #[test]
1583    fn filter_config_data_handle_reads_initial_value() {
1584        let handle = FilterConfigDataHandle::<u32>::__new_owned(42);
1585        let read_guard = handle.read();
1586        assert_eq!(*read_guard, 42);
1587    }
1588
1589    #[test]
1590    fn filter_config_data_handle_writes_and_reads_updated_value() {
1591        let handle = FilterConfigDataHandle::<u32>::__new_owned(42);
1592        {
1593            let mut write_guard = handle.write();
1594            *write_guard = 100;
1595        }
1596        let read_guard = handle.read();
1597        assert_eq!(*read_guard, 100);
1598    }
1599
1600    #[test]
1601    fn filter_config_data_handle_try_read_fails_when_locked_for_write() {
1602        let handle = FilterConfigDataHandle::<u32>::__new_owned(42);
1603        let _write_guard = handle.write();
1604        let try_read_guard = handle.try_read();
1605        assert!(try_read_guard.is_none());
1606    }
1607
1608    #[test]
1609    fn filter_config_data_handle_try_write_fails_when_locked_for_read() {
1610        let handle = FilterConfigDataHandle::<u32>::__new_owned(42);
1611        let _read_guard = handle.read();
1612        let try_write_guard = handle.try_write();
1613        assert!(try_write_guard.is_none());
1614    }
1615
1616    #[test]
1617    fn filter_config_data_handle_clone_shares_state() {
1618        let handle = FilterConfigDataHandle::<u32>::__new_owned(42);
1619        let cloned_handle = handle.clone();
1620        {
1621            let mut write_guard = handle.write();
1622            *write_guard = 100;
1623        }
1624        let read_guard = cloned_handle.read();
1625        assert_eq!(*read_guard, 100);
1626    }
1627
1628    #[test]
1629    fn filter_config_data_handle_never_drops_data_for_borrowed() {
1630        let mut data =
1631            crate::filter::ErasedFilterConfigData::with_default_value("test".to_string(), 42);
1632        let data_ptr = Box::into_raw(Box::new(42u32));
1633        data.value = Some(std::ptr::NonNull::new(data_ptr as _).unwrap());
1634        let handle = FilterConfigDataHandle::<u32>::__from_erased(&data);
1635        drop(handle);
1636
1637        assert_eq!(unsafe { *data_ptr }, 42);
1638    }
1639
1640    #[test]
1641    fn filter_config_data_handle_reads_value_from_erased_data() {
1642        let boxed = Box::new(77u32);
1643        let ptr = std::ptr::NonNull::from(boxed.as_ref());
1644        let data = crate::filter::FilterConfigData {
1645            name: "test".to_string(),
1646            value: Some(ptr),
1647            default_value: 0,
1648        };
1649        let erased = data.erase_type();
1650        let handle = FilterConfigDataHandle::<u32>::__from_erased(&erased);
1651        let read_guard = handle.read();
1652
1653        assert_eq!(*read_guard, 77);
1654        assert_eq!(erased.value.unwrap().as_ptr() as *mut u32, ptr.as_ptr());
1655
1656        drop(read_guard);
1657        drop(handle);
1658        drop(boxed);
1659    }
1660
1661    #[test]
1662    fn variable_length_filter_config_data_handle_reads_and_writes_owned_data() {
1663        let handle = VariableLengthFilterConfigDataHandle::__new_owned(vec![1, 2, 3]);
1664        let cloned = handle.clone();
1665
1666        assert_eq!(&*handle.read(), &[1, 2, 3]);
1667        {
1668            let mut value = cloned.write();
1669            value[1] = 9;
1670        }
1671        assert_eq!(&*handle.read(), &[1, 9, 3]);
1672    }
1673
1674    #[test]
1675    fn variable_length_filter_config_data_resize_updates_all_clones() {
1676        let mut old_value = vec![1u8, 2, 3];
1677        let mut new_value = vec![4u8, 5, 6, 7];
1678        let mut raw = aviutl2_sys::filter2::FILTER_ITEM_DATA {
1679            r#type: std::ptr::null(),
1680            name: std::ptr::null(),
1681            value: old_value.as_mut_ptr().cast(),
1682            size: old_value.len() as i32,
1683            default_value: [MaybeUninit::new(0); 16 * 1024],
1684        };
1685        let mut handle = VariableLengthFilterConfigDataHandle {
1686            inner: std::sync::Arc::new(parking_lot::RwLock::new(VariableLengthDataBacking::Host(
1687                NonNull::from(&mut raw),
1688            ))),
1689        };
1690        let cloned = handle.clone();
1691
1692        handle
1693            .try_resize(new_value.len(), |raw, size| {
1694                let raw = unsafe { &mut *raw.cast::<aviutl2_sys::filter2::FILTER_ITEM_DATA>() };
1695                raw.value = new_value.as_mut_ptr().cast();
1696                raw.size = size;
1697            })
1698            .unwrap();
1699
1700        assert_eq!(&*cloned.read(), &[4, 5, 6, 7]);
1701    }
1702
1703    #[test]
1704    fn variable_length_filter_config_data_rejects_oversized_resize() {
1705        let mut handle = VariableLengthFilterConfigDataHandle::__new_owned(Vec::new());
1706
1707        let result = handle.try_resize(16 * 1024 + 1, |_, _| panic!("resize must not be called"));
1708
1709        assert!(matches!(
1710            result,
1711            Err(crate::filter::FilterProcError::ValueOutOfRange)
1712        ));
1713    }
1714}