grouse 0.3.0

A simple asset bundler for Rust.
Documentation
//! # grouse
//!
//! A simple asset bundler for Rust.
//!
//! ## about
//!
//! `grouse` is a very simple asset bundler intended for baking static
//! files directly into your Rust binaries. In short, `grouse` will generate a
//! unit `struct` that implements an `fn` to retreive all of the files within a
//! particular [Manifest], and one to lookup a file by it's sha256 digest.
//!
//! ## getting started
//!
//! To start using `grouse`, you'll first need to add our package to your
//! `Cargo.toml` manifest:
//!
//! ```sh
//! cargo add grouse
//! ```
//!
//! Then you can bundle a directory into your Rust executable.
//!
//! ```rust
//! // Thanks to recently stablized proc-macro features, the include
//! // path is relative to the current file directory, like how the
//! // builtin [`core::include_bytes!`] macro works.
//! #[grouse::manifest("../src")]
//! struct Manifest;
//!
//! fn main() {
//!   // Iterate through all of the files in the manifest.
//!   for file in Manifest::files() {
//!      eprintln!("{} => {}", file.path(), file.digest());
//!   }
//!
//!   // We can also get the digest of a particular file directly.
//!   let x = grouse::file!("../src/lib.rs").digest();
//!
//!   // Which can then be used to lookup it's corresponding file in the
//!   // manifest.
//!   let lib = Manifest::get(x).unwrap();
//! }
//! ```

pub use grouse_macros::{file, manifest};

/// Represents a file embedded into this binary.
///
/// You can lookup or retrieve a slice of [File] by creating a [Manifest] with
/// the [manifest] macro. Or you can directly retrieve a [File] using a relative
/// path via [file].
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct File {
    name: &'static str,
    digest: &'static str,
    path: &'static str,
    bytes: &'static [u8],
    mime: &'static str,

    #[cfg(feature = "base64")]
    base64: &'static str,
}

impl File {
    /// The name of this file, according to [std::path::Path::file_name].
    #[inline]
    pub const fn name(&self) -> &'static str {
        self.name
    }

    /// The sha256 digest of the contents and path of this file, encoded as a
    /// hex string.
    #[inline]
    pub const fn digest(&self) -> &'static str {
        self.digest
    }

    /// The path of this file, relative to the `CARGO_MANIFEST_DIR`.
    #[inline]
    pub const fn path(&self) -> &'static str {
        self.path
    }

    /// The raw contents of this file.
    #[inline]
    pub const fn bytes(&self) -> &'static [u8] {
        self.bytes
    }

    /// A best-effort guess as to the mime type of this file.
    #[inline]
    pub const fn mime(&self) -> &'static str {
        self.mime
    }

    /// The contents of this file, encoded as a base64 string.
    #[cfg(feature = "base64")]
    #[inline]
    pub const fn base64(&self) -> &'static str {
        self.base64
    }
}

pub trait Manifest {
    /// All of the files that this [Manifest] contains.
    fn files() -> &'static [File];

    /// Lookup a [File] by it's sha256 digest.
    fn get(x: &str) -> Option<File>;
}

#[cfg(feature = "macros")]
#[doc(hidden)]
pub mod __macros {
    #[inline]
    pub const fn file(
        name: &'static str,
        digest: &'static str,
        path: &'static str,
        bytes: &'static [u8],
        mime: &'static str,

        #[cfg(feature = "base64")] base64: &'static str,
    ) -> crate::File {
        crate::File {
            name,
            digest,
            path,
            bytes,
            mime,

            #[cfg(feature = "base64")]
            base64,
        }
    }
}