Skip to main content

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