it: works
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1 +1,3 @@
|
|||||||
/target
|
/target
|
||||||
|
|
||||||
|
Cargo.lock
|
||||||
|
|||||||
7
Cargo.lock
generated
7
Cargo.lock
generated
@@ -1,7 +0,0 @@
|
|||||||
# This file is automatically @generated by Cargo.
|
|
||||||
# It is not intended for manual editing.
|
|
||||||
version = 4
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "const-macros"
|
|
||||||
version = "0.1.0"
|
|
||||||
@@ -9,10 +9,8 @@ repository = "https://git.javalsai.tuxcord.net/rust/const-macros"
|
|||||||
keywords = ["compile", "const", "macro"]
|
keywords = ["compile", "const", "macro"]
|
||||||
categories = ["development-tools::procedural-macro-helpers"]
|
categories = ["development-tools::procedural-macro-helpers"]
|
||||||
|
|
||||||
[lib]
|
|
||||||
proc-macro = true
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
const-macros-proc = { path = "./const-macros-proc" }
|
||||||
|
|
||||||
[lints.clippy]
|
[lints.clippy]
|
||||||
cargo = { level = "warn", priority = -1 }
|
cargo = { level = "warn", priority = -1 }
|
||||||
|
|||||||
1
assets/DATA1
Normal file
1
assets/DATA1
Normal file
@@ -0,0 +1 @@
|
|||||||
|
This is just a bunch of bytes that will hash to a known sequence and I can test for validity
|
||||||
BIN
assets/DATA2
Normal file
BIN
assets/DATA2
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 67 B |
1
const-macros-proc/.gitignore
vendored
Normal file
1
const-macros-proc/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/target
|
||||||
11
const-macros-proc/Cargo.toml
Normal file
11
const-macros-proc/Cargo.toml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
[package]
|
||||||
|
name = "const-macros-proc"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
proc-macro = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
magic = "0.16"
|
||||||
|
sha2 = "0.10"
|
||||||
126
const-macros-proc/src/lib.rs
Normal file
126
const-macros-proc/src/lib.rs
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
#![feature(proc_macro_value)]
|
||||||
|
use std::{fs::File, io::Read};
|
||||||
|
|
||||||
|
use proc_macro::{Delimiter, Group, Literal, Punct, TokenStream, TokenTree};
|
||||||
|
use sha2::Digest;
|
||||||
|
|
||||||
|
fn read_path_literal(input: TokenStream) -> String {
|
||||||
|
println!("{input:?}");
|
||||||
|
let mut input_iter = input.into_iter();
|
||||||
|
let path_token = input_iter.next().expect("expected a path");
|
||||||
|
assert!(input_iter.next().is_none(), "only expected one argument");
|
||||||
|
|
||||||
|
let path_literal = match path_token {
|
||||||
|
TokenTree::Group(path_group) => {
|
||||||
|
let mut path_stream = path_group.stream().into_iter();
|
||||||
|
let path_literal = path_stream.next().expect("expected a str literal");
|
||||||
|
assert!(path_stream.next().is_none(), "expected a str literal");
|
||||||
|
|
||||||
|
let TokenTree::Literal(path_literal) = path_literal else {
|
||||||
|
panic!("expected a str literal");
|
||||||
|
};
|
||||||
|
|
||||||
|
path_literal
|
||||||
|
}
|
||||||
|
TokenTree::Literal(path_literal) => path_literal,
|
||||||
|
_ => panic!("expected a str literal"),
|
||||||
|
};
|
||||||
|
|
||||||
|
// eprintln!("{path_literal:?}");
|
||||||
|
path_literal.str_value().expect("expected a str literal")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extend_grouped(
|
||||||
|
ts: &mut TokenStream,
|
||||||
|
delim: Delimiter,
|
||||||
|
items: impl Iterator<Item = TokenStream>,
|
||||||
|
) {
|
||||||
|
let mut comma_ts = TokenStream::new();
|
||||||
|
comma_ts.extend(std::iter::once(TokenTree::Punct(Punct::new(
|
||||||
|
',',
|
||||||
|
proc_macro::Spacing::Alone,
|
||||||
|
))));
|
||||||
|
|
||||||
|
let mut tuple_content = TokenStream::new();
|
||||||
|
tuple_content.extend(items.flat_map(|token| [token, comma_ts.clone()]));
|
||||||
|
|
||||||
|
ts.extend(std::iter::once(TokenTree::Group(Group::new(
|
||||||
|
delim,
|
||||||
|
tuple_content,
|
||||||
|
))));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extend_array(ts: &mut TokenStream, array: &[u8]) {
|
||||||
|
extend_grouped(
|
||||||
|
ts,
|
||||||
|
Delimiter::Bracket,
|
||||||
|
array.iter().map(|&b| {
|
||||||
|
let mut ts = TokenStream::new();
|
||||||
|
ts.extend(std::iter::once(TokenTree::Literal(Literal::u8_unsuffixed(
|
||||||
|
b,
|
||||||
|
))));
|
||||||
|
ts
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extend_asset_tuple(ts: &mut TokenStream, buf: &[u8], mime: &str, sha256sum: [u8; 32]) {
|
||||||
|
extend_grouped(
|
||||||
|
ts,
|
||||||
|
Delimiter::Parenthesis,
|
||||||
|
[
|
||||||
|
{
|
||||||
|
let mut ts = TokenStream::new();
|
||||||
|
ts.extend(std::iter::once(TokenTree::Punct(Punct::new(
|
||||||
|
'&',
|
||||||
|
proc_macro::Spacing::Joint,
|
||||||
|
))));
|
||||||
|
extend_array(&mut ts, buf);
|
||||||
|
ts
|
||||||
|
},
|
||||||
|
{
|
||||||
|
let mut ts = TokenStream::new();
|
||||||
|
ts.extend(std::iter::once(Literal::string(mime)));
|
||||||
|
ts
|
||||||
|
},
|
||||||
|
{
|
||||||
|
let mut ts = TokenStream::new();
|
||||||
|
extend_array(&mut ts, &sha256sum);
|
||||||
|
ts
|
||||||
|
},
|
||||||
|
]
|
||||||
|
.into_iter(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_mime(buf: &[u8]) -> String {
|
||||||
|
let cookie =
|
||||||
|
magic::Cookie::open(magic::cookie::Flags::MIME).expect("failure opening mime cookie");
|
||||||
|
let cookie = cookie
|
||||||
|
.load(&magic::cookie::DatabasePaths::default())
|
||||||
|
.expect("failure loading magic db");
|
||||||
|
|
||||||
|
cookie.buffer(buf).expect("error getting file mime")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_sha256sum(buf: &[u8]) -> [u8; 32] {
|
||||||
|
sha2::Sha256::digest(buf)
|
||||||
|
.as_slice()
|
||||||
|
.try_into()
|
||||||
|
.expect("failed to sha256sum file")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[proc_macro]
|
||||||
|
#[allow(clippy::missing_panics_doc)]
|
||||||
|
pub fn include_asset(input: TokenStream) -> TokenStream {
|
||||||
|
let path = read_path_literal(input);
|
||||||
|
let mut buf = Vec::new();
|
||||||
|
File::open(path)
|
||||||
|
.expect("couldn't open file")
|
||||||
|
.read_to_end(&mut buf)
|
||||||
|
.expect("error reading file");
|
||||||
|
|
||||||
|
let mut ts = TokenStream::new();
|
||||||
|
extend_asset_tuple(&mut ts, &buf, &get_mime(&buf), get_sha256sum(&buf));
|
||||||
|
ts
|
||||||
|
}
|
||||||
72
src/lib.rs
72
src/lib.rs
@@ -1,15 +1,61 @@
|
|||||||
// #[must_use]
|
// So hand working with [`TokenStream`] might be a bad idea BUT I partially made this crate to
|
||||||
// pub const fn add(left: u64, right: u64) -> u64 {
|
// learn about [`proc_macro`] so I'm not gonna use [`quote`] or [`syn`]
|
||||||
// left + right
|
|
||||||
// }
|
|
||||||
|
|
||||||
// #[cfg(test)]
|
pub mod file {
|
||||||
// mod tests {
|
pub type IncludeAssetMacroTy = (&'static [u8], &'static str, [u8; 32]);
|
||||||
// use super::*;
|
|
||||||
|
|
||||||
// #[test]
|
pub struct FileAsset {
|
||||||
// fn it_works() {
|
pub bytes: &'static [u8],
|
||||||
// let result = add(2, 2);
|
pub mime: &'static str,
|
||||||
// assert_eq!(result, 4);
|
pub shasum: [u8; 32],
|
||||||
// }
|
}
|
||||||
// }
|
|
||||||
|
impl FileAsset {
|
||||||
|
#[must_use]
|
||||||
|
pub const fn from_tuple(tuple: IncludeAssetMacroTy) -> Self {
|
||||||
|
Self {
|
||||||
|
bytes: tuple.0,
|
||||||
|
mime: tuple.1,
|
||||||
|
shasum: tuple.2,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<IncludeAssetMacroTy> for FileAsset {
|
||||||
|
fn from(value: (&'static [u8], &'static str, [u8; 32])) -> Self {
|
||||||
|
Self::from_tuple(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! include_asset {
|
||||||
|
($path:literal) => {
|
||||||
|
$crate::file::FileAsset::from_tuple($crate::file::_include_asset!($path))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
pub use include_asset;
|
||||||
|
|
||||||
|
pub use const_macros_proc::include_asset as _include_asset;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
pub mod test {
|
||||||
|
#[test]
|
||||||
|
fn works() {
|
||||||
|
const ASSET1: super::FileAsset = super::include_asset!("assets/DATA1");
|
||||||
|
const ASSET2: super::FileAsset = super::include_asset!("assets/DATA2");
|
||||||
|
|
||||||
|
assert_eq!(ASSET1.bytes, b"This is just a bunch of bytes that will hash to a known sequence and I can test for validity\n");
|
||||||
|
assert_eq!(ASSET1.mime, "text/plain; charset=us-ascii");
|
||||||
|
assert_eq!(
|
||||||
|
ASSET1.shasum,
|
||||||
|
[
|
||||||
|
0x4f, 0x72, 0xae, 0x5a, 0x7e, 0x2d, 0x70, 0xfe, 0xc4, 0x13, 0xaf, 0x0e, 0x29,
|
||||||
|
0x8f, 0x1b, 0x7a, 0x7c, 0x1d, 0x8d, 0x9c, 0xaf, 0x4f, 0xd6, 0x24, 0x46, 0x0d,
|
||||||
|
0x2f, 0xe2, 0xd8, 0x1b, 0x83, 0x28,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(ASSET2.mime, "image/png; charset=binary");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user