rs_vips/
voption.rs

1// (c) Copyright 2025 mrdkprj
2use crate::{
3    bindings::{
4        g_log, g_object_get_property, g_object_ref, g_object_set_property, g_object_unref,
5        g_type_check_instance_is_a, g_value_dup_boxed, g_value_get_boolean, g_value_get_double,
6        g_value_get_int, g_value_get_object, g_value_get_string, g_value_init, g_value_set_boolean,
7        g_value_set_boxed, g_value_set_double, g_value_set_enum, g_value_set_int,
8        g_value_set_object, g_value_set_string, g_value_set_uint64, g_value_unset,
9        vips_array_double_get_type, vips_array_image_get_type, vips_array_int_get_type,
10        vips_blob_get_type, vips_cache_operation_buildp, vips_enum_from_nick, vips_error_buffer,
11        vips_error_clear, vips_image_get_type, vips_interpolate_get_type, vips_object_get_argument,
12        vips_object_set_from_string, vips_object_unref_outputs, vips_operation_new,
13        vips_source_get_type, vips_target_get_type, vips_value_get_array_double,
14        vips_value_get_array_image, vips_value_set_array_double, vips_value_set_array_image,
15        vips_value_set_array_int, GLogLevelFlags_G_LOG_LEVEL_WARNING, GParamSpec, GTypeInstance,
16        GValue, VipsArgumentClass, VipsArgumentInstance, VipsBlob, VipsImage, VipsObject,
17        VipsOperation,
18    },
19    utils::{
20        get_g_type, new_c_string, G_TYPE_BOOLEAN, G_TYPE_DOUBLE, G_TYPE_INT, G_TYPE_STRING,
21        G_TYPE_UINT64,
22    },
23};
24use std::{mem::MaybeUninit, os::raw::c_void};
25
26/// Runs the vips operation with options
27pub fn call(operation: &str, option: VOption) -> std::os::raw::c_int {
28    call_option_string(
29        operation,
30        "",
31        option,
32    )
33}
34
35/// Runs the vips operation with options
36pub fn call_option_string(
37    operation: &str,
38    option_string: &str,
39    option: VOption,
40) -> std::os::raw::c_int {
41    let operation = new_c_string(operation).unwrap();
42    let option_string = new_c_string(option_string).unwrap();
43    call_option_string_(
44        operation.as_ptr(),
45        option_string.as_ptr() as _,
46        option,
47    )
48}
49
50pub(crate) fn call_option_string_(
51    operation: *const i8,
52    option_string: *mut i8,
53    option: VOption,
54) -> std::os::raw::c_int {
55    unsafe {
56        let mut vips_operation = vips_operation_new(operation);
57
58        if !option_string.is_null()
59            && vips_object_set_from_string(
60                vips_operation as _,
61                option_string,
62            ) < 0
63        {
64            vips_object_unref_outputs(vips_operation as _);
65            g_object_unref(vips_operation as _);
66            return 1;
67        }
68
69        set_opreration(
70            vips_operation,
71            &option,
72        );
73
74        let result = vips_cache_operation_buildp(&mut vips_operation);
75
76        if result < 0 {
77            vips_object_unref_outputs(vips_operation as _);
78            g_object_unref(vips_operation as _);
79            return 1;
80        }
81
82        get_operation(
83            vips_operation,
84            option,
85        );
86
87        g_object_unref(vips_operation as _);
88
89        result
90    }
91}
92
93enum VipsValue<'a> {
94    Bool(bool),
95    MutBool(&'a mut bool),
96    Int(i32),
97    MutInt(&'a mut i32),
98    Uint(u64),
99    Double(f64),
100    MutDouble(&'a mut f64),
101    Str(&'a str),
102    Image(&'a crate::VipsImage),
103    MutImage(&'a mut crate::VipsImage),
104    IntArray(&'a [i32]),
105    DoubleArray(&'a [f64]),
106    DoubleVec(Vec<f64>),
107    MutDoubleArray(&'a mut Vec<f64>),
108    ImageArray(&'a [crate::VipsImage]),
109    Blob(&'a crate::region::VipsBlob),
110    MutBlob(&'a mut crate::region::VipsBlob),
111    Target(&'a crate::connection::VipsTarget),
112    Source(&'a crate::connection::VipsSource),
113    Interpolate(&'a crate::interpolate::VipsInterpolate),
114}
115
116struct Pair<'a> {
117    input: bool,
118    name: String,
119    value: VipsValue<'a>,
120}
121
122impl<'a> Pair<'a> {
123    fn input(name: &str, value: VipsValue<'a>) -> Self {
124        Self {
125            input: true,
126            name: name.to_string(),
127            value,
128        }
129    }
130
131    fn output(name: &str, value: VipsValue<'a>) -> Self {
132        Self {
133            input: false,
134            name: name.to_string(),
135            value,
136        }
137    }
138}
139
140/// VOption, a list of name-value pairs
141#[derive(Default)]
142pub struct VOption<'a> {
143    options: Vec<Pair<'a>>,
144}
145
146impl<'a> VOption<'a> {
147    pub fn new() -> Self {
148        Self {
149            options: Vec::new(),
150        }
151    }
152}
153
154fn get_operation(vips_operation: *mut VipsOperation, option: VOption) {
155    unsafe {
156        for opt in option.options {
157            if opt.input {
158                continue;
159            }
160
161            let mut gvalue = MaybeUninit::<GValue>::zeroed();
162            let gvalue_ptr = gvalue.as_mut_ptr();
163            let name = new_c_string(opt.name).unwrap();
164
165            match opt.value {
166                VipsValue::MutBool(out) => {
167                    g_value_init(
168                        gvalue_ptr,
169                        get_g_type(G_TYPE_BOOLEAN),
170                    );
171                    g_object_get_property(
172                        vips_operation.cast(),
173                        name.as_ptr(),
174                        gvalue_ptr,
175                    );
176                    *out = g_value_get_boolean(gvalue_ptr) != 0;
177                }
178                VipsValue::MutInt(out) => {
179                    g_value_init(
180                        gvalue_ptr,
181                        get_g_type(G_TYPE_INT),
182                    );
183                    g_object_get_property(
184                        vips_operation.cast(),
185                        name.as_ptr(),
186                        gvalue_ptr,
187                    );
188                    *out = g_value_get_int(gvalue_ptr);
189                }
190                VipsValue::MutDouble(out) => {
191                    g_value_init(
192                        gvalue_ptr,
193                        get_g_type(G_TYPE_DOUBLE),
194                    );
195                    g_object_get_property(
196                        vips_operation.cast(),
197                        name.as_ptr(),
198                        gvalue_ptr,
199                    );
200                    *out = g_value_get_double(gvalue_ptr);
201                }
202                VipsValue::MutDoubleArray(out) => {
203                    g_value_init(
204                        gvalue_ptr,
205                        vips_array_double_get_type(),
206                    );
207                    g_object_get_property(
208                        vips_operation.cast(),
209                        name.as_ptr(),
210                        gvalue_ptr,
211                    );
212                    let mut len: i32 = 0;
213                    let array = vips_value_get_array_double(
214                        gvalue_ptr,
215                        &mut len,
216                    );
217                    let result = std::slice::from_raw_parts(
218                        array,
219                        len as usize,
220                    );
221                    out.extend(result);
222                }
223                VipsValue::MutBlob(out) => {
224                    g_value_init(
225                        gvalue_ptr,
226                        vips_blob_get_type(),
227                    );
228                    g_object_get_property(
229                        vips_operation.cast(),
230                        name.as_ptr(),
231                        gvalue_ptr,
232                    );
233                    let out_blob: *mut VipsBlob = g_value_dup_boxed(gvalue_ptr).cast();
234                    out.ctx = out_blob;
235                }
236                VipsValue::MutImage(out) => {
237                    g_value_init(
238                        gvalue_ptr,
239                        vips_image_get_type(),
240                    );
241                    g_object_get_property(
242                        vips_operation.cast(),
243                        name.as_ptr(),
244                        gvalue_ptr,
245                    );
246                    let out_image: *mut VipsImage = g_value_get_object(gvalue_ptr).cast();
247                    out.ctx = out_image;
248                }
249                _ => {}
250            }
251            g_value_unset(gvalue_ptr);
252        }
253    }
254}
255
256fn set_opreration(operation: *mut VipsOperation, option: &VOption) {
257    unsafe {
258        for pair in &option.options {
259            if !pair.input {
260                continue;
261            }
262
263            let mut gvalue = MaybeUninit::<GValue>::zeroed();
264            let gvalue_ptr = gvalue.as_mut_ptr();
265
266            match pair.value {
267                VipsValue::Bool(value) => {
268                    g_value_init(
269                        gvalue_ptr,
270                        get_g_type(G_TYPE_BOOLEAN),
271                    );
272                    g_value_set_boolean(
273                        gvalue_ptr,
274                        value.into(),
275                    );
276                }
277                VipsValue::Int(value) => {
278                    g_value_init(
279                        gvalue_ptr,
280                        get_g_type(G_TYPE_INT),
281                    );
282                    g_value_set_int(
283                        gvalue_ptr,
284                        value,
285                    );
286                }
287                VipsValue::Uint(value) => {
288                    g_value_init(
289                        gvalue_ptr,
290                        get_g_type(G_TYPE_UINT64),
291                    );
292                    g_value_set_uint64(
293                        gvalue_ptr,
294                        value,
295                    );
296                }
297                VipsValue::Double(value) => {
298                    g_value_init(
299                        gvalue_ptr,
300                        get_g_type(G_TYPE_DOUBLE),
301                    );
302                    g_value_set_double(
303                        gvalue_ptr,
304                        value,
305                    );
306                }
307                VipsValue::Str(value) => {
308                    let str = new_c_string(value).unwrap();
309                    g_value_init(
310                        gvalue_ptr,
311                        get_g_type(G_TYPE_STRING),
312                    );
313                    g_value_set_string(
314                        gvalue_ptr,
315                        str.as_ptr(),
316                    );
317                }
318                VipsValue::IntArray(value) => {
319                    g_value_init(
320                        gvalue_ptr,
321                        vips_array_int_get_type(),
322                    );
323                    vips_value_set_array_int(
324                        gvalue_ptr,
325                        value.as_ptr(),
326                        value.len() as _,
327                    );
328                }
329                VipsValue::DoubleArray(value) => {
330                    g_value_init(
331                        gvalue_ptr,
332                        vips_array_double_get_type(),
333                    );
334                    vips_value_set_array_double(
335                        gvalue_ptr,
336                        value.as_ptr(),
337                        value.len() as _,
338                    );
339                }
340                VipsValue::Image(value) => {
341                    g_value_init(
342                        gvalue_ptr,
343                        vips_image_get_type(),
344                    );
345                    g_value_set_object(
346                        gvalue_ptr,
347                        value.ctx as *mut c_void,
348                    );
349                }
350                VipsValue::ImageArray(value) => {
351                    g_value_init(
352                        gvalue_ptr,
353                        vips_array_image_get_type(),
354                    );
355                    vips_value_set_array_image(
356                        gvalue_ptr,
357                        value.len() as _,
358                    );
359                    let array = vips_value_get_array_image(
360                        gvalue_ptr,
361                        &mut 0,
362                    );
363                    let array = std::slice::from_raw_parts_mut(
364                        array,
365                        value.len() as _,
366                    );
367                    for i in 0..value.len() {
368                        g_object_ref(value[i].ctx as _);
369                        array[i] = value[i].ctx;
370                    }
371                }
372                VipsValue::Blob(value) => {
373                    g_value_init(
374                        gvalue_ptr,
375                        vips_blob_get_type(),
376                    );
377                    g_value_set_boxed(
378                        gvalue_ptr,
379                        value.ctx as *const c_void,
380                    );
381                }
382                VipsValue::Source(value) => {
383                    g_value_init(
384                        gvalue_ptr,
385                        vips_source_get_type(),
386                    );
387                    g_value_set_object(
388                        gvalue_ptr,
389                        value.ctx as *mut c_void,
390                    );
391                }
392                VipsValue::Target(value) => {
393                    g_value_init(
394                        gvalue_ptr,
395                        vips_target_get_type(),
396                    );
397                    g_value_set_object(
398                        gvalue_ptr,
399                        value.ctx as *mut c_void,
400                    );
401                }
402                VipsValue::Interpolate(value) => {
403                    g_value_init(
404                        gvalue_ptr,
405                        vips_interpolate_get_type(),
406                    );
407                    g_value_set_object(
408                        gvalue_ptr,
409                        value.ctx as *mut c_void,
410                    );
411                }
412                _ => {}
413            }
414
415            set_property(
416                operation,
417                &pair.name,
418                gvalue_ptr,
419            );
420            g_value_unset(gvalue_ptr);
421        }
422    }
423}
424
425fn set_property(operation: *mut VipsOperation, name: &str, value: *mut GValue) {
426    unsafe {
427        let object: *mut VipsObject = operation.cast();
428        let name = new_c_string(name).unwrap();
429
430        let mut pspec: *mut GParamSpec = std::ptr::null_mut();
431        let mut argument_class: *mut VipsArgumentClass = std::ptr::null_mut();
432        let mut argument_instance: *mut VipsArgumentInstance = std::ptr::null_mut();
433        if vips_object_get_argument(
434            object,
435            name.as_ptr(),
436            &mut pspec,
437            &mut argument_class,
438            &mut argument_instance,
439        ) < 0
440        {
441            g_warning();
442            vips_error_clear();
443            return;
444        }
445
446        let is_param_spec_enum = g_type_check_instance_is_a(
447            pspec as *mut GTypeInstance,
448            get_g_type("GParamEnum"),
449        ) != 0;
450
451        if is_param_spec_enum && (*value).g_type == get_g_type(G_TYPE_STRING) {
452            let pspec_type = (*pspec).value_type;
453            let enum_value = vips_enum_from_nick(
454                (*object).nickname,
455                pspec_type,
456                g_value_get_string(value),
457            );
458            if enum_value < 0 {
459                g_warning();
460                vips_error_clear();
461                return;
462            }
463
464            let mut gvalue = MaybeUninit::<GValue>::zeroed();
465            let value2 = gvalue.as_mut_ptr();
466            g_value_init(
467                value2,
468                pspec_type,
469            );
470            g_value_set_enum(
471                value2,
472                enum_value,
473            );
474            g_object_set_property(
475                object.cast(),
476                name.as_ptr(),
477                value2,
478            );
479            g_value_unset(value2);
480        } else {
481            g_object_set_property(
482                object.cast(),
483                name.as_ptr(),
484                value,
485            );
486        }
487    }
488}
489
490fn g_warning() {
491    let domain = new_c_string("GLib-GObject").unwrap();
492    let format = new_c_string("%s").unwrap();
493    unsafe {
494        g_log(
495            domain.as_ptr(),
496            GLogLevelFlags_G_LOG_LEVEL_WARNING,
497            format.as_ptr(),
498            vips_error_buffer(),
499        )
500    };
501}
502
503/// Set the value of a name-value pair of VOption
504pub trait Setter<'a, T> {
505    fn set(self, name: &str, value: T) -> VOption<'a>;
506    fn add(&mut self, name: &str, value: T);
507}
508
509// input bool
510impl<'a> Setter<'a, bool> for VOption<'a> {
511    fn set(mut self, name: &str, value: bool) -> VOption<'a> {
512        self.options
513            .push(
514                Pair::input(
515                    name,
516                    VipsValue::Bool(value),
517                ),
518            );
519        self
520    }
521    fn add(&mut self, name: &str, value: bool) {
522        self.options
523            .push(
524                Pair::input(
525                    name,
526                    VipsValue::Bool(value),
527                ),
528            );
529    }
530}
531
532// input i32
533impl<'a> Setter<'a, i32> for VOption<'a> {
534    fn set(mut self, name: &str, value: i32) -> VOption<'a> {
535        self.options
536            .push(
537                Pair::input(
538                    name,
539                    VipsValue::Int(value),
540                ),
541            );
542        self
543    }
544    fn add(&mut self, name: &str, value: i32) {
545        self.options
546            .push(
547                Pair::input(
548                    name,
549                    VipsValue::Int(value),
550                ),
551            );
552    }
553}
554
555// input u64
556impl<'a> Setter<'a, u64> for VOption<'a> {
557    fn set(mut self, name: &str, value: u64) -> VOption<'a> {
558        self.options
559            .push(
560                Pair::input(
561                    name,
562                    VipsValue::Uint(value),
563                ),
564            );
565        self
566    }
567    fn add(&mut self, name: &str, value: u64) {
568        self.options
569            .push(
570                Pair::input(
571                    name,
572                    VipsValue::Uint(value),
573                ),
574            );
575    }
576}
577
578// input f64
579impl<'a> Setter<'a, f64> for VOption<'a> {
580    fn set(mut self, name: &str, value: f64) -> VOption<'a> {
581        self.options
582            .push(
583                Pair::input(
584                    name,
585                    VipsValue::Double(value),
586                ),
587            );
588        self
589    }
590    fn add(&mut self, name: &str, value: f64) {
591        self.options
592            .push(
593                Pair::input(
594                    name,
595                    VipsValue::Double(value),
596                ),
597            );
598    }
599}
600
601// input &str
602impl<'a> Setter<'a, &'a str> for VOption<'a> {
603    fn set(mut self, name: &str, value: &'a str) -> VOption<'a> {
604        self.options
605            .push(
606                Pair::input(
607                    name,
608                    VipsValue::Str(value),
609                ),
610            );
611        self
612    }
613    fn add(&mut self, name: &str, value: &'a str) {
614        self.options
615            .push(
616                Pair::input(
617                    name,
618                    VipsValue::Str(value),
619                ),
620            );
621    }
622}
623
624impl<'a> Setter<'a, &'a String> for VOption<'a> {
625    fn set(mut self, name: &str, value: &'a String) -> VOption<'a> {
626        self.options
627            .push(
628                Pair::input(
629                    name,
630                    VipsValue::Str(value),
631                ),
632            );
633        self
634    }
635    fn add(&mut self, name: &str, value: &'a String) {
636        self.options
637            .push(
638                Pair::input(
639                    name,
640                    VipsValue::Str(value),
641                ),
642            );
643    }
644}
645
646// input VipsImage
647impl<'a> Setter<'a, &'a crate::VipsImage> for VOption<'a> {
648    fn set(mut self, name: &str, value: &'a crate::VipsImage) -> VOption<'a> {
649        self.options
650            .push(
651                Pair::input(
652                    name,
653                    VipsValue::Image(value),
654                ),
655            );
656        self
657    }
658    fn add(&mut self, name: &str, value: &'a crate::VipsImage) {
659        self.options
660            .push(
661                Pair::input(
662                    name,
663                    VipsValue::Image(value),
664                ),
665            );
666    }
667}
668
669// input &[i32]
670impl<'a> Setter<'a, &'a [i32]> for VOption<'a> {
671    fn set(mut self, name: &str, value: &'a [i32]) -> VOption<'a> {
672        self.options
673            .push(
674                Pair::input(
675                    name,
676                    VipsValue::IntArray(value),
677                ),
678            );
679        self
680    }
681    fn add(&mut self, name: &str, value: &'a [i32]) {
682        self.options
683            .push(
684                Pair::input(
685                    name,
686                    VipsValue::IntArray(value),
687                ),
688            );
689    }
690}
691
692impl<'a, const N: usize> Setter<'a, &'a [i32; N]> for VOption<'a> {
693    fn set(mut self, name: &str, value: &'a [i32; N]) -> VOption<'a> {
694        self.options
695            .push(
696                Pair::input(
697                    name,
698                    VipsValue::IntArray(value),
699                ),
700            );
701        self
702    }
703    fn add(&mut self, name: &str, value: &'a [i32; N]) {
704        self.options
705            .push(
706                Pair::input(
707                    name,
708                    VipsValue::IntArray(value),
709                ),
710            );
711    }
712}
713
714// input &[f64]
715impl<'a> Setter<'a, &'a [f64]> for VOption<'a> {
716    fn set(mut self, name: &str, value: &'a [f64]) -> VOption<'a> {
717        self.options
718            .push(
719                Pair::input(
720                    name,
721                    VipsValue::DoubleArray(value),
722                ),
723            );
724        self
725    }
726    fn add(&mut self, name: &str, value: &'a [f64]) {
727        self.options
728            .push(
729                Pair::input(
730                    name,
731                    VipsValue::DoubleArray(value),
732                ),
733            );
734    }
735}
736
737impl<'a, const N: usize> Setter<'a, &'a [f64; N]> for VOption<'a> {
738    fn set(mut self, name: &str, value: &'a [f64; N]) -> VOption<'a> {
739        self.options
740            .push(
741                Pair::input(
742                    name,
743                    VipsValue::DoubleArray(value),
744                ),
745            );
746        self
747    }
748    fn add(&mut self, name: &str, value: &'a [f64; N]) {
749        self.options
750            .push(
751                Pair::input(
752                    name,
753                    VipsValue::DoubleArray(value),
754                ),
755            );
756    }
757}
758
759// input &[VipsImage]
760impl<'a> Setter<'a, &'a [crate::VipsImage]> for VOption<'a> {
761    fn set(mut self, name: &str, value: &'a [crate::VipsImage]) -> VOption<'a> {
762        self.options
763            .push(
764                Pair::input(
765                    name,
766                    VipsValue::ImageArray(value),
767                ),
768            );
769        self
770    }
771    fn add(&mut self, name: &str, value: &'a [crate::VipsImage]) {
772        self.options
773            .push(
774                Pair::input(
775                    name,
776                    VipsValue::ImageArray(value),
777                ),
778            );
779    }
780}
781
782impl<'a, const N: usize> Setter<'a, &'a [crate::VipsImage; N]> for VOption<'a> {
783    fn set(mut self, name: &str, value: &'a [crate::VipsImage; N]) -> VOption<'a> {
784        self.options
785            .push(
786                Pair::input(
787                    name,
788                    VipsValue::ImageArray(value),
789                ),
790            );
791        self
792    }
793    fn add(&mut self, name: &str, value: &'a [crate::VipsImage; N]) {
794        self.options
795            .push(
796                Pair::input(
797                    name,
798                    VipsValue::ImageArray(value),
799                ),
800            );
801    }
802}
803
804// input VipsBlob
805impl<'a> Setter<'a, &'a crate::region::VipsBlob> for VOption<'a> {
806    fn set(mut self, name: &str, value: &'a crate::region::VipsBlob) -> VOption<'a> {
807        self.options
808            .push(
809                Pair::input(
810                    name,
811                    VipsValue::Blob(value),
812                ),
813            );
814        self
815    }
816    fn add(&mut self, name: &str, value: &'a crate::region::VipsBlob) {
817        self.options
818            .push(
819                Pair::input(
820                    name,
821                    VipsValue::Blob(value),
822                ),
823            );
824    }
825}
826
827// input VipsTarget
828impl<'a> Setter<'a, &'a crate::connection::VipsTarget> for VOption<'a> {
829    fn set(mut self, name: &str, value: &'a crate::connection::VipsTarget) -> VOption<'a> {
830        self.options
831            .push(
832                Pair::input(
833                    name,
834                    VipsValue::Target(value),
835                ),
836            );
837        self
838    }
839    fn add(&mut self, name: &str, value: &'a crate::connection::VipsTarget) {
840        self.options
841            .push(
842                Pair::input(
843                    name,
844                    VipsValue::Target(value),
845                ),
846            );
847    }
848}
849
850// input VipsSource
851impl<'a> Setter<'a, &'a crate::connection::VipsSource> for VOption<'a> {
852    fn set(mut self, name: &str, value: &'a crate::connection::VipsSource) -> VOption<'a> {
853        self.options
854            .push(
855                Pair::input(
856                    name,
857                    VipsValue::Source(value),
858                ),
859            );
860        self
861    }
862    fn add(&mut self, name: &str, value: &'a crate::connection::VipsSource) {
863        self.options
864            .push(
865                Pair::input(
866                    name,
867                    VipsValue::Source(value),
868                ),
869            );
870    }
871}
872
873// input VipsInterpolate
874impl<'a> Setter<'a, &'a crate::interpolate::VipsInterpolate> for VOption<'a> {
875    fn set(mut self, name: &str, value: &'a crate::interpolate::VipsInterpolate) -> VOption<'a> {
876        self.options
877            .push(
878                Pair::input(
879                    name,
880                    VipsValue::Interpolate(value),
881                ),
882            );
883        self
884    }
885    fn add(&mut self, name: &str, value: &'a crate::interpolate::VipsInterpolate) {
886        self.options
887            .push(
888                Pair::input(
889                    name,
890                    VipsValue::Interpolate(value),
891                ),
892            );
893    }
894}
895
896// output bool
897impl<'a> Setter<'a, &'a mut bool> for VOption<'a> {
898    fn set(mut self, name: &str, value: &'a mut bool) -> VOption<'a> {
899        self.options
900            .push(
901                Pair::output(
902                    name,
903                    VipsValue::MutBool(value),
904                ),
905            );
906        self
907    }
908    fn add(&mut self, name: &str, value: &'a mut bool) {
909        self.options
910            .push(
911                Pair::output(
912                    name,
913                    VipsValue::MutBool(value),
914                ),
915            );
916    }
917}
918
919// output i32
920impl<'a> Setter<'a, &'a mut i32> for VOption<'a> {
921    fn set(mut self, name: &str, value: &'a mut i32) -> VOption<'a> {
922        self.options
923            .push(
924                Pair::output(
925                    name,
926                    VipsValue::MutInt(value),
927                ),
928            );
929        self
930    }
931    fn add(&mut self, name: &str, value: &'a mut i32) {
932        self.options
933            .push(
934                Pair::output(
935                    name,
936                    VipsValue::MutInt(value),
937                ),
938            );
939    }
940}
941
942// output f64
943impl<'a> Setter<'a, &'a mut f64> for VOption<'a> {
944    fn set(mut self, name: &str, value: &'a mut f64) -> VOption<'a> {
945        self.options
946            .push(
947                Pair::output(
948                    name,
949                    VipsValue::MutDouble(value),
950                ),
951            );
952        self
953    }
954    fn add(&mut self, name: &str, value: &'a mut f64) {
955        self.options
956            .push(
957                Pair::output(
958                    name,
959                    VipsValue::MutDouble(value),
960                ),
961            );
962    }
963}
964
965// output VipsImage
966impl<'a> Setter<'a, &'a mut crate::VipsImage> for VOption<'a> {
967    fn set(mut self, name: &str, value: &'a mut crate::VipsImage) -> VOption<'a> {
968        self.options
969            .push(
970                Pair::output(
971                    name,
972                    VipsValue::MutImage(value),
973                ),
974            );
975        self
976    }
977    fn add(&mut self, name: &str, value: &'a mut crate::VipsImage) {
978        self.options
979            .push(
980                Pair::output(
981                    name,
982                    VipsValue::MutImage(value),
983                ),
984            );
985    }
986}
987
988// output Vec<f64>
989impl<'a> Setter<'a, &'a mut Vec<f64>> for VOption<'a> {
990    fn set(mut self, name: &str, value: &'a mut Vec<f64>) -> VOption<'a> {
991        self.options
992            .push(
993                Pair::output(
994                    name,
995                    VipsValue::MutDoubleArray(value),
996                ),
997            );
998        self
999    }
1000    fn add(&mut self, name: &str, value: &'a mut Vec<f64>) {
1001        self.options
1002            .push(
1003                Pair::output(
1004                    name,
1005                    VipsValue::MutDoubleArray(value),
1006                ),
1007            );
1008    }
1009}
1010
1011// output VipsBlob
1012impl<'a> Setter<'a, &'a mut crate::region::VipsBlob> for VOption<'a> {
1013    fn set(mut self, name: &str, value: &'a mut crate::region::VipsBlob) -> VOption<'a> {
1014        self.options
1015            .push(
1016                Pair::output(
1017                    name,
1018                    VipsValue::MutBlob(value),
1019                ),
1020            );
1021        self
1022    }
1023    fn add(&mut self, name: &str, value: &'a mut crate::region::VipsBlob) {
1024        self.options
1025            .push(
1026                Pair::output(
1027                    name,
1028                    VipsValue::MutBlob(value),
1029                ),
1030            );
1031    }
1032}