1use std::{borrow::Cow::Borrowed, fs::File, ops::Deref};
2
3use mbed_macros::{Artifact, LocalFile, Writer};
4use tanager::Parse;
5
6#[proc_macro]
7pub fn include_bytes(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
8 #[derive(Debug, Hash, Parse)]
9 #[tanager(transparent)]
10 struct Input(Files);
11
12 impl std::fmt::Display for Input {
13 #[inline]
14 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
15 write!(f, "mbed::include_bytes {}", self.0)
16 }
17 }
18
19 mbed_macros::execute_fn(item.into(), |deps, input: Input| {
20 deps.track_files(&*input.0);
21
22 let mut writer = Writer::new()?;
23
24 for path in input.0.iter() {
25 std::io::copy(&mut File::open(path)?, &mut writer)?;
26 }
27
28 std::io::Result::Ok(Artifact {
29 mime: input
30 .0
31 .first()
32 .map(|x| {
33 mime_guess::from_path(x)
34 .first_or_octet_stream()
35 .to_string()
36 .into()
37 })
38 .unwrap_or(Borrowed("application/octet-stream")),
39
40 ..writer.finish()?
41 })
42 })
43 .into()
44}
45
46#[proc_macro]
47pub fn include_str(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
48 #[derive(Debug, Hash, Parse)]
49 #[tanager(transparent)]
50 struct Input(Files);
51
52 impl std::fmt::Display for Input {
53 #[inline]
54 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
55 write!(f, "mbed::include_str {}", self.0)
56 }
57 }
58
59 mbed_macros::execute_fn(item.into(), |deps, input: Input| {
60 deps.track_files(&*input.0);
61
62 let mut writer = Writer::new()?;
63
64 for path in input.0.iter() {
65 std::io::copy(&mut File::open(path)?, &mut writer)?;
66 }
67
68 std::io::Result::Ok(Artifact {
69 mime: input
70 .0
71 .first()
72 .map(|x| {
73 mime_guess::from_path(x)
74 .first_or_text_plain()
75 .to_string()
76 .into()
77 })
78 .unwrap_or(Borrowed("text/plain")),
79
80 ..writer.finish()?.into_text_artifact()
81 })
82 })
83 .into()
84}
85
86#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Parse)]
87#[tanager(transparent)]
88struct Files(Box<[LocalFile]>);
89
90impl std::fmt::Display for Files {
91 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
92 let cwd = std::env::current_dir().ok();
93
94 let paths = self
95 .0
96 .iter()
97 .map(|x| {
98 cwd.as_ref()
99 .and_then(|cwd| x.strip_prefix(cwd).ok())
100 .unwrap_or(x.as_path())
101 })
102 .map(|x| x.to_string_lossy());
103
104 write!(f, "[ ")?;
105
106 let mut b: usize = 80;
107
108 for (index, path) in paths.enumerate() {
109 if index != 0 {
110 write!(f, ", ")?;
111
112 b = b.saturating_sub(path.len());
113
114 if b != 0 {
115 write!(f, "{path}")?;
116 } else {
117 write!(f, "...")?;
118 }
119 } else {
120 b = b.saturating_sub(path.len());
121
122 write!(f, "{path}")?;
123 }
124 }
125
126 write!(f, " ]")?;
127
128 Ok(())
129 }
130}
131
132impl Deref for Files {
133 type Target = [LocalFile];
134
135 #[inline]
136 fn deref(&self) -> &Self::Target {
137 &self.0
138 }
139}