1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// Take a look at the license at the top of the repository in the LICENSE file.

// e.g. declare_surface(ImageSurface, SurfaceType::Image)
macro_rules! declare_surface {
    ($surf_name:ident, $surf_type:expr) => {
        #[derive(Debug)]
        #[repr(transparent)]
        pub struct $surf_name(Surface);

        impl TryFrom<Surface> for $surf_name {
            type Error = Surface;

            #[inline]
            fn try_from(surface: Surface) -> Result<$surf_name, Surface> {
                if surface.type_() == $surf_type {
                    Ok($surf_name(surface))
                } else {
                    Err(surface)
                }
            }
        }

        impl $surf_name {
            #[inline]
            pub unsafe fn from_raw_full(
                ptr: *mut ffi::cairo_surface_t,
            ) -> Result<$surf_name, crate::error::Error> {
                let surface = Surface::from_raw_full(ptr)?;
                Self::try_from(surface).map_err(|_| crate::error::Error::SurfaceTypeMismatch)
            }

            #[inline]
            pub unsafe fn from_raw_none(
                ptr: *mut ffi::cairo_surface_t,
            ) -> Result<$surf_name, crate::error::Error> {
                let surface = Surface::from_raw_none(ptr);
                Self::try_from(surface).map_err(|_| crate::error::Error::SurfaceTypeMismatch)
            }
        }

        #[cfg(feature = "use_glib")]
        impl IntoGlibPtr<*mut ffi::cairo_surface_t> for $surf_name {
            #[inline]
            unsafe fn into_glib_ptr(self) -> *mut ffi::cairo_surface_t {
                std::mem::ManuallyDrop::new(self).to_glib_none().0
            }
        }

        #[cfg(feature = "use_glib")]
        impl<'a> ToGlibPtr<'a, *mut ffi::cairo_surface_t> for $surf_name {
            type Storage = std::marker::PhantomData<&'a Surface>;

            #[inline]
            fn to_glib_none(&'a self) -> Stash<'a, *mut ffi::cairo_surface_t, Self> {
                let stash = self.0.to_glib_none();
                Stash(stash.0, stash.1)
            }

            #[inline]
            fn to_glib_full(&self) -> *mut ffi::cairo_surface_t {
                unsafe { ffi::cairo_surface_reference(self.to_glib_none().0) }
            }
        }

        #[cfg(feature = "use_glib")]
        impl FromGlibPtrNone<*mut ffi::cairo_surface_t> for $surf_name {
            #[inline]
            unsafe fn from_glib_none(ptr: *mut ffi::cairo_surface_t) -> $surf_name {
                Self::try_from(from_glib_none::<_, Surface>(ptr)).unwrap()
            }
        }

        #[cfg(feature = "use_glib")]
        impl FromGlibPtrBorrow<*mut ffi::cairo_surface_t> for $surf_name {
            #[inline]
            unsafe fn from_glib_borrow(
                ptr: *mut ffi::cairo_surface_t,
            ) -> crate::Borrowed<$surf_name> {
                let surface = from_glib_borrow::<_, Surface>(ptr);
                let surface = Self::try_from(surface.into_inner())
                    .map_err(std::mem::forget)
                    .unwrap();
                crate::Borrowed::new(surface)
            }
        }

        #[cfg(feature = "use_glib")]
        impl FromGlibPtrFull<*mut ffi::cairo_surface_t> for $surf_name {
            #[inline]
            unsafe fn from_glib_full(ptr: *mut ffi::cairo_surface_t) -> $surf_name {
                Self::from_raw_full(ptr).unwrap()
            }
        }

        #[cfg(feature = "use_glib")]
        gvalue_impl!(
            $surf_name,
            ffi::cairo_surface_t,
            ffi::gobject::cairo_gobject_surface_get_type
        );

        impl Deref for $surf_name {
            type Target = Surface;

            #[inline]
            fn deref(&self) -> &Surface {
                &self.0
            }
        }

        impl AsRef<Surface> for $surf_name {
            #[inline]
            fn as_ref(&self) -> &Surface {
                &self.0
            }
        }

        impl Clone for $surf_name {
            #[inline]
            fn clone(&self) -> $surf_name {
                $surf_name(self.0.clone())
            }
        }

        impl fmt::Display for $surf_name {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                f.write_str(stringify!($surf_name))
            }
        }
    };
}