default_params/lib.rs
1#![no_std]
2//#![feature(adt_const_params)]
3#![warn(clippy::pedantic,clippy::cargo,clippy::nursery,clippy::complexity,clippy::perf,clippy::correctness,clippy::all)]
4#![warn(clippy::cognitive_complexity,clippy::large_const_arrays)]
5#![warn(clippy::style,clippy::suspicious,large_assignments)]
6#![warn(rustdoc::all,missing_docs,clippy::empty_docs)]
7//! Do you want default function arguments or method parameters inside Rust?
8//!
9//! Well, too bad! As this feature is currently not supported in Rust we can
10//! only emulate this functionality through macros and even more macros.
11//!
12//! # Formalisation
13//! Default parameters could be easily formalised as
14//! ```ignore
15//! struct DefaultParam<T, const VAL: T>(T);
16//! ```
17//!
18//! # Reality
19//! This approach however falls apart in a spectacular fashion as Rust doesn't
20//! support types dependent on other types.
21//!
22//! Sadly this leaves us no choice. We can currently only make default arguments
23//! for `integer`, `bool` and `char` types.
24//!
25//! # How does this implementation work?
26//! - All supported types have a wrapper around them (`i32 -> Di32`, `bool -> Dbool` ...)
27//! - Empty default arguments can be created via
28//! ```
29//! # use default_params::Di32;
30//! let def1=Di32::<23>::new(); // Its value will be 23
31//! ```
32//! - Default arguments with values can be created via
33//! ```
34//! # use default_params::Di32;
35//! let def2=Di32::<5>::from(53); // Its value will be 53
36//! ```
37//! - The value of default arguments can be unwrapped via
38//! ```
39//! # use default_params::Di32;
40//! # let def1=Di32::<23>::new();
41//! # let def2=Di32::<5>::from(53);
42//! assert_eq!(def1.unwrap(),23);
43//! assert_eq!(def2.unwrap(),53);
44//! ```
45
46/// Trait for classifying default parameters
47pub trait DefaultParam<T> : From<T> + Default {
48 /// Unwrap a default parameter into a primitive value
49 ///
50 /// # Example
51 /// ```
52 /// # use default_params::Di32;
53 /// let def=Di32::<23>::new();
54 /// assert_eq!(def.unwrap(),23)
55 /// ```
56 #[must_use]
57 fn unwrap(self) -> T;
58 /// Create a new Default parameter
59 ///
60 /// # Example
61 /// ```
62 /// # use default_params::Di32;
63 /// let def=Di32::<23>::new();
64 /// assert_eq!(def.unwrap(),23)
65 /// ```
66 #[must_use]
67 fn new() -> Self;
68}
69
70macro_rules! gen_default_param {
71 ($name:ident, $type:ty) => {
72 /// Default parameter for primitive type
73 pub struct $name<const VAL: $type>(pub $type);
74
75 impl<const VAL: $type> $name<VAL> {
76 /// Unwrap a default parameter into a primitive value
77 ///
78 /// # Example
79 /// ```
80 /// # use default_params::Di32;
81 /// let def=Di32::<23>::new();
82 /// assert_eq!(def.unwrap(),23)
83 /// ```
84 #[must_use]
85 pub const fn const_unwrap(self) -> $type {
86 self.0
87 }
88 /// Create a new Default parameter
89 ///
90 /// # Example
91 /// ```
92 /// # use default_params::Di32;
93 /// let def=Di32::<23>::new();
94 /// assert_eq!(def.unwrap(),23)
95 /// ```
96 #[must_use]
97 pub const fn const_new() -> Self {
98 Self(VAL)
99 }
100 }
101 impl<const VAL: $type> DefaultParam<$type> for $name<VAL> {
102 fn unwrap(self) -> $type {
103 self.0
104 }
105 fn new() -> Self {
106 Self(VAL)
107 }
108 }
109 impl<const VAL: $type> From<$type> for $name<VAL> {
110 fn from(value: $type) -> Self {
111 Self(value)
112 }
113 }
114 impl<const VAL: $type> Default for $name<VAL> {
115 fn default() -> Self {
116 Self::new()
117 }
118 }
119 };
120}
121
122gen_default_param!(Di8,i8);
123gen_default_param!(Di16,i16);
124gen_default_param!(Di32,i32);
125gen_default_param!(Di64,i64);
126gen_default_param!(Di128,i128);
127gen_default_param!(Disize,isize);
128gen_default_param!(Du8,u8);
129gen_default_param!(Du16,u16);
130gen_default_param!(Du32,u32);
131gen_default_param!(Du64,u64);
132gen_default_param!(Du128,u128);
133gen_default_param!(Dusize,usize);
134gen_default_param!(Dbool,bool);
135gen_default_param!(Dchar,char);