1/// Same as [`std::vec!`] but converts each element with [`Into`].
2///
3/// **WARNING:** it's not recommended to import this macro into scope. Reference it
4/// using the full path (`bon::vec![]`) to avoid confusion with the [`std::vec!`] macro.
5///
6/// A good example of the use case for this macro is when you want to create a
7/// [`Vec<String>`] where part of the items are hard-coded string literals of type
8/// `&str` and the other part is made of dynamic [`String`] values.
9///
10/// ```
11/// fn convert_media(input_extension: &str, output_extension: &str) -> std::io::Result<()> {
12/// let ffmpeg_args: Vec<String> = bon::vec![
13/// "-i",
14/// format!("input.{input_extension}"),
15/// "-y",
16/// format!("output.{output_extension}"),
17/// ];
18///
19/// std::process::Command::new("ffmpeg").args(ffmpeg_args).output()?;
20///
21/// Ok(())
22/// }
23/// ```
24///
25/// This macro doesn't support `vec![expr; N]` syntax, since it's simpler to
26/// just write `vec![expr.into(); N]` using [`std::vec!`] instead.
27#[macro_export]
28#[cfg(feature = "alloc")]
29#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
30#[allow(edition_2024_expr_fragment_specifier)]
31macro_rules! vec {
32 () => ($crate::__::alloc::vec::Vec::new());
33 ($($item:expr),+ $(,)?) => ($crate::__::alloc::vec![$(::core::convert::Into::into($item)),+ ]);
34}
3536/// Creates a fixed-size array literal with each element converted with [`Into`].
37///
38/// You'll probably need a hint for the target type of items in the array if the
39/// compiler can't infer it from its usage.
40///
41/// This is similar in spirit to the [`bon::vec!`] macro, but it's for arrays.
42/// See [`bon::vec!`] docs for details.
43///
44/// Same example as in [`bon::vec!`], but using this macro. It works with array
45/// as well because [`Command::args`] accepts any value that implements [`IntoIterator`]:
46///
47/// ```
48/// fn convert_media(input_extension: &str, output_extension: &str) -> std::io::Result<()> {
49/// let ffmpeg_args: [String; 4] = bon::arr![
50/// "-i",
51/// format!("input.{input_extension}"),
52/// "-y",
53/// format!("output.{output_extension}"),
54/// ];
55///
56/// std::process::Command::new("ffmpeg").args(ffmpeg_args).output()?;
57///
58/// Ok(())
59/// }
60/// ```
61///
62/// This macro doesn't support `[expr; N]` syntax, since it's simpler to
63/// just write `[expr.into(); N]` instead.
64///
65/// [`Command::args`]: std::process::Command::args
66/// [`bon::vec!`]: crate::vec
67#[macro_export]
68#[allow(edition_2024_expr_fragment_specifier)]
69macro_rules! arr {
70 () => ([]);
71 ($($item:expr),+ $(,)?) => ([$(::core::convert::Into::into($item)),+]);
72}
7374#[cfg(test)]
75mod tests {
76#[cfg(feature = "alloc")]
77use crate::__::alloc::{string::String, vec::Vec};
78use core::num::NonZeroU8;
7980#[cfg(feature = "alloc")]
81 #[test]
82fn arr_of_strings() {
83let actual: [String; 3] = crate::arr!["foo", "bar", "baz"];
84assert_eq!(actual, ["foo", "bar", "baz"]);
8586let actual: [String; 0] = crate::arr![];
87assert!(actual.is_empty());
88 }
8990#[test]
91fn arr_of_numbers() {
92let actual: [u8; 2] = crate::arr![NonZeroU8::new(1).unwrap(), NonZeroU8::new(2).unwrap()];
93assert_eq!(actual, [1, 2]);
9495let actual: [u8; 0] = crate::arr![];
96assert!(actual.is_empty());
97 }
9899#[cfg(feature = "alloc")]
100 #[test]
101fn vec_smoke() {
102let actual: Vec<String> = crate::vec!["foo", "bar", "baz"];
103assert_eq!(actual, ["foo", "bar", "baz"]);
104105let actual: Vec<String> = crate::vec![];
106assert!(actual.is_empty());
107 }
108109#[cfg(feature = "std")]
110 #[test]
111fn map_smoke() {
112use std::collections::{BTreeMap, HashMap};
113114let hash_strings: HashMap<String, String> = crate::map! {
115"Hello": "World",
116"Goodbye": "Mars",
117 };
118119assert_eq!(hash_strings["Hello"], "World");
120assert_eq!(hash_strings["Goodbye"], "Mars");
121122let tree_strings: BTreeMap<String, String> = crate::map! {
123"Hello": "World",
124"Goodbye": "Mars",
125 };
126127assert_eq!(tree_strings["Hello"], "World");
128assert_eq!(tree_strings["Goodbye"], "Mars");
129 }
130131#[cfg(feature = "std")]
132 #[test]
133fn set_smoke() {
134use std::collections::BTreeSet;
135use std::collections::HashSet;
136137let hash_strings: HashSet<String> = crate::set!["Hello", "World", "Goodbye", "Mars"];
138139assert!(hash_strings.contains("Hello"));
140assert!(hash_strings.contains("World"));
141assert!(hash_strings.contains("Goodbye"));
142assert!(hash_strings.contains("Mars"));
143144let tree_strings: BTreeSet<String> = crate::set!["Hello", "World", "Goodbye", "Mars"];
145146assert!(tree_strings.contains("Hello"));
147assert!(tree_strings.contains("World"));
148assert!(tree_strings.contains("Goodbye"));
149assert!(tree_strings.contains("Mars"));
150 }
151}