~repos /rust-embed

#rust#proc-macro#http

GIT_CONFIG_PARAMETERS="'http.version=HTTP/1.1'" git clone https://git.pyrossh.dev/rust-embed/.git rust-embed
Discussions: https://groups.google.com/g/rust-embed-devs

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


Files changed (4) hide show
  1. Cargo.toml +1 -1
  2. impl/Cargo.toml +6 -1
  3. impl/src/lib.rs +24 -8
  4. utils/src/lib.rs +7 -24
Cargo.toml CHANGED
@@ -93,7 +93,7 @@ sha2 = "0.10"
93
93
  debug-embed = ["rust-embed-impl/debug-embed", "rust-embed-utils/debug-embed"]
94
94
  interpolate-folder-path = ["rust-embed-impl/interpolate-folder-path"]
95
95
  compression = ["rust-embed-impl/compression", "include-flate"]
96
- mime-guess = ["rust-embed-impl/mime-guess", "rust-embed-utils/mime-guess"]
96
+ mime-guess = ["rust-embed-utils/mime-guess"]
97
97
  include-exclude = [
98
98
  "rust-embed-impl/include-exclude",
99
99
  "rust-embed-utils/include-exclude",
impl/Cargo.toml CHANGED
@@ -17,6 +17,12 @@ proc-macro = true
17
17
  [dependencies]
18
18
  rust-embed-utils = { version = "8.11.0", path = "../utils" }
19
19
 
20
+ # Unconditional (host-only, this is a proc-macro crate) so that the `__mimetype_of`
21
+ # proc macro can always compute a mimetype regardless of how the `mime-guess`
22
+ # feature resolves for the host. Whether the result is actually used is decided
23
+ # target-side by the `__rust_embed_metadata!` macro in `rust-embed-utils`.
24
+ mime_guess = "2.0.4"
25
+
20
26
  syn = { version = "2", default-features = false, features = [
21
27
  "derive",
22
28
  "parsing",
@@ -35,6 +41,5 @@ optional = true
35
41
  debug-embed = []
36
42
  interpolate-folder-path = ["shellexpand"]
37
43
  compression = []
38
- mime-guess = ["rust-embed-utils/mime-guess"]
39
44
  include-exclude = ["rust-embed-utils/include-exclude"]
40
45
  deterministic-timestamps = []
impl/src/lib.rs CHANGED
@@ -276,13 +276,6 @@ fn embed_file(
276
276
  };
277
277
  (last_modified, created)
278
278
  };
279
- // Always compute and emit the mimetype, without branching on this crate's own
280
- // `mime-guess` feature. This crate is a proc-macro compiled for the host, so
281
- // its features are resolved independently of the target the generated code is
282
- // compiled into. The decision of whether to keep the mimetype is made
283
- // target-side by the `__rust_embed_metadata!` macro in `rust-embed-utils`.
284
- let mimetype = rust_embed_utils::_mimetype_of(Path::new(full_canonical_path));
285
-
286
279
  let embedding_code = if metadata_only {
287
280
  quote! {
288
281
  const BYTES: &'static [u8] = &[];
@@ -311,7 +304,12 @@ fn embed_file(
311
304
 
312
305
  #crate_path::EmbeddedFile {
313
306
  data: ::std::borrow::Cow::Borrowed(&BYTES),
307
+ // The mimetype is computed by a proc macro (so it does not depend
308
+ // on the host's `mime-guess` feature) and passed as the final
309
+ // argument. `__rust_embed_metadata!` is selected target-side: when
310
+ // the target lacks `mime-guess` it drops this argument without ever
311
+ // expanding the `__mimetype_of!` call.
314
- metadata: #crate_path::utils::__rust_embed_metadata!([#(#hash),*], #last_modified, #created, #mimetype)
312
+ metadata: #crate_path::utils::__rust_embed_metadata!([#(#hash),*], #last_modified, #created, #crate_path::__mimetype_of!(#full_canonical_path))
315
313
  }
316
314
  }
317
315
  })
@@ -449,3 +447,21 @@ pub fn derive_input_object(input: TokenStream) -> TokenStream {
449
447
  Err(e) => e.to_compile_error().into(),
450
448
  }
451
449
  }
450
+
451
+ /// Expands to a string literal containing the mimetype of the file at the given
452
+ /// path, guessed from its extension.
453
+ ///
454
+ /// This lives in the proc-macro crate (which depends on `mime_guess`
455
+ /// unconditionally) rather than being computed inside the derive's host-side
456
+ /// logic: the derive must emit tokens that do not depend on the *host*'s
457
+ /// `mime-guess` feature, and this proc macro is invoked only from the
458
+ /// target-side `__rust_embed_metadata!` macro. When the target has `mime-guess`
459
+ /// disabled, the invocation generated by the derive is discarded by that macro
460
+ /// without ever being expanded.
461
+ #[doc(hidden)]
462
+ #[proc_macro]
463
+ pub fn __mimetype_of(input: TokenStream) -> TokenStream {
464
+ let path = parse_macro_input!(input as syn::LitStr).value();
465
+ let mimetype = mime_guess::from_path(&path).first_or_octet_stream().to_string();
466
+ quote! { #mimetype }.into()
467
+ }
utils/src/lib.rs CHANGED
@@ -60,10 +60,10 @@ pub struct Metadata {
60
60
  /// compiled for the *host*, where its `mime-guess` feature is resolved
61
61
  /// independently of the *target* that the generated code is compiled into. It
62
62
  /// must not branch on its own `#[cfg(feature = "mime-guess")]`, since that
63
- /// reflects the host rather than the target. Instead it unconditionally emits
63
+ /// reflects the host rather than the target. Instead it unconditionally emits a
64
- /// all four arguments (including a mimetype string) and defers to this macro,
64
+ /// `__mimetype_of!(...)` call as the final argument and defers to this macro,
65
- /// which *is* compiled for the target and so discards the mimetype when
65
+ /// which *is* compiled for the target. This variant (target has `mime-guess`)
66
- /// `mime-guess` is disabled there.
66
+ /// forwards the argument, expanding the proc macro to the real mimetype.
67
67
  #[cfg(feature = "mime-guess")]
68
68
  #[doc(hidden)]
69
69
  #[macro_export]
@@ -73,7 +73,9 @@ macro_rules! __rust_embed_metadata {
73
73
  };
74
74
  }
75
75
 
76
- /// See the `mime-guess` variant above. This variant drops the mimetype token.
76
+ /// See the `mime-guess` variant above. This variant (target lacks `mime-guess`)
77
+ /// drops the final argument, so the `__mimetype_of!` call it contains is never
78
+ /// expanded.
77
79
  #[cfg(not(feature = "mime-guess"))]
78
80
  #[doc(hidden)]
79
81
  #[macro_export]
@@ -83,25 +85,6 @@ macro_rules! __rust_embed_metadata {
83
85
  };
84
86
  }
85
87
 
86
- /// Computes the mimetype of a file at build time.
87
- ///
88
- /// This is always available (regardless of the `mime-guess` feature) so that
89
- /// the derive macro can unconditionally produce a mimetype token without using
90
- /// `#[cfg(…)]`. The token is only ever used by [`__rust_embed_metadata`] when
91
- /// the target enables `mime-guess`; otherwise the empty string returned here is
92
- /// discarded by the macro.
93
- #[doc(hidden)]
94
- pub fn _mimetype_of(_path: &Path) -> String {
95
- #[cfg(feature = "mime-guess")]
96
- {
97
- mime_guess::from_path(_path).first_or_octet_stream().to_string()
98
- }
99
- #[cfg(not(feature = "mime-guess"))]
100
- {
101
- String::new()
102
- }
103
- }
104
-
105
88
  impl Metadata {
106
89
  #[doc(hidden)]
107
90
  pub const fn __rust_embed_new(