1#![forbid(unsafe_code)]
9#![forbid(non_fmt_panics)]
10#![deny(missing_docs)]
11#![deny(rustdoc::missing_crate_level_docs)]
12#![warn(rustdoc::missing_doc_code_examples)]
13#![deny(rustdoc::invalid_codeblock_attributes)]
14#![warn(rustdoc::broken_intra_doc_links)]
15#![warn(rustdoc::private_intra_doc_links)]
16#![warn(rustdoc::unescaped_backticks)]
17#![allow(rustdoc::private_doc_tests)]
18#![allow(unused_parens)]
19#![allow(non_camel_case_types)]
20
21extern crate proc_macro;
33use proc_macro::TokenStream;
34
35use syn::{parse_macro_input, LitByteStr, LitStr};
37use syn::parse::{Parse, ParseStream};
38use quote::quote;
39use std::fmt;
40
41
42#[derive(Debug)]
49struct MacroArgumentsAR {
50 id: String,
52 content: StrOrByte,
54 len: Option<usize>
56}
57
58impl Parse for MacroArgumentsAR {
59 fn parse(input: ParseStream) -> syn::Result<Self> {
60 use syn::Ident;
61 use syn::Token;
62 use syn::LitInt;
63 let ident: Ident = input.parse()?;
64 let _comma: Token![,] = input.parse()?;
65 let payload: StrOrByte = input.parse()?;
66 let maybecomma: Result<Token![,],_> = input.parse();
68 let maybesize: Result<LitInt,_> = input.parse();
69 let maybeusizedlen =
70 if maybesize.is_ok() && maybecomma.is_ok() {
71 maybesize.unwrap().base10_parse::<usize>()
73 } else {
74 Err(syn::Error::new(input.span(), "Failed to parse size as usize"))
75 };
76 match( maybeusizedlen ) {
77 Err(e) =>
78 if (maybecomma.is_ok()) {
79 Err(e)
80 } else {
81 Ok(MacroArgumentsAR { id: ident.to_string(), content: payload, len: None })
82 },
83 Ok(expectedlen) => Ok(MacroArgumentsAR { id: ident.to_string(), content: payload, len: Some(expectedlen) })
84 }
85 }
86}
87
88#[proc_macro]
124pub fn str_array(tokens: TokenStream) -> TokenStream {
125 let input: MacroArgumentsAR = parse_macro_input!(tokens as MacroArgumentsAR);
126 let id = syn::Ident::new(&input.id, proc_macro2::Span::from(proc_macro::Span::call_site()));
127 let u8s = input.content.as_bytes();
128 let mut len = u8s.len();
129 if let Some(expectedlen) = input.len {
130 len = expectedlen;
131 };
132
133 proc_macro::TokenStream::from(
134 quote! {
135 const #id: [u8; #len] = [ #(#u8s),* ];
136 })
137}
138
139#[proc_macro]
167pub fn str_array0(tokens: TokenStream) -> TokenStream {
168 let input: MacroArgumentsAR = parse_macro_input!(tokens as MacroArgumentsAR);
169 let id = syn::Ident::new(&input.id, proc_macro::Span::call_site().into());
170 let u8s = input.content.add0().as_bytes();
171 let mut len = u8s.len();
172 if let Some(expectedlen) = input.len {
173 len = expectedlen;
174 };
175 proc_macro::TokenStream::from(
176 quote! {
177 const #id: [ u8; #len ] = [ #(#u8s),* ];
178 })
179}
180
181
182#[proc_macro]
204pub fn str_len(tokens: TokenStream) -> TokenStream {
205 let input = parse_macro_input!(tokens as StrOrByte);
206 let len = input.as_bytes().len();
207 proc_macro::TokenStream::from(
208 quote! {
209 #len
210 })
211}
212
213#[proc_macro]
231pub fn str_len0(tokens: TokenStream) -> TokenStream {
232 let input = parse_macro_input!(tokens as StrOrByte);
233 let len = 1 + input.as_bytes().len();
234
235 proc_macro::TokenStream::from(
236 quote! {
237 #len
238 })
239}
240
241
242enum StrOrByte {
247 str(LitStr),
248 byte(LitByteStr)
249}
250
251impl fmt::Debug for StrOrByte {
252 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
253 match self {
254 StrOrByte::str(lit_str) => write!(f, "Str({:?})", lit_str.value()),
255 StrOrByte::byte(lit_byte_str) => write!(f, "Byte({:?})", std::str::from_utf8(&lit_byte_str.value()).map_err(|_| fmt::Error)?),
256 }
257 }
258}
259
260impl PartialEq<StrOrByte> for StrOrByte {
261 fn eq(&self, other: &Self) -> bool {
262 match (self, other) {
263 (StrOrByte::str(a), StrOrByte::str(b)) => a.value() == b.value(),
264 (StrOrByte::byte(a), StrOrByte::byte(b)) => a.value() == b.value(),
265 _ => false,
266 }
267 }
268}
269
270impl PartialEq<&str> for StrOrByte {
271 fn eq(&self, other: &&str) -> bool {
272 match self {
273 StrOrByte::str(lit_str) => lit_str.value() == *other,
274 _ => false
275 }
276 }
277}
278
279impl PartialEq<&[u8]> for StrOrByte {
280 fn eq(&self, other: &&[u8]) -> bool {
281 match self {
282 StrOrByte::byte(lit_byte) => lit_byte.value() == *other,
283 _ => false
284 }
285 }
286}
287
288impl Parse for StrOrByte {
289 fn parse(input: ParseStream) -> syn::Result<Self> {
290 if input.peek(LitStr) {
291 let lit_str: LitStr = input.parse()?;
292 Ok(StrOrByte::str(lit_str))
293 } else {
294 let lit_bytestr: LitByteStr = input.parse()?;
295 Ok(StrOrByte::byte(lit_bytestr))
296 }
297 }
298}
299
300impl quote::ToTokens for StrOrByte {
301 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
302 match self {
303 StrOrByte::str(lit_str) => lit_str.to_tokens(tokens),
304 StrOrByte::byte(lit_byte_str) => lit_byte_str.to_tokens(tokens),
305 }
306 }
307}
308
309impl StrOrByte {
310 fn repeat(&self, times: usize) -> Self {
311 match self {
312 StrOrByte::str(lit_str) => {
313 let repeated = lit_str.value().repeat(times);
314 StrOrByte::str(LitStr::new(&repeated, lit_str.span()))
315 },
316 StrOrByte::byte(lit_byte_str) => {
317 let repeated_bytes = lit_byte_str.value().repeat(times);
318 StrOrByte::byte(LitByteStr::new(&repeated_bytes, lit_byte_str.span()))
319 },
320 }
321 }
322 fn add0(&self) -> Self {
323 match self {
324 StrOrByte::str(lit_str) => {
325 let with_null = format!("{}\0", lit_str.value());
326 StrOrByte::str(LitStr::new(&with_null, lit_str.span()))
327 },
328 StrOrByte::byte(lit_byte_str) => {
329 let mut with_null = lit_byte_str.value().clone();
330 with_null.push(0 as u8);
331 StrOrByte::byte(LitByteStr::new(&with_null, lit_byte_str.span()))
332 },
333 }
334 }
335 fn as_bytes(&self) -> Vec<u8> {
336 match self {
337 StrOrByte::str(lit_str) => lit_str.value().as_bytes().to_vec(),
338 StrOrByte::byte(lit_byte_str) => lit_byte_str.value()
339 }
340 }
341}
342
343#[derive(Debug)]
344struct MacroArgumentsRP {
345 content: StrOrByte,
346 times: usize
347}
348
349impl Parse for MacroArgumentsRP {
350 fn parse(input: ParseStream) -> syn::Result<Self> {
351 use syn::Token;
352 use syn::LitInt;
353 let payload: StrOrByte = input.parse()?;
354 let _comma: Token![,] = input.parse()?;
355 let times: usize = input.parse::<LitInt>()?.base10_parse::<usize>()?;
356 Ok(MacroArgumentsRP { content: payload, times })
357 }
358}
359
360#[proc_macro]
381pub fn str_repeat(tokens: TokenStream) -> TokenStream {
382 let input: MacroArgumentsRP = parse_macro_input!(tokens as MacroArgumentsRP);
383 let payload = input.content.repeat(input.times);
384
385 proc_macro::TokenStream::from(
386 quote! {
387 #payload
388 })
389}
390
391#[proc_macro]
409pub fn str_repeat0(tokens: TokenStream) -> TokenStream {
410 let input: MacroArgumentsRP = parse_macro_input!(tokens as MacroArgumentsRP);
411 let payload = input.content.repeat(input.times).add0();
412
413 proc_macro::TokenStream::from(
414 quote! {
415 #payload
416 })
417}
418
419#[proc_macro]
439pub fn str_repeat_bytes(tokens: TokenStream) -> TokenStream {
440 let input: MacroArgumentsRP = parse_macro_input!(tokens as MacroArgumentsRP);
441 let bytes = input.content.repeat(input.times).as_bytes();
442
443 proc_macro::TokenStream::from(
444 quote! { &[#(#bytes),*] }
445 )
446}
447
448#[proc_macro]
468pub fn str_repeat_bytes0(tokens: TokenStream) -> TokenStream {
469 let input: MacroArgumentsRP = parse_macro_input!(tokens as MacroArgumentsRP);
470 let bytes = input.content.repeat(input.times).add0().as_bytes();
471
472 proc_macro::TokenStream::from(
473 quote! { &[#(#bytes),*] }
474 )
475}
476
477#[proc_macro]
489pub fn str_bytes(tokens: TokenStream) -> TokenStream {
490 let input = parse_macro_input!(tokens as StrOrByte);
491 let bytes = input.as_bytes();
492 proc_macro::TokenStream::from(
493 quote! { &[#(#bytes),*] }
494 )
495}
496
497#[proc_macro]
509pub fn str_bytes0(tokens: TokenStream) -> TokenStream {
510 let input = parse_macro_input!(tokens as StrOrByte);
511 let bytes = input.add0().as_bytes();
512 proc_macro::TokenStream::from(
513 quote! { &[#(#bytes),*] }
514 )
515}
516
517#[cfg(test)]
518#[path= "./macro_tests.rs"]
519mod tests;
520
521#[cfg(test)]
522#[path= "./macro_parseAR_tests.rs"]
523mod ARparsetests;
524
525#[cfg(test)]
526#[path= "./macro_parseRP_tests.rs"]
527mod RPparsetests;
528
529#[cfg(test)]
530#[path= "./macro_strorbyte_tests.rs"]
531mod SoBparsetests;
532
533#[cfg(doctest)]
534#[path= "./macro_sized_tests.rs"]
535mod sizedtests;
536
537#[cfg(doctest)]
538#[path= "./macro_0sized_tests.rs"]
539mod zerosizedtests;