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
//! This crate contains macros for statically including assets in release mode, but dynamically loading them in debug mode.
//!
//! This is primarily intended for games, allowing you to both avoid file IO in release builds and dynamically reload assets
//! in debug mode.

/// Load a text asset statically in release mode, or dynamically in debug.
///
/// The filename is relative to the root of your crate.
///
/// If you wish to override the static/dynamic behaviour, you can use the `force-static` or `force-dynamic`
/// features.
///
/// # Panics
///
/// When running in debug mode, this will panic if the file does not exist. In release mode, this
/// will be a compile error and will never panic.
///
/// # Examples
///
/// ```rust,ignore
/// let toml = asset_str!("Cargo.toml");
/// println!("{}", toml);
/// ```
#[macro_export]
macro_rules! asset_str
{
    ($filename: tt) => {
        {
            #[cfg(any(feature = "force-static", all(not(feature = "force-dynamic"), not(debug_assertions))))]
            {
                const ASSET: &str = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/", $filename));
                let asset: ::std::borrow::Cow<'static, str> = ::std::borrow::Cow::Borrowed(ASSET);
                asset
            }

            #[cfg(any(feature = "force-dynamic", all(not(feature = "force-static"), debug_assertions)))]
            {
                let asset = $crate::load_str(concat!(env!("CARGO_MANIFEST_DIR"), "/", $filename));
                let asset: ::std::borrow::Cow<'static, str> = ::std::borrow::Cow::Owned(asset);
                asset
            }
        }
    }
}


/// Load a binary asset statically in release mode, or dynamically in debug.
///
/// The filename is relative to the root of your crate.
///
/// If you wish to override the static/dynamic behaviour, you can use the `force-static` or `force-dynamic`
/// features.
///
/// # Panics
///
/// When running in debug mode, this will panic if the file does not exist. In release mode, this
/// will be a compile error and will never panic.
///
/// # Examples
///
/// ```rust,ignore
/// let toml_bytes = asset_bytes!("Cargo.toml");
/// println!("{:?}", toml_bytes);
/// ```
#[macro_export]
macro_rules! asset_bytes
{
    ($filename: tt) => {
        {
            #[cfg(any(feature = "force-static", all(not(feature = "force-dynamic"), not(debug_assertions))))]
            {
                const ASSET: &[u8] = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/", $filename));
                let asset: ::std::borrow::Cow<'static, [u8]> = ::std::borrow::Cow::Borrowed(ASSET);
                asset
            }

            #[cfg(any(feature = "force-dynamic", all(not(feature = "force-static"), debug_assertions)))]
            {
                let asset = $crate::load_bytes(concat!(env!("CARGO_MANIFEST_DIR"), "/", $filename));
                let asset: ::std::borrow::Cow<'static, [u8]> = ::std::borrow::Cow::Owned(asset);
                asset
            }
        }
    }
}


/// Used internally by [`asset_str!`](macro.asset_str.html) when loading dynamically.
#[cfg(any(feature = "force-dynamic", all(not(feature = "force-static"), debug_assertions)))]
#[inline]
pub fn load_str(filepath: &str) -> String
{
    use std::fs::File;
    use std::io::Read;

    let mut file = File::open(filepath).unwrap_or_else(|e| panic!("Failed to open file `{}`:\n{}", filepath, e));
    let mut buffer = String::new();
    file.read_to_string(&mut buffer).unwrap_or_else(|e| panic!("Failed to read from `{}`:\n{}", filepath, e));
    buffer
}


/// Used internally by [`asset_bytes!`](macro.asset_bytes.html) when loading dynamically.
#[cfg(any(feature = "force-dynamic", all(not(feature = "force-static"), debug_assertions)))]
#[inline]
pub fn load_bytes(filepath: &str) -> Vec<u8>
{
    use std::fs::File;
    use std::io::Read;

    let mut file = File::open(filepath).unwrap_or_else(|e| panic!("Failed to open file `{}`:\n{}", filepath, e));
    let mut buffer = Vec::new();
    file.read_to_end(&mut buffer).unwrap_or_else(|e| panic!("Failed to read from `{}`:\n{}", filepath, e));
    buffer
}