mr_bundle/
lib.rs

1//! Library for collecting bundling resources based on a manifest.
2//!
3//! Bundles created with Mr. Bundle are designed to be portable so
4//! that they can be sent to other systems and unpacked there.
5//!
6//! A [`Bundle`] contains a [`Manifest`] as well as any number of arbitrary
7//! opaque resources in the form of [`ResourceBytes`]. The manifest describes
8//! the resources that should be included in the bundle. A Bundle can be
9//! serialized and written to a file.
10//!
11//! With the `fs` feature, the `FileSystemBundler` can be used to work with
12//! bundles on the file system.
13//!
14//! # Example: In-memory bundle
15//!
16//! A basic use of this library would be to create a bundle in-memory.
17//!
18//! ```rust
19//! use std::collections::HashMap;
20//! use serde::{Deserialize, Serialize};
21//! use mr_bundle::{Bundle, Manifest, ResourceIdentifier};
22//!
23//! // Define your manifest
24//! #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
25//! struct MyManifest {
26//!     video: String,
27//!     audio: String,
28//! }
29//!
30//! // Implement the Manifest trait for MyManifest
31//! impl Manifest for MyManifest {
32//!     fn generate_resource_ids(&mut self) -> HashMap<ResourceIdentifier, String> {
33//!         [self.video.clone(), self.audio.clone()].into_iter().map(|r| {
34//!            (r.clone(), r.clone())
35//!         }).collect()
36//!     }
37//!
38//!     fn resource_ids(&self) -> Vec<ResourceIdentifier> {
39//!         [self.video.clone(), self.audio.clone()].into_iter().collect()
40//!     }
41//!
42//!     fn file_name() -> &'static str {
43//!         "example.yaml"
44//!     }
45//!
46//!     fn bundle_extension() -> &'static str {
47//!         "bundle"
48//!     }
49//! }
50//!
51//! let bundle = Bundle::new(
52//!   MyManifest {
53//!       video: "audio_sample".into(),
54//!       audio: "video_sample".into(),
55//!   },
56//!   vec![(
57//!      "audio_sample".to_string(), vec![1, 2, 3].into()
58//!   ), (
59//!      "video_sample".to_string(), vec![44, 54, 23].into()
60//!   )]
61//! ).unwrap();
62//!
63//! // Serialize the bundle to a byte vector
64//! let bytes = bundle.pack().unwrap();
65//!
66//! // Then do something with the bytes...
67//! ```
68//!
69//! # Example: Bundle to the file system
70//!
71//!
72//! ```rust,no_run
73//! use std::collections::HashMap;
74//! use serde::{Deserialize, Serialize};
75//! use mr_bundle::{resource_id_for_path, Bundle, FileSystemBundler, Manifest, ResourceIdentifier};
76//!
77//! # #[tokio::main]
78//! # async fn main() {
79//! // Define your manifest
80//! #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
81//! struct MyManifest {
82//!     video: String,
83//!     audio: String,
84//! }
85//!
86//! // Implement the Manifest trait for MyManifest
87//! impl Manifest for MyManifest {
88//!     fn generate_resource_ids(&mut self) -> HashMap<ResourceIdentifier, String> {
89//!         let mut out = HashMap::new();
90//!
91//!         let audio_id = resource_id_for_path(&self.audio).unwrap_or("audio-id".to_string());
92//!         out.insert(audio_id.clone(), self.audio.clone());
93//!         self.audio = audio_id;
94//!
95//!         let video_id = resource_id_for_path(&self.video).unwrap_or("video-id".to_string());
96//!         out.insert(video_id.clone(), self.video.clone());
97//!         self.video = video_id;
98//!
99//!         out
100//!     }
101//!
102//!     fn resource_ids(&self) -> Vec<ResourceIdentifier> {
103//!         [
104//!             resource_id_for_path(&self.audio).unwrap_or("audio-id".to_string()),
105//!             resource_id_for_path(&self.video).unwrap_or("video-id".to_string())
106//!         ].into_iter().collect()
107//!     }
108//!
109//!     fn file_name() -> &'static str {
110//!         "example.yaml"
111//!     }
112//!
113//!     fn bundle_extension() -> &'static str {
114//!         "bundle"
115//!     }
116//! }
117//!
118//! // Create an example manifest, and note that the resource paths would also need to exist.
119//! std::fs::write("./example.yaml", r#"
120//! audio: ./audio-sample.mp3
121//! video: ./video-sample.mp4
122//! "#).unwrap();
123//!
124//! // Then create a bundle using the manifest.
125//! // The resulting bundle will be written to the file system.
126//! FileSystemBundler::bundle_to::<MyManifest>(
127//!     "./example.yaml",
128//!     "./packaging/example.bundle",
129//! ).await.unwrap();
130//!
131//! // The bundle will now exist on the file system.
132//! assert!(std::fs::exists("./packaging/example.bundle").unwrap());
133//! # }
134//! ```
135//!
136
137#![deny(missing_docs)]
138#![cfg_attr(docsrs, feature(doc_cfg))]
139
140mod bundle;
141pub mod error;
142#[cfg(feature = "fs")]
143#[cfg_attr(docsrs, doc(cfg(feature = "fs")))]
144mod fs;
145mod manifest;
146mod pack;
147
148pub use bundle::{resource::ResourceBytes, Bundle, ResourceMap};
149#[cfg(feature = "fs")]
150pub use fs::{resource_id_for_path, FileSystemBundler};
151pub use manifest::{Manifest, ResourceIdentifier};
152pub use pack::{pack, unpack};