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        pub struct $wand {
22            wand: *mut crate::bindings::$wand,
23        }
24
25        impl Default for $wand {
26            fn default() -> Self {
27                Self::new()
28            }
29        }
30
31        impl $wand {
32            pub fn new() -> Self {
33                $wand {
34                    wand: unsafe { crate::bindings::$new_wand() },
35                }
36            }
37
38            pub (crate) fn from_ptr(ptr: *mut crate::bindings::$wand) -> Self {
39                $wand {
40                    wand: ptr
41                }
42            }
43
44            pub (crate) fn as_ptr(&self) -> *mut crate::bindings::$wand {
45                self.wand
46            }
47
48            fn clear(&mut self) {
49                unsafe { crate::bindings::$clear_wand(self.wand) }
50            }
51
52            pub fn clear_exception(&mut self) -> Result<()> {
53                match unsafe { crate::bindings::$clear_exc(self.wand) } {
54                    crate::bindings::MagickBooleanType::MagickTrue => Ok(()),
55                    _ => Err(MagickError(
56                        concat!("failed to clear", stringify!($wand), "exception").to_string(),
57                    )),
58                }
59            }
60
61            pub fn get_exception_type(&self) -> crate::bindings::ExceptionType {
62                unsafe { crate::bindings::$get_exc_type(self.wand) }
63            }
64
65            pub fn get_exception(&self) -> Result<(String, crate::bindings::ExceptionType)> {
66                let mut severity: crate::bindings::ExceptionType =
67                    crate::bindings::ExceptionType::UndefinedException;
68
69                let ptr = unsafe { crate::bindings::$get_exc(self.wand, &mut severity as *mut _) };
70                if ptr.is_null() {
71                    Err(MagickError(
72                        concat!("null ptr returned by", stringify!($wand), "get_exception")
73                            .to_string(),
74                    ))
75                } else {
76                    let c_str = unsafe { CStr::from_ptr(ptr) };
77                    let exception = c_str.to_string_lossy().into_owned();
78                    unsafe { crate::bindings::RelinquishMagickMemory(ptr as *mut ::libc::c_void) };
79                    Ok((exception, severity))
80                }
81            }
82
83            pub fn is_wand(&self) -> Result<()> {
84                match unsafe { crate::bindings::$is_wand(self.wand) } {
85                    crate::bindings::MagickBooleanType::MagickTrue => Ok(()),
86                    _ => Err(MagickError(
87                        concat!(stringify!($wand), " not a wand").to_string(),
88                    )),
89                }
90            }
91        }
92
93        impl Clone for $wand {
94            fn clone(&self) -> Self {
95                $wand {
96                    wand: unsafe { crate::bindings::$clone(self.wand) },
97                }
98            }
99        }
100
101        impl Drop for $wand {
102            fn drop(&mut self) {
103                unsafe {
104                    crate::bindings::$clear_exc(self.wand);
105                    crate::bindings::$destroy(self.wand);
106                }
107            }
108        }
109
110        // The wand types should be safe to drop in a different thread
111        unsafe impl Send for $wand {}
112
113        // Probably shouldn't implement Sync because some methods might not be
114        // safe to call on the same wand from different threads.
115        // unsafe impl Sync for $wand {}
116    };
117}
118
119macro_rules! get {
120    ($($get:ident, $c_get:ident, $typ:ty )*) => {
121        $(
122            pub fn $get(&self) -> $typ {
123                unsafe { crate::bindings::$c_get(self.wand).into() }
124            }
125        )*
126    }
127}
128
129macro_rules! set_get {
130    ($($get:ident, $set:ident, $c_get:ident, $c_set:ident, $typ:ty )*) => {
131        $(
132            pub fn $get(&self) -> $typ {
133                unsafe { crate::bindings::$c_get(self.wand).into() }
134            }
135            pub fn $set(&mut self, v: $typ) -> Result<()> {
136                match unsafe { crate::bindings::$c_set(self.wand, v.into()) } {
137                    crate::bindings::MagickBooleanType::MagickTrue => Ok(()),
138                    _ => Err(MagickError(concat!(stringify!($set), " returned false").to_string()))
139                }
140            }
141        )*
142        pub fn fmt_checked_settings(&self, f: &mut ::std::fmt::Formatter, prefix: &str) -> ::std::fmt::Result {
143            $( writeln!(f, "{}{:<50}: {:?}", prefix, stringify!($c_get), self.$get())?; )*
144            Ok(())
145        }
146    }
147}
148
149macro_rules! set_get_unchecked {
150    ($($get:ident, $set:ident, $c_get:ident, $c_set:ident, $typ:ty )*) => {
151        $(
152            pub fn $get(&self) -> $typ {
153                unsafe { crate::bindings::$c_get(self.wand).into() }
154            }
155            pub fn $set(&mut self, v: $typ) {
156                unsafe { crate::bindings::$c_set(self.wand, v.into()) }
157            }
158        )*
159        pub fn fmt_unchecked_settings(&self, f: &mut ::std::fmt::Formatter, prefix: &str) -> ::std::fmt::Result {
160            $( writeln!(f, "{}{:<50}: {:?}", prefix, stringify!($c_get), self.$get())?; )*
161            Ok(())
162        }
163    }
164}
165
166macro_rules! string_get {
167    ($get:ident, $c_get:ident) => {
168        pub fn $get(&self) -> Result<String> {
169            let ptr = unsafe { crate::bindings::$c_get(self.wand) };
170            if ptr.is_null() {
171                Err(MagickError(
172                    concat!("null ptr returned by ", stringify!($get)).to_string(),
173                ))
174            } else {
175                let c_str = unsafe { ::std::ffi::CStr::from_ptr(ptr) };
176                let result: String = c_str.to_string_lossy().into_owned();
177                unsafe { crate::bindings::free(ptr as *mut ::libc::c_void) };
178                Ok(result)
179            }
180        }
181    };
182}
183
184macro_rules! string_set_get {
185    ($($get:ident, $set:ident, $c_get:ident, $c_set:ident)*) => {
186        $(
187            string_get!($get, $c_get);
188            pub fn $set(&mut self, s: &str) -> Result<()> {
189                let c_string = std::ffi::CString::new(s).map_err(|_| "could not convert to cstring")?;
190                match unsafe { crate::bindings::$c_set(self.wand, c_string.as_ptr()) } {
191                    crate::bindings::MagickBooleanType::MagickTrue => Ok(()),
192                    _ => Err(MagickError(concat!(stringify!($set), " returned false").to_string()))
193                }
194            }
195        )*
196        pub fn fmt_string_settings(&self, f: &mut ::std::fmt::Formatter, prefix: &str) -> ::std::fmt::Result {
197            $( writeln!(f, "{}{:<50}: {:?}", prefix, stringify!($c_get), self.$get())?; )*
198            Ok(())
199        }
200    }
201}
202
203macro_rules! string_set_get_unchecked {
204    ($($get:ident, $set:ident, $c_get:ident, $c_set:ident )*) => {
205        $(
206            string_get!($get, $c_get);
207            pub fn $set(&mut self, s: &str) -> Result<()> {
208                let c_string = ::std::ffi::CString::new(s).map_err(|_| "could not convert to cstring")?;
209                unsafe { crate::bindings::$c_set(self.wand, c_string.as_ptr()) };
210                Ok(())
211            }
212        )*
213        pub fn fmt_string_unchecked_settings(&self, f: &mut ::std::fmt::Formatter, prefix: &str) -> ::std::fmt::Result {
214            $( writeln!(f, "{}{:<50}: {:?}", prefix, stringify!($c_get), self.$get())?; )*
215            Ok(())
216        }
217    }
218}
219
220macro_rules! pixel_set_get {
221    ($($get:ident, $set:ident, $c_get:ident, $c_set:ident )*) => {
222        $(
223            pub fn $get(&self) -> crate::PixelWand {
224                let pw = crate::PixelWand::new();
225                unsafe { crate::bindings::$c_get(self.wand, pw.as_ptr()) };
226                pw
227            }
228            pub fn $set(&mut self, pw: &crate::PixelWand) {
229                unsafe { crate::bindings::$c_set(self.wand, pw.as_ptr()) }
230            }
231        )*
232        pub fn fmt_pixel_settings(&self, f: &mut ::std::fmt::Formatter, prefix: &str) -> ::std::fmt::Result {
233            $(
234                writeln!(f, "{}{:<50}: ", prefix, stringify!($c_get))?;
235                self.$get().fmt_w_prefix(f, &format!("{}{:<53}", prefix, " ") )?;
236            )*
237            Ok(())
238        }
239    }
240}
241
242macro_rules! color_set_get {
243    ($(
244        $get:ident,   $get_quantum:ident,   $set:ident,   $set_quantum:ident,
245        $c_get:ident, $c_get_quantum:ident, $c_set:ident, $c_set_quantum:ident
246    )*) => {
247        $(
248            pub fn $get(&self) -> f64 {
249                unsafe { crate::bindings::$c_get(self.wand) }
250            }
251            pub fn $get_quantum(&self) -> bindings::Quantum {
252                unsafe { crate::bindings::$c_get_quantum(self.wand) }
253            }
254            pub fn $set(&mut self, v: f64) {
255                unsafe { crate::bindings::$c_set(self.wand, v) }
256            }
257            pub fn $set_quantum(&mut self, v: bindings::Quantum) {
258                unsafe { crate::bindings::$c_set_quantum(self.wand, v) }
259            }
260        )*
261        pub fn fmt_color_settings(&self, f: &mut ::std::fmt::Formatter, prefix: &str) -> ::std::fmt::Result {
262            writeln!(f, "{}Color: {:?}, normalized: {:?}\n{}hsl: {:?}",
263                     prefix,
264                     self.get_color_as_string(),
265                     self.get_color_as_normalized_string(),
266                     prefix,
267                     self.get_hsl()
268            )?;
269            $( writeln!(f, "{}{:<10}: {:>} quantum: {}", prefix, stringify!($c_get).split_at(8).1, self.$get(), self.$get_quantum())?; )*
270            Ok(())
271        }
272    }
273}
274
275macro_rules! mutations {
276    ($($(#[$attr:meta])* $c_fun:ident => $fun:ident($($arg:ident: $ty:ty),*))*) => {
277        $(
278            $(#[$attr])*
279            pub fn $fun(&self $(, $arg: $ty)*) -> Result<()> {
280                match unsafe { bindings::$c_fun(self.wand $(, $arg.into())*) } {
281                    bindings::MagickBooleanType::MagickTrue => Ok(()),
282                    _ => Err(MagickError(concat!(stringify!($c_fun), " invocation failed").to_string()))
283                }
284            }
285        )*
286    }
287}