rust-embed v8.12.0

#rust#proc-macro#http

git clone https://git.pyrossh.dev/rust-embed

rust macro which loads files into the rust binary at compile time during release and loads the file from the fs during dev.


38f5767 — Peter John 2026-09-16T14:00:10+05:30
Add DynRustEmbed for dyn-compatible trait objects
Files changed (3) hide show
  1. changelog.md +4 -0
  2. src/lib.rs +49 -0
  3. tests/lib.rs +14 -1
changelog.md CHANGED
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
7
7
 
8
8
  Thanks to [Mark Drobnak](https://github.com/AzureMarker) for the changelog.
9
9
 
10
+ ## [Unreleased]
11
+
12
+ - Add `DynRustEmbed`, a dyn-compatible counterpart to `RustEmbed`, blanket-implemented for all embed types so they can be stored behind `Box<dyn DynRustEmbed>` / `&dyn DynRustEmbed`.
13
+
10
14
  ## [8.12.0] - 2026-07-08
11
15
 
12
16
  - Fix embedded data being duplicated in binary. Thanks to [email protected].
src/lib.rs CHANGED
@@ -59,6 +59,55 @@ pub trait RustEmbed {
59
59
 
60
60
  pub use RustEmbed as Embed;
61
61
 
62
+ /// A dyn-compatible ("object safe") counterpart to [`RustEmbed`].
63
+ ///
64
+ /// `RustEmbed` cannot be used as `dyn RustEmbed` because its methods have no
65
+ /// `self` parameter (they are associated functions on a marker type). This
66
+ /// trait exists for callers who need to store or pass around an embedded
67
+ /// directory as a trait object, e.g. `Box<dyn DynRustEmbed>`.
68
+ ///
69
+ /// It is blanket-implemented for every type that implements `RustEmbed`, so
70
+ /// there is nothing to derive or implement manually:
71
+ ///
72
+ /// ```
73
+ /// use rust_embed::{DynRustEmbed, Embed};
74
+ ///
75
+ /// #[derive(Embed)]
76
+ /// #[folder = "examples/public/"]
77
+ /// struct Asset;
78
+ ///
79
+ /// fn main() {
80
+ /// let embed: Box<dyn DynRustEmbed> = Box::new(Asset);
81
+ /// let _ = embed.get("index.html");
82
+ /// }
83
+ /// ```
84
+ pub trait DynRustEmbed {
85
+ /// Get file compressed. See [`RustEmbed::compressed`].
86
+ #[cfg(feature = "compression")]
87
+ fn compressed(&self, file_path: &str) -> Option<EmbeddedCompressedFile>;
88
+
89
+ /// Get an embedded file and its metadata. See [`RustEmbed::get`].
90
+ fn get(&self, file_path: &str) -> Option<EmbeddedFile>;
91
+
92
+ /// Returns the file paths in the folder. See [`RustEmbed::iter`].
93
+ fn names(&self) -> Vec<std::borrow::Cow<'static, str>>;
94
+ }
95
+
96
+ impl<T: RustEmbed> DynRustEmbed for T {
97
+ #[cfg(feature = "compression")]
98
+ fn compressed(&self, file_path: &str) -> Option<EmbeddedCompressedFile> {
99
+ T::compressed(file_path)
100
+ }
101
+
102
+ fn get(&self, file_path: &str) -> Option<EmbeddedFile> {
103
+ T::get(file_path)
104
+ }
105
+
106
+ fn names(&self) -> Vec<std::borrow::Cow<'static, str>> {
107
+ T::iter().collect()
108
+ }
109
+ }
110
+
62
111
  /// An iterator over filenames.
63
112
  ///
64
113
  /// This enum exists for optimization purposes, to avoid boxing the iterator in
tests/lib.rs CHANGED
@@ -1,4 +1,4 @@
1
- use rust_embed::{Embed, RustEmbed};
1
+ use rust_embed::{DynRustEmbed, Embed, RustEmbed};
2
2
 
3
3
  /// Test doc comment
4
4
  #[derive(Embed)]
@@ -70,3 +70,16 @@ fn iter_can_be_boxed() {
70
70
  assert_eq!(filenames.len(), 7);
71
71
  assert!(filenames.contains(&"index.html".to_string()));
72
72
  }
73
+
74
+ /// Test that an embedded directory can be used as a trait object via
75
+ /// `DynRustEmbed`, since `RustEmbed` itself is not dyn-compatible.
76
+ #[test]
77
+ fn dyn_rust_embed_works() {
78
+ let boxed: Box<dyn DynRustEmbed> = Box::new(Asset);
79
+ assert!(boxed.get("index.html").is_some(), "index.html should exist");
80
+ assert!(boxed.get("gg.html").is_none(), "gg.html should not exist");
81
+
82
+ let names = boxed.names();
83
+ assert_eq!(names.len(), 7);
84
+ assert!(names.iter().any(|n| n == "index.html"));
85
+ }