1 // Take a look at the license at the top of the repository in the LICENSE file.
2 
3 use crate::{resources_register, Resource};
4 use glib::translate::*;
5 use std::env;
6 use std::mem;
7 use std::path::Path;
8 use std::process::Command;
9 use std::ptr;
10 
11 impl Resource {
12     #[doc(alias = "g_resource_new_from_data")]
from_data(data: &glib::Bytes) -> Result<Resource, glib::Error>13     pub fn from_data(data: &glib::Bytes) -> Result<Resource, glib::Error> {
14         unsafe {
15             let mut error = ptr::null_mut();
16 
17             // Create a copy of data if it is not pointer-aligned
18             // https://bugzilla.gnome.org/show_bug.cgi?id=790030
19             let mut data = data.clone();
20             let data_ptr = glib::ffi::g_bytes_get_data(data.to_glib_none().0, ptr::null_mut());
21             if data_ptr as usize % mem::align_of::<*const u8>() != 0 {
22                 data = glib::Bytes::from(&*data);
23             }
24 
25             let ret = ffi::g_resource_new_from_data(data.to_glib_none().0, &mut error);
26             if error.is_null() {
27                 Ok(from_glib_full(ret))
28             } else {
29                 Err(from_glib_full(error))
30             }
31         }
32     }
33 }
34 
35 // rustdoc-stripper-ignore-next
36 /// Call from build script to run `glib-compile-resources` to generate compiled gresources to embed
37 /// in binary with [resources_register_include]. `target` is relative to `OUT_DIR`.
38 ///
39 /// ```no_run
40 /// gio::compile_resources(
41 ///     "resources",
42 ///     "resources/resources.gresource.xml",
43 ///     "compiled.gresource",
44 /// );
45 /// ```
compile_resources<P: AsRef<Path>>(source_dir: P, gresource: &str, target: &str)46 pub fn compile_resources<P: AsRef<Path>>(source_dir: P, gresource: &str, target: &str) {
47     let out_dir = env::var("OUT_DIR").unwrap();
48 
49     let status = Command::new("glib-compile-resources")
50         .arg("--sourcedir")
51         .arg(source_dir.as_ref())
52         .arg("--target")
53         .arg(&format!("{}/{}", out_dir, target))
54         .arg(gresource)
55         .status()
56         .unwrap();
57 
58     if !status.success() {
59         panic!("glib-compile-resources failed with exit status {}", status);
60     }
61 
62     println!("cargo:rerun-if-changed={}", gresource);
63     let output = Command::new("glib-compile-resources")
64         .arg("--sourcedir")
65         .arg(source_dir.as_ref())
66         .arg("--generate-dependencies")
67         .arg(gresource)
68         .output()
69         .unwrap()
70         .stdout;
71     let output = String::from_utf8(output).unwrap();
72     for dep in output.split_whitespace() {
73         println!("cargo:rerun-if-changed={}", dep);
74     }
75 }
76 
77 #[doc(hidden)]
resources_register_include_impl(bytes: &'static [u8]) -> Result<(), glib::Error>78 pub fn resources_register_include_impl(bytes: &'static [u8]) -> Result<(), glib::Error> {
79     let bytes = glib::Bytes::from_static(bytes);
80     let resource = Resource::from_data(&bytes)?;
81     resources_register(&resource);
82     Ok(())
83 }
84 
85 // rustdoc-stripper-ignore-next
86 /// Include gresources generated with [compile_resources] and register with glib. `path` is
87 /// relative to `OUTDIR`.
88 ///
89 /// ```ignore
90 /// gio::resources_register_include!("compiled.gresource").unwrap();
91 /// ```
92 #[macro_export]
93 macro_rules! resources_register_include {
94     ($path:expr) => {
95         $crate::resources_register_include_impl(include_bytes!(concat!(
96             env!("OUT_DIR"),
97             "/",
98             $path
99         )))
100     };
101 }
102