const_gen/
lib.rs

1#![cfg_attr(all(not(feature = "std"), not(test)), no_std)]
2#![doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/README.md"))]
3#![forbid(clippy::format_push_string)]
4
5use core::net::*;
6
7#[cfg(not(feature = "std"))]
8include!("no_std.rs");
9#[cfg(feature = "std")]
10use std::{borrow::Cow, collections::HashSet, fmt::Display, rc::Rc, sync::Arc};
11
12#[cfg(feature = "phf")]
13use std::collections::HashMap;
14
15#[cfg(feature = "derive")]
16pub use const_gen_derive::*;
17
18#[cfg(test)]
19mod test;
20
21#[cfg(feature = "either")]
22mod either;
23
24/// A macro to help in the creation of const definitions. Allows this syntax:
25/// `const_definition!(#[attribute1] #[attributeN] visibility TypeName)`
26/// This is syntactic sugar for calling the `CompileConst::const_definition`
27/// function.
28#[macro_export]
29macro_rules! const_definition
30{
31    ( $(#[$attr:meta])* $vis:vis $ty:ty) =>
32    {
33        <$ty>::const_definition(stringify!($(#[$attr])*), stringify!($vis))
34    }
35}
36
37/// A macro to help in the creation of const declarations. Allows this syntax:
38/// `const_declaration!(visibility VAR_NAME = value)`
39/// This is syntactic sugar for calling the `CompileConst::const_declaration`
40/// function.
41#[macro_export]
42macro_rules! const_declaration
43{
44    ( $(#[$attr:meta])* $vis:vis $name:ident = $($val:tt)*) =>
45    {
46        $($val)*.const_declaration(stringify!($(#[$attr])*), stringify!($vis), stringify!($name))
47    }
48}
49
50/// A macro to help in the creation of static declarations. Allows this syntax:
51/// `static_declaration!(visibility VAR_NAME = value)`
52/// This is syntactic sugar for calling the `CompileConst::static_declaration`
53/// function.
54#[macro_export]
55macro_rules! static_declaration
56{
57    ( $(#[$attr:meta])* $vis:vis $name:ident = $($val:tt)*) =>
58    {
59        $($val)*.static_declaration(stringify!($(#[$attr])*), stringify!($vis), stringify!($name))
60    }
61}
62
63/// Like const_declaration, but for const array types
64#[macro_export]
65macro_rules! const_array_declaration
66{
67    ( $(#[$attr:meta])* $vis:vis $name:ident = $($val:tt)*) =>
68    {
69        $($val)*.const_array_declaration(stringify!($(#[$attr])*), stringify!($vis), stringify!($name))
70    }
71}
72
73/// Like static_declaration, but for const array types
74#[macro_export]
75macro_rules! static_array_declaration
76{
77    ( $(#[$attr:meta])* $vis:vis $name:ident = $($val:tt)*) =>
78    {
79        $($val)*.static_array_declaration(stringify!($(#[$attr])*), stringify!($vis), stringify!($name))
80    }
81}
82
83/// Enum representing the type of declaration to generate, e.g. `const` or `static`.
84#[derive(Debug, Copy, Clone, Eq, PartialEq)]
85pub enum DeclarationType {
86    Const,
87    Static,
88}
89
90impl Display for DeclarationType {
91    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
92        f.write_str(match self {
93            DeclarationType::Const => "const",
94            DeclarationType::Static => "static",
95        })
96    }
97}
98
99/// Trait which defines how a type should be represented as a constant
100pub trait CompileConst {
101    /// Get a string representation of a type. This must be implemented for each
102    /// type. Note that this is not necessarily a representation
103    /// of the ACTUAL type, but rather the type that should be used if this data
104    /// is going to be represented as a compile-time constant.
105    fn const_type() -> String;
106    /// Get a string representation of the current value in constant form.
107    fn const_val(&self) -> String;
108    /// Generates the declaration statement string.
109    ///
110    /// Takes 3 strings: Attributes, a visibility (eg pub) and a name (a SCREAMING_SNAKE_CASE string is preferred),
111    /// plus a [declaration type](DeclarationType) (e.g. const or static).
112    ///
113    /// It then constructs a valid Rust declaration statement using the type and value of the current object by calling [const_val()](CompileConst::const_val) and [const_type()](CompileConst::const_type).
114    ///
115    ///```rust
116    /// use const_gen::{CompileConst, DeclarationType};
117    ///
118    /// let test_str_declaration = "I'm a string!".declaration(
119    ///    "#[allow(dead_code)]",
120    ///    "pub(crate)",
121    ///    DeclarationType::Const,
122    ///    "TEST_STR",
123    /// );
124    /// assert_eq!(
125    ///    test_str_declaration,
126    ///    r#"#[allow(dead_code)] pub(crate) const TEST_STR: &str = "I'm a string!";"#
127    /// );
128    ///```
129    fn declaration(
130        &self,
131        attrs: &str,
132        vis: &str,
133        declaration_type: DeclarationType,
134        name: &str,
135    ) -> String {
136        format!(
137            "{}{}{}{}{} {}: {} = {};",
138            if attrs.is_empty() { "" } else { attrs },
139            if attrs.is_empty() { "" } else { " " },
140            vis,
141            if vis.is_empty() { "" } else { " " },
142            declaration_type,
143            name,
144            Self::const_type(),
145            self.const_val()
146        )
147    }
148    /// Generates the declaration statement string for a `const` declaration.
149    ///
150    /// See [declaration()](CompileConst::declaration) for more information.
151    fn const_declaration(&self, attrs: &str, vis: &str, name: &str) -> String {
152        self.declaration(attrs, vis, DeclarationType::Const, name)
153    }
154    /// Generates the declaration statement string for a `static` declaration.
155    ///
156    /// See [declaration()](CompileConst::declaration) for more information.
157    fn static_declaration(&self, attrs: &str, vis: &str, name: &str) -> String {
158        self.declaration(attrs, vis, DeclarationType::Static, name)
159    }
160    /// Return a const definition for this type. Attributes may be included, and
161    /// must be formatted as the compiler would expect to see them (including
162    /// the pound sign and square brackets `"#[...]"`). Always returns an empty
163    /// string for types defined in the standard library. Typically this is
164    /// easier to call instead through the const_definition! macro. Visibility
165    /// modifiers (eg, pub(...)) may be used, or an empty string passed in to
166    /// generate a private item.
167    fn const_definition(_attrs: &str, _vis: &str) -> String {
168        String::new()
169    }
170}
171
172/// Trait which defines how an array-representable type should be represented as a const array
173pub trait CompileConstArray {
174    /// Like [const_type](CompileConst::const_type), but for a fixed-size array.
175    fn const_array_type(&self) -> String;
176    /// Like [const_val](CompileConst::const_val), but for a fixed-size array.
177    fn const_array_val(&self) -> String;
178    /// Like [declaration](CompileConst::declaration), but for a fixed-size array.
179    fn array_declaration(
180        &self,
181        attrs: &str,
182        vis: &str,
183        declaration_type: DeclarationType,
184        name: &str,
185    ) -> String {
186        format!(
187            "{}{}{}{}{} {}: {} = {};",
188            if attrs.is_empty() { "" } else { attrs },
189            if attrs.is_empty() { "" } else { " " },
190            vis,
191            if vis.is_empty() { "" } else { " " },
192            declaration_type,
193            name,
194            self.const_array_type(),
195            self.const_array_val()
196        )
197    }
198
199    /// Like [const_declaration](CompileConst::const_declaration), but for a fixed-size array.
200    fn const_array_declaration(&self, attrs: &str, vis: &str, name: &str) -> String {
201        self.array_declaration(attrs, vis, DeclarationType::Const, name)
202    }
203    /// Like [static_declaration](CompileConst::static_declaration), but for a fixed-size array.
204    fn static_array_declaration(&self, attrs: &str, vis: &str, name: &str) -> String {
205        self.array_declaration(attrs, vis, DeclarationType::Static, name)
206    }
207}
208
209macro_rules! numerics
210{
211    ( $($t:ty),* ) =>
212    {
213        $(impl CompileConst for $t
214        {
215            fn const_type() -> String
216            {
217                stringify!($t).to_string()
218            }
219
220            fn const_val(&self) -> String
221            {
222                format!("{}{}", self, stringify!($t))
223            }
224        })*
225    }
226}
227numerics!(u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64);
228
229macro_rules! strings
230{
231    ( $($t:ty),* ) =>
232    {
233        $(
234        impl CompileConst for $t
235        {
236            fn const_type() -> String
237            {
238                "&'static str".to_string()
239            }
240
241            fn const_val(&self) -> String
242            {
243                format!("\"{}\"", self)
244            }
245        }
246        impl CompileConstArray for $t
247        {
248            fn const_array_type(&self) -> String
249            {
250                format!("[char; {}]", self.chars().count())
251            }
252
253            fn const_array_val(&self) -> String
254            {
255                format!("[{}]", self.chars().map(|c| format!("'{}',", c)).collect::<Vec<String>>().concat())
256            }
257        }
258        )*
259    }
260}
261strings!(String, &str, str);
262
263macro_rules! slices
264{
265    ( $($t:ty),* ) =>
266    {
267        $(
268        impl<T: CompileConst> CompileConst for $t
269        {
270            fn const_type() -> String
271            {
272                format!("&'static [{}]", T::const_type())
273            }
274
275            fn const_val(&self) -> String
276            {
277                format!("&[{}]", self
278                    .into_iter()
279                    .map(|e| e.const_val())
280                    .collect::<Vec<String>>()
281                    .join(","))
282            }
283        }
284        impl<T: CompileConst> CompileConstArray for $t
285        {
286            fn const_array_type(&self) -> String
287            {
288                format!("[{}; {}]", T::const_type(), self.iter().count())
289            }
290
291            fn const_array_val(&self) -> String
292            {
293                format!("[{}]", self
294                    .into_iter()
295                    .map(|e| e.const_val())
296                    .collect::<Vec<String>>()
297                    .join(","))
298            }
299        }
300        )*
301    }
302}
303slices!(Vec<T>, &[T]);
304
305macro_rules! derefs
306{
307    ( $($t:ty $(=> $bound:tt)?),* ) =>
308    {
309        $(
310        impl<T: CompileConst $(+ $bound)? > CompileConst for $t
311        {
312            fn const_type() -> String
313            {
314                T::const_type()
315            }
316            fn const_val(&self) -> String
317            {
318                (**self).const_val()
319            }
320        }
321        impl<T: CompileConstArray $(+ $bound)? > CompileConstArray for $t
322        {
323            fn const_array_type(&self) -> String
324            {
325                (**self).const_array_type()
326            }
327
328            fn const_array_val(&self) -> String
329            {
330                (**self).const_array_val()
331            }
332        }
333        )*
334    }
335}
336derefs!(
337    Box<T>,
338    Cow<'_, T> => Clone,
339    Rc<T>,
340    Arc<T>
341);
342
343impl CompileConst for char {
344    fn const_type() -> String {
345        "char".to_owned()
346    }
347
348    fn const_val(&self) -> String {
349        format!("'{}'", *self)
350    }
351}
352
353impl CompileConst for bool {
354    fn const_type() -> String {
355        "bool".to_owned()
356    }
357
358    fn const_val(&self) -> String {
359        if *self { "true" } else { "false" }.to_owned()
360    }
361}
362
363impl<T: CompileConst> CompileConst for Option<T> {
364    fn const_type() -> String {
365        format!("Option<{}>", T::const_type())
366    }
367
368    fn const_val(&self) -> String {
369        match self {
370            Some(t) => format!("Some({})", t.const_val()),
371            None => String::from("None"),
372        }
373    }
374}
375
376#[cfg(feature = "phf")]
377impl<K: CompileConst, V: CompileConst> CompileConst for HashMap<K, V> {
378    fn const_type() -> String {
379        format!("phf::Map<{}, {}>", K::const_type(), V::const_type())
380    }
381
382    fn const_val(&self) -> String {
383        format!(
384            "phf::phf_map!{{{}}}",
385            self.iter()
386                .map(|(k, v)| format!("{} => {}", k.const_val(), v.const_val()))
387                .collect::<Vec<String>>()
388                .join(",")
389        )
390    }
391}
392
393#[cfg(feature = "phf")]
394impl<E: CompileConst> CompileConst for HashSet<E> {
395    fn const_type() -> String {
396        format!("phf::Set<{}>", E::const_type())
397    }
398
399    fn const_val(&self) -> String {
400        format!(
401            "phf::phf_set!{{{}}}",
402            self.iter()
403                .map(|e| e.const_val().to_string())
404                .collect::<Vec<String>>()
405                .join(",")
406        )
407    }
408}
409
410impl CompileConst for Ipv4Addr {
411    fn const_type() -> String {
412        "core::net::Ipv4Addr".to_owned()
413    }
414
415    fn const_val(&self) -> String {
416        format!(
417            "core::net::Ipv4Addr::new({})",
418            self.octets()
419                .iter()
420                .map(|x| x.to_string())
421                .collect::<Vec<String>>()
422                .join(",")
423        )
424    }
425}
426
427impl CompileConst for Ipv6Addr {
428    fn const_type() -> String {
429        "core::net::Ipv6Addr".to_owned()
430    }
431
432    fn const_val(&self) -> String {
433        format!(
434            "core::net::Ipv6Addr::new({})",
435            self.segments()
436                .iter()
437                .map(|x| x.to_string())
438                .collect::<Vec<String>>()
439                .join(",")
440        )
441    }
442}
443
444impl CompileConst for IpAddr {
445    fn const_type() -> String {
446        "core::net::IpAddr".to_owned()
447    }
448
449    fn const_val(&self) -> String {
450        match self {
451            IpAddr::V4(ipv4) => format!("core::net::IpAddr::V4({})", ipv4.const_val()),
452            IpAddr::V6(ipv6) => format!("core::net::IpAddr::V6({})", ipv6.const_val()),
453        }
454    }
455}
456
457impl CompileConst for SocketAddr {
458    fn const_type() -> String {
459        "core::net::SocketAddr".to_owned()
460    }
461
462    fn const_val(&self) -> String {
463        format!(
464            "core::net::SocketAddr::new({}, {})",
465            self.ip().const_val(),
466            self.port()
467        )
468    }
469}
470
471impl CompileConst for SocketAddrV4 {
472    fn const_type() -> String {
473        "core::net::SocketAddrV4".to_owned()
474    }
475
476    fn const_val(&self) -> String {
477        format!(
478            "core::net::SocketAddrV4::new({}, {})",
479            self.ip().const_val(),
480            self.port()
481        )
482    }
483}
484
485impl CompileConst for SocketAddrV6 {
486    fn const_type() -> String {
487        "core::net::SocketAddrV6".to_owned()
488    }
489
490    fn const_val(&self) -> String {
491        format!(
492            "core::net::SocketAddrV6::new({}, {}, {}, {})",
493            self.ip().const_val(),
494            self.port(),
495            self.flowinfo(),
496            self.scope_id()
497        )
498    }
499}
500
501
502macro_rules! arrays
503{
504    ($($n:literal),*) =>
505    {
506        $(impl<T: CompileConst> CompileConst for [T; $n]
507        {
508            fn const_type() -> String
509            {
510                format!("[{}; {}]", T::const_type(), $n)
511            }
512
513            fn const_val(&self) -> String
514            {
515                format!("[{}]", self
516                    .iter()
517                    .map(|e| e.const_val())
518                    .collect::<Vec<String>>()
519                    .join(","))
520            }
521        })*
522    }
523}
524arrays!(
525    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
526    26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
527    50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73,
528    74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97,
529    98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116,
530    117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135,
531    136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154,
532    155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173,
533    174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192,
534    193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211,
535    212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230,
536    231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249,
537    250, 251, 252, 253, 254, 255, 256
538);
539
540// Implementation for various-sized tuples
541macro_rules! tuples
542{
543    ($format:literal $(, $ty:ident $index:tt)*) =>
544    {
545        impl<$($ty: CompileConst),*> CompileConst for ($($ty),*)
546        {
547            fn const_type() -> String
548            {
549                format!($format, $($ty::const_type()),*)
550            }
551
552            fn const_val(&self) -> String
553            {
554                format!($format, $(self.$index.const_val()),*)
555            }
556        }
557
558        impl<$($ty: CompileConstArray),*> CompileConstArray for ($($ty),*)
559        {
560            fn const_array_type(&self) -> String
561            {
562                format!($format, $(self.$index.const_array_type()),*)
563            }
564
565            fn const_array_val(&self) -> String
566            {
567                format!($format, $(self.$index.const_array_val()),*)
568            }
569        }
570    }
571}
572
573tuples!("()");
574tuples!("({},{})", A 0, B 1);
575tuples!("({},{},{})", A 0, B 1, C 2);
576tuples!("({},{},{},{})", A 0, B 1, C 2, D 3);
577tuples!("({},{},{},{},{})", A 0, B 1, C 2, D 3, E 4);
578tuples!("({},{},{},{},{},{})", A 0, B 1, C 2, D 3, E 4, F 5);
579tuples!("({},{},{},{},{},{},{})", A 0, B 1, C 2, D 3, E 4, F 5, G 6);
580tuples!("({},{},{},{},{},{},{},{})", A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7);
581tuples!("({},{},{},{},{},{},{},{},{})", A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7, I 8);
582tuples!("({},{},{},{},{},{},{},{},{},{})", A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7, I 8, J 9);
583tuples!("({},{},{},{},{},{},{},{},{},{},{})", A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7, I 8, J 9, K 10);
584tuples!("({},{},{},{},{},{},{},{},{},{},{},{})", A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7, I 8, J 9, K 10, L 11);
585tuples!("({},{},{},{},{},{},{},{},{},{},{},{},{})", A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7, I 8, J 9, K 10, L 11, M 12);
586tuples!("({},{},{},{},{},{},{},{},{},{},{},{},{},{})", A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7, I 8, J 9, K 10, L 11, M 12, N 13);
587tuples!("({},{},{},{},{},{},{},{},{},{},{},{},{},{},{})", A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7, I 8, J 9, K 10, L 11, M 12, N 13, O 14);
588tuples!("({},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{})", A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7, I 8, J 9, K 10, L 11, M 12, N 13, O 14, P 15);