Skip to main content

magick_rust/wand/
macros.rs

1/*
2 * Copyright 2016 Mattis Marjak
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16macro_rules! wand_common {
17    (   $wand:ident,
18        $new_wand:ident, $clear_wand:ident, $is_wand:ident, $clone:ident, $destroy:ident,
19        $clear_exc:ident, $get_exc_type:ident, $get_exc:ident
20    ) => {
21        #[doc = concat!(
22                    "A safe wrapper around an ImageMagick `", stringify!($wand), "`.\n\n",
23                    "The wand owns the underlying ImageMagick handle and destroys it when dropped."
24                )]
25        pub struct $wand {
26            wand: *mut crate::bindings::$wand,
27        }
28
29        impl Default for $wand {
30            fn default() -> Self {
31                Self::new()
32            }
33        }
34
35        impl $wand {
36            #[doc = concat!("Creates a new, empty `", stringify!($wand), "`.")]
37            pub fn new() -> Self {
38                $wand {
39                    wand: unsafe { crate::bindings::$new_wand() },
40                }
41            }
42
43            pub(crate) fn from_ptr(ptr: *mut crate::bindings::$wand) -> Self {
44                $wand { wand: ptr }
45            }
46
47            pub(crate) fn as_ptr(&self) -> *mut crate::bindings::$wand {
48                self.wand
49            }
50
51            fn clear(&mut self) {
52                unsafe { crate::bindings::$clear_wand(self.wand) }
53            }
54
55            /// Clears any exception currently recorded on the wand.
56            pub fn clear_exception(&mut self) -> Result<()> {
57                match unsafe { crate::bindings::$clear_exc(self.wand) } {
58                    crate::bindings::MagickBooleanType::MagickTrue => Ok(()),
59                    _ => Err(MagickError(
60                        concat!("failed to clear", stringify!($wand), "exception").to_string(),
61                    )),
62                }
63            }
64
65            /// Returns the severity of the most recent exception on the wand.
66            pub fn get_exception_type(&self) -> crate::bindings::ExceptionType {
67                unsafe { crate::bindings::$get_exc_type(self.wand) }
68            }
69
70            /// Returns the most recent exception on the wand as a `(message,
71            /// severity)` pair, or an error if no exception message is available.
72            pub fn get_exception(&self) -> Result<(String, crate::bindings::ExceptionType)> {
73                let mut severity: crate::bindings::ExceptionType =
74                    crate::bindings::ExceptionType::UndefinedException;
75
76                let ptr = unsafe { crate::bindings::$get_exc(self.wand, &mut severity as *mut _) };
77                if ptr.is_null() {
78                    Err(MagickError(
79                        concat!("null ptr returned by", stringify!($wand), "get_exception")
80                            .to_string(),
81                    ))
82                } else {
83                    let c_str = unsafe { CStr::from_ptr(ptr) };
84                    let exception = c_str.to_string_lossy().into_owned();
85                    unsafe { crate::bindings::RelinquishMagickMemory(ptr as *mut ::libc::c_void) };
86                    Ok((exception, severity))
87                }
88            }
89
90            /// Returns `Ok(())` if this is a valid wand of the expected type.
91            pub fn is_wand(&self) -> Result<()> {
92                match unsafe { crate::bindings::$is_wand(self.wand) } {
93                    crate::bindings::MagickBooleanType::MagickTrue => Ok(()),
94                    _ => Err(MagickError(
95                        concat!(stringify!($wand), " not a wand").to_string(),
96                    )),
97                }
98            }
99        }
100
101        impl Clone for $wand {
102            fn clone(&self) -> Self {
103                $wand {
104                    wand: unsafe { crate::bindings::$clone(self.wand) },
105                }
106            }
107        }
108
109        impl Drop for $wand {
110            fn drop(&mut self) {
111                unsafe {
112                    crate::bindings::$clear_exc(self.wand);
113                    crate::bindings::$destroy(self.wand);
114                }
115            }
116        }
117
118        // The wand types should be safe to drop in a different thread
119        unsafe impl Send for $wand {}
120
121        // Probably shouldn't implement Sync because some methods might not be
122        // safe to call on the same wand from different threads.
123        // unsafe impl Sync for $wand {}
124    };
125}
126
127macro_rules! get {
128    ($($get:ident, $c_get:ident, $typ:ty )*) => {
129        $(
130            #[doc = concat!("Wraps ImageMagick's `", stringify!($c_get), "` function.")]
131            pub fn $get(&self) -> $typ {
132                unsafe { crate::bindings::$c_get(self.wand).into() }
133            }
134        )*
135    }
136}
137
138macro_rules! set_get {
139    ($($get:ident, $set:ident, $c_get:ident, $c_set:ident, $typ:ty )*) => {
140        $(
141            #[doc = concat!("Wraps ImageMagick's `", stringify!($c_get), "` function.")]
142            pub fn $get(&self) -> $typ {
143                unsafe { crate::bindings::$c_get(self.wand).into() }
144            }
145            #[doc = concat!("Wraps ImageMagick's `", stringify!($c_set), "` function.")]
146            pub fn $set(&mut self, v: $typ) -> Result<()> {
147                match unsafe { crate::bindings::$c_set(self.wand, v.into()) } {
148                    crate::bindings::MagickBooleanType::MagickTrue => Ok(()),
149                    _ => Err(MagickError(concat!(stringify!($set), " returned false").to_string()))
150                }
151            }
152        )*
153        pub fn fmt_checked_settings(&self, f: &mut ::std::fmt::Formatter, prefix: &str) -> ::std::fmt::Result {
154            $( writeln!(f, "{}{:<50}: {:?}", prefix, stringify!($c_get), self.$get())?; )*
155            Ok(())
156        }
157    }
158}
159
160macro_rules! set_get_unchecked {
161    ($($get:ident, $set:ident, $c_get:ident, $c_set:ident, $typ:ty )*) => {
162        $(
163            #[doc = concat!("Wraps ImageMagick's `", stringify!($c_get), "` function.")]
164            pub fn $get(&self) -> $typ {
165                unsafe { crate::bindings::$c_get(self.wand).into() }
166            }
167            #[doc = concat!("Wraps ImageMagick's `", stringify!($c_set), "` function.")]
168            pub fn $set(&mut self, v: $typ) {
169                unsafe { crate::bindings::$c_set(self.wand, v.into()) }
170            }
171        )*
172        pub fn fmt_unchecked_settings(&self, f: &mut ::std::fmt::Formatter, prefix: &str) -> ::std::fmt::Result {
173            $( writeln!(f, "{}{:<50}: {:?}", prefix, stringify!($c_get), self.$get())?; )*
174            Ok(())
175        }
176    }
177}
178
179macro_rules! string_get {
180    ($get:ident, $c_get:ident) => {
181        #[doc = concat!("Wraps ImageMagick's `", stringify!($c_get), "` function.")]
182        pub fn $get(&self) -> Result<String> {
183            let ptr = unsafe { crate::bindings::$c_get(self.wand) };
184            if ptr.is_null() {
185                Err(MagickError(
186                    concat!("null ptr returned by ", stringify!($get)).to_string(),
187                ))
188            } else {
189                let c_str = unsafe { ::std::ffi::CStr::from_ptr(ptr) };
190                let result: String = c_str.to_string_lossy().into_owned();
191                unsafe { crate::bindings::free(ptr as *mut ::libc::c_void) };
192                Ok(result)
193            }
194        }
195    };
196}
197
198macro_rules! string_set_get {
199    ($($get:ident, $set:ident, $c_get:ident, $c_set:ident)*) => {
200        $(
201            string_get!($get, $c_get);
202            #[doc = concat!("Wraps ImageMagick's `", stringify!($c_set), "` function.")]
203            pub fn $set(&mut self, s: &str) -> Result<()> {
204                let c_string = std::ffi::CString::new(s).map_err(|_| "could not convert to cstring")?;
205                match unsafe { crate::bindings::$c_set(self.wand, c_string.as_ptr()) } {
206                    crate::bindings::MagickBooleanType::MagickTrue => Ok(()),
207                    _ => Err(MagickError(concat!(stringify!($set), " returned false").to_string()))
208                }
209            }
210        )*
211        pub fn fmt_string_settings(&self, f: &mut ::std::fmt::Formatter, prefix: &str) -> ::std::fmt::Result {
212            $( writeln!(f, "{}{:<50}: {:?}", prefix, stringify!($c_get), self.$get())?; )*
213            Ok(())
214        }
215    }
216}
217
218macro_rules! string_set_get_unchecked {
219    ($($get:ident, $set:ident, $c_get:ident, $c_set:ident )*) => {
220        $(
221            string_get!($get, $c_get);
222            #[doc = concat!("Wraps ImageMagick's `", stringify!($c_set), "` function.")]
223            pub fn $set(&mut self, s: &str) -> Result<()> {
224                let c_string = ::std::ffi::CString::new(s).map_err(|_| "could not convert to cstring")?;
225                unsafe { crate::bindings::$c_set(self.wand, c_string.as_ptr()) };
226                Ok(())
227            }
228        )*
229        pub fn fmt_string_unchecked_settings(&self, f: &mut ::std::fmt::Formatter, prefix: &str) -> ::std::fmt::Result {
230            $( writeln!(f, "{}{:<50}: {:?}", prefix, stringify!($c_get), self.$get())?; )*
231            Ok(())
232        }
233    }
234}
235
236macro_rules! pixel_set_get {
237    ($($get:ident, $set:ident, $c_get:ident, $c_set:ident )*) => {
238        $(
239            #[doc = concat!("Wraps ImageMagick's `", stringify!($c_get), "` function.")]
240            pub fn $get(&self) -> crate::PixelWand {
241                let pw = crate::PixelWand::new();
242                unsafe { crate::bindings::$c_get(self.wand, pw.as_ptr()) };
243                pw
244            }
245            #[doc = concat!("Wraps ImageMagick's `", stringify!($c_set), "` function.")]
246            pub fn $set(&mut self, pw: &crate::PixelWand) {
247                unsafe { crate::bindings::$c_set(self.wand, pw.as_ptr()) }
248            }
249        )*
250        pub fn fmt_pixel_settings(&self, f: &mut ::std::fmt::Formatter, prefix: &str) -> ::std::fmt::Result {
251            $(
252                writeln!(f, "{}{:<50}: ", prefix, stringify!($c_get))?;
253                self.$get().fmt_w_prefix(f, &format!("{}{:<53}", prefix, " ") )?;
254            )*
255            Ok(())
256        }
257    }
258}
259
260macro_rules! color_set_get {
261    ($(
262        $get:ident,   $get_quantum:ident,   $set:ident,   $set_quantum:ident,
263        $c_get:ident, $c_get_quantum:ident, $c_set:ident, $c_set_quantum:ident
264    )*) => {
265        $(
266            #[doc = concat!("Wraps ImageMagick's `", stringify!($c_get), "` function.")]
267            pub fn $get(&self) -> f64 {
268                unsafe { crate::bindings::$c_get(self.wand) }
269            }
270            #[doc = concat!("Wraps ImageMagick's `", stringify!($c_get_quantum), "` function.")]
271            pub fn $get_quantum(&self) -> bindings::Quantum {
272                unsafe { crate::bindings::$c_get_quantum(self.wand) }
273            }
274            #[doc = concat!("Wraps ImageMagick's `", stringify!($c_set), "` function.")]
275            pub fn $set(&mut self, v: f64) {
276                unsafe { crate::bindings::$c_set(self.wand, v) }
277            }
278            #[doc = concat!("Wraps ImageMagick's `", stringify!($c_set_quantum), "` function.")]
279            pub fn $set_quantum(&mut self, v: bindings::Quantum) {
280                unsafe { crate::bindings::$c_set_quantum(self.wand, v) }
281            }
282        )*
283        pub fn fmt_color_settings(&self, f: &mut ::std::fmt::Formatter, prefix: &str) -> ::std::fmt::Result {
284            writeln!(f, "{}Color: {:?}, normalized: {:?}\n{}hsl: {:?}",
285                     prefix,
286                     self.get_color_as_string(),
287                     self.get_color_as_normalized_string(),
288                     prefix,
289                     self.get_hsl()
290            )?;
291            $( writeln!(f, "{}{:<10}: {:>} quantum: {}", prefix, stringify!($c_get).split_at(8).1, self.$get(), self.$get_quantum())?; )*
292            Ok(())
293        }
294    }
295}
296
297macro_rules! mutations {
298    ($($(#[$attr:meta])* $c_fun:ident => $fun:ident($($arg:ident: $ty:ty),*))*) => {
299        $(
300            $(#[$attr])*
301            pub fn $fun(&self $(, $arg: $ty)*) -> Result<()> {
302                match unsafe { bindings::$c_fun(self.wand $(, $arg.into())*) } {
303                    bindings::MagickBooleanType::MagickTrue => Ok(()),
304                    _ => Err(MagickError(concat!(stringify!($c_fun), " invocation failed").to_string()))
305                }
306            }
307        )*
308    }
309}