code_spells/
lib.rs

1//! Do you think Rust macros are a bit like magic? I do too!
2//!
3//! With this crate you can live your wizard dreams right in your source code.
4//! It aliases some common (and some less common) code snippets to macros
5//! named after thematically appropriate spells from Harry Potter.
6//!
7//! This enables you to cast [`geminio!(item)`](geminio) instead of forcing you to call [`item.clone()`](core::clone::Clone::clone).
8//! ```
9//! # use code_spells::{accio, erecto, obliviate, expecto_patronum, geminio};
10//! let v1 = vec![erecto!(i32); 5];
11//! let mut v2 = geminio!(&v1);
12//! obliviate!(v1);
13//! accio!(expecto_patronum!(v2.get_mut(0), "Dementors B-gone!")) = 5;
14//! ```
15//! Also aliases `unsafe` to the macro [`unforgivable!`](unforgivable),
16//! because what could be more unforgivable than undefined behaviour?  
17
18/// Alias for [`std::thread::sleep`](std::thread::sleep).
19/// # Example
20/// ```
21/// # use code_spells::petrificus_totalus;
22/// petrificus_totalus!(std::time::Duration::from_secs(1));
23/// ```
24#[macro_export]
25macro_rules! petrificus_totalus {
26    ($duration:expr) => {
27        ::std::thread::sleep($duration)
28    };
29}
30
31/// Alias for [`panic!`].
32/// # Example
33/// ```no_run
34/// # use code_spells::avada_kedavra;
35/// avada_kedavra!("Lily Potter");
36/// let lily_potter = "continue"; // This code will never execute, as the program is dead!
37/// ```
38#[macro_export]
39macro_rules! avada_kedavra {
40    ($($arg:tt)*) => {
41        panic!($($arg)*)
42    };
43}
44
45/// Alias for [`Drop::drop`](core::mem::drop).
46/// # Examples
47/// Drop the return value of an expression:
48/// ```
49/// # use code_spells::obliviate;
50/// obliviate!(vec![0; 5]);
51/// ```
52/// Drop a variable:
53/// ```compile_fail
54/// # use code_spells::obliviate;
55/// let x = vec![0; 5];
56/// obliviate!(x);
57/// // no longer possible to reference x
58/// println!("{x:?}");
59/// ```
60#[macro_export]
61macro_rules! obliviate {
62    ($memory:expr) => {
63        ::core::mem::drop($memory)
64    };
65}
66
67/// Constructs the given type using either the [`Default::default`](core::default::Default::default)
68/// or `new(<optional args>)` functions.
69/// Calling it with `erecto!(type)` results in the former, while
70/// `erecto!(type: <optional args>)` results in the latter.
71/// # Examples
72/// ```
73/// # use code_spells::erecto;
74/// #[derive(Debug, Default, PartialEq)]
75/// struct Thing {
76///     x: u8,
77/// }
78///
79/// impl Thing {
80///     fn new(x: u8) -> Self {
81///         Self { x }
82///     }
83/// }
84///
85/// assert_eq!(erecto!(u8), 0);
86/// assert_eq!(erecto!(String), String::default());
87/// assert_eq!(erecto!(String:), String::new());
88/// assert_eq!(erecto!(Thing), Thing::default());
89/// assert_eq!(erecto!(Thing: 5), Thing::new(5));
90/// ```
91#[macro_export]
92macro_rules! erecto {
93    ($t:ty) => {
94        <$t as ::core::default::Default>::default()
95    };
96    ($t:ty: $($arg:expr),*) => {
97        <$t>::new( $($arg,)* )
98    };
99}
100
101/// Alias for dereferencing. This does not use the [`Deref`](core::ops::Deref) or [`DerefMut`](core::ops::DerefMut) traits,
102/// but prepends `*` to the start of the given expression.
103/// # Example
104/// ```
105/// # use code_spells::accio;
106/// let x = 5;
107/// let y = &x;
108/// assert_eq!(accio!(y), x);
109///
110/// let a = vec![0; 5];
111/// assert_eq!(accio!(a.get(0).unwrap()), 0);
112/// ```
113#[macro_export]
114macro_rules! accio {
115    ($x:expr) => {
116        *$x
117    };
118}
119
120/// Alias for [`Clone::clone`](core::clone::Clone::clone).
121/// # Example
122/// ```
123/// # use code_spells::geminio;
124/// let a = vec![0; 5];
125/// let b = geminio!(&a);
126/// drop(a);
127/// assert_eq!(b, vec![0; 5]);
128/// ```
129#[macro_export]
130macro_rules! geminio {
131    ($object:expr) => {
132        ::core::clone::Clone::clone($object)
133    };
134}
135
136/// Alias for [`Pin::new`](core::pin::Pin::new).
137/// # Example
138/// ```
139/// # use code_spells::immobulus;
140/// let mut val = 5;
141/// let pinned = immobulus!(&mut val);
142/// let r = core::pin::Pin::into_inner(pinned);
143/// assert_eq!(*r, 5);
144/// ```
145#[macro_export]
146macro_rules! immobulus {
147    ($item:expr) => {
148        ::core::pin::Pin::new($item)
149    };
150}
151
152/// Appends `.expect(message)` if given a message, otherwise appends `.unwrap()`.
153/// # Examples
154/// ```
155/// # use code_spells::expecto_patronum;
156/// # use std::convert::TryFrom;
157/// expecto_patronum!(u8::try_from(5));
158/// ```
159/// ```should_panic
160/// # use code_spells::expecto_patronum;
161/// # use std::convert::TryFrom;
162/// expecto_patronum!(u8::try_from(-5), "Here be Dementors!");
163/// ```
164#[macro_export]
165macro_rules! expecto_patronum {
166    ($danger:expr, $message:expr) => {
167        $danger.expect($message)
168    };
169    ($danger:expr) => {
170        $danger.unwrap()
171    };
172}
173
174/// Alias for [`Mutex::lock`](std::sync::Mutex::lock).
175/// # Example
176/// ```
177/// # use code_spells::colloportus;
178/// use std::sync::Mutex;
179/// let door = Mutex::new(5);
180/// let guard_result = colloportus!(&door);
181/// ```
182#[macro_export]
183macro_rules! colloportus {
184    ($door:expr) => {
185        ::std::sync::Mutex::lock($door)
186    };
187}
188
189/// Alias for [`Box::leak`](std::boxed::Box::leak). The item is still there, it's just invisible. Can be revealed with [`aparecium!`](aparecium).
190/// # Examples
191/// If the returned pointer is dropped this causes a memory leak. You forgot where you put it, and it's invisible.
192/// ```compile_fail
193/// # use code_spells::evanesco;
194/// let a = Box::new(vec![5; 100]);
195/// evanesco!(a);
196/// println!("{a:?}");
197/// ```
198/// ```no_run
199/// # use code_spells::evanesco;
200/// let ostrich = Box::new(vec![5; 100]);
201/// // What do you have there?
202/// evanesco!(ostrich);
203/// // A smoothie..?
204/// ```
205/// Using [`Box::from_raw`](std::boxed::Box::from_raw) is one way of getting the item back.
206/// This crate allows that function to be cast with [`aparecium!`].
207/// ```
208/// # use code_spells::{evanesco, aparecium};
209/// let a: &mut Vec<i32> = evanesco!(Box::new(vec![5; 100]));
210/// assert_eq!(unsafe { aparecium!(a) }, Box::new(vec![5; 100]));
211/// ```
212#[macro_export]
213macro_rules! evanesco {
214    ($item:expr) => {
215        ::std::boxed::Box::leak($item)
216    };
217}
218
219/// Alias for [`Box::from_raw`](std::boxed::Box::from_raw). Useful if you have made something invisible with [`evanesco!`](evanesco).
220/// This is `unsafe` as revealing something invisible might not be what the invisible thing wants,
221/// and it might attack you and cause undefined behaviour.
222/// # Example
223/// ```
224/// # use code_spells::{evanesco, aparecium};
225/// let a: &mut Vec<i32> = evanesco!(Box::new(vec![5; 100]));
226/// assert_eq!(unsafe { aparecium!(a) }, Box::new(vec![5; 100]));
227/// ```
228#[macro_export]
229macro_rules! aparecium {
230    ($item:expr) => {
231        ::std::boxed::Box::from_raw($item)
232    };
233}
234
235/// Alias for [`println!`].
236/// # Example
237/// ```
238/// # use code_spells::sonorous;
239/// sonorous!("Hello, World!");
240/// sonorous!("{} chocolate", "dark");
241/// let a = 1 + 1;
242/// sonorous!("{a} is not {}", 5);
243/// ```
244#[macro_export]
245macro_rules! sonorous {
246    () => {
247        print!("\n")
248    };
249    ($($arg:tt)*) => {
250        println!($($arg)*)
251    };
252}
253
254/// Alias for [`Result::unwrap_or`](core::result::Result::unwrap_or) and [`Result::unwrap_or_else`](core::result::Result::unwrap_or_else).
255/// Automatically chooses [`unwrap_or_else`](core::result::Result::unwrap_or_else) if given a closure,
256/// and [`unwrap_or`](core::result::Result::unwrap_or) if given an expression that is not a closure.
257/// # Example
258/// ```
259/// # use code_spells::reparo;
260/// fn foo(x: u8) -> Result<u8, u8> {
261///     if x < 125 {
262///         Ok(x)
263///     } else {
264///         Err(x)
265///     }
266/// }
267/// let five = 5;
268/// assert_eq!(reparo!(foo(5), five), 5); // unwrap_or
269/// assert_eq!(reparo!(foo(255), u8::MAX), u8::MAX); // unwrap_or
270/// assert_eq!(reparo!(foo(255), |_| 5), 5); // unwrap_or_else
271/// let primes = vec![2, 3, 5];
272/// assert_eq!(reparo!(foo(255), move |_| primes.into_iter().sum()), 10); // unwrap_or_else
273/// ```
274/// # Note
275/// If the second argument is the name of a function this macro will not work.
276/// ```compile_fail
277/// # use code_spells::reparo;
278/// # fn foo(x: u8) -> Result<u8, u8> {if x < 125 { Ok(x) } else { Err(x) } }
279/// fn ten() -> u8 { 10 }
280/// assert_eq!(reparo!(foo(255), ten), 10);
281/// ```
282/// We can make it work by converting the function to a closure
283/// ```
284/// # use code_spells::reparo;
285/// # fn foo(x: u8) -> Result<u8, u8> {if x < 125 { Ok(x) } else { Err(x) } }
286/// # fn ten() -> u8 { 10 }
287/// assert_eq!(reparo!(foo(255), |_| ten()), 10); // uses unwrap_or_else
288/// ```
289/// or by calling the function in the macro.
290/// ```
291/// # use code_spells::reparo;
292/// # fn foo(x: u8) -> Result<u8, u8> {if x < 125 { Ok(x) } else { Err(x) } }
293/// # fn ten() -> u8 { 10 }
294/// assert_eq!(reparo!(foo(255), ten()), 10); // uses unwrap_or
295/// ```
296#[macro_export]
297macro_rules! reparo {
298    ($result:expr, move |$arg_name:pat_param| $body:expr) => {
299        ::core::result::Result::unwrap_or_else($result, move |$arg_name| $body)
300    };
301    ($result:expr, |$arg_name:pat_param| $body:expr) => {
302        ::core::result::Result::unwrap_or_else($result, |$arg_name| $body)
303    };
304    ($result:expr, $alt:expr) => {
305        ::core::result::Result::unwrap_or($result, $alt)
306    };
307}
308
309/// Alias for unsafe. What could be more unforgivable than undefined behaviour?
310/// # Example
311/// ```
312/// # use code_spells::unforgivable;
313/// use core::num::NonZeroU8;
314/// // Forgivability: `new_unchecked` is UB if the argument is zero, but two is not zero.
315/// const two: NonZeroU8 = unforgivable! { NonZeroU8::new_unchecked(2) };
316/// assert_eq!(two.get(), 2);
317/// ```
318#[macro_export]
319macro_rules! unforgivable {
320    ($($code:tt)+) => {
321        unsafe {
322            $($code)+
323        }
324    };
325}
326
327/// Alias for [`Vec::reserve`](std::vec::Vec::reserve).
328/// # Example
329/// ```
330/// # use code_spells::capacious_extremis;
331/// let mut police_box = Vec::<i32>::new();
332/// capacious_extremis!(&mut police_box, 5);
333/// assert!(police_box.capacity() >= 5);
334/// let r = &mut police_box;
335/// capacious_extremis!(r, 10);
336/// assert!(police_box.capacity() >= 10);
337/// ```
338#[macro_export]
339macro_rules! capacious_extremis {
340    (&mut $vec:ident, $capacity:expr) => {
341        ::std::vec::Vec::reserve(&mut $vec, $capacity)
342    };
343    ($vec:ident, $capacity:expr) => {
344        ::std::vec::Vec::reserve($vec, $capacity)
345    };
346}
347
348/// Alias for [`mem::transmute`](core::mem::transmute). Disregard the rules, force the type system to do what you want!
349/// # Safety
350/// This spell is unforgivable for a reason, see the documentation of [`mem::transmute`](core::mem::transmute) for more details.
351/// # Examples
352/// ```
353/// # use code_spells::{imperio, unforgivable};
354/// let a = [0_u8; 4];
355/// let b: u32 = unforgivable! { imperio!(a) };
356/// assert_eq!(b, 0);
357/// let mut c = unforgivable! { imperio!(b, u32 => [u8; 4]) };
358/// assert_eq!(c, [0; 4]);
359/// let d = &mut c;
360/// assert_eq!(unforgivable! { imperio!(d, &mut [u8; 4] => &[u8; 4]) }, &c)
361/// ```
362/// Force a pointer to become a function pointer!
363/// ```
364/// # use code_spells::{imperio, unforgivable};
365/// fn foo() -> i32 { 0 }
366/// let pointer = foo as *const ();
367/// let function = unforgivable! {
368///     imperio!(pointer, *const () => fn() -> i32)
369/// };
370/// assert_eq!(function(), 0);
371/// ```
372#[macro_export]
373macro_rules! imperio {
374    // Elision
375    ($will:expr) => {
376        ::core::mem::transmute($will)
377    };
378    // Pure type to type
379    ($will:expr, $src:ty => $dst:ty) => {
380        ::core::mem::transmute::<$src, $dst>($will)
381    };
382    // Attempt to match against any expression
383    ($will:expr, $src:expr => $dst:expr) => {
384        ::core::mem::transmute::<$src, $dst>($will)
385    };
386}
387
388#[cfg(test)]
389mod tests {
390    use super::*;
391    use std::convert::TryFrom;
392
393    #[test]
394    fn practice_obliviate() {
395        let x = vec![0; 5];
396        obliviate!(x);
397    }
398
399    #[test]
400    fn practice_accio() {
401        let x = 5;
402        let y = &x;
403        assert_eq!(accio!(y), 5);
404    }
405
406    #[test]
407    fn practice_erecto() {
408        #[derive(Debug, Default, PartialEq)]
409        struct Thing {
410            x1: f64,
411            x2: f32,
412            y1: u64,
413            y2: u32,
414            y3: u16,
415            y4: u8,
416            y5: i64,
417            y6: i32,
418            y7: i16,
419            y8: i8,
420            y9: u128,
421            y10: i128,
422            y11: usize,
423            y12: isize,
424            b: bool,
425            cs: std::ffi::CString,
426            os: std::ffi::OsString,
427            s: String,
428        }
429        impl Thing {
430            fn new(b: bool, x: u8) -> Self {
431                Self {
432                    b,
433                    y4: x,
434                    ..Default::default()
435                }
436            }
437        }
438        assert_eq!(erecto!(Thing), Thing::default());
439        assert_eq!(erecto!(Thing: true, 5), Thing::new(true, 5));
440        let b = true;
441        let x = 5;
442        assert_eq!(erecto!(Thing: b, x), Thing::new(b, x));
443        assert_eq!(
444            erecto!(Thing: 5 != 2, 2_u8.pow(5)),
445            Thing::new(5 != 2, 2_u8.pow(5))
446        );
447        assert_eq!(erecto!(Thing: 5 != 2, x), Thing::new(5 != 2, x));
448        assert_eq!(erecto!(String:), String::new());
449    }
450
451    #[test]
452    fn practice_geminio() {
453        let a = vec![0; 5];
454        let b = geminio!(&a);
455        assert_eq!(a, b);
456        drop(a);
457        assert_eq!(b, vec![0; 5]);
458    }
459
460    #[test]
461    fn practice_immobulus() {
462        let mut val = 5;
463        let pinned = immobulus!(&mut val);
464        let r = core::pin::Pin::into_inner(pinned);
465        assert_eq!(*r, 5);
466    }
467
468    #[test]
469    fn practice_expecto_patronum() {
470        expecto_patronum!(u8::try_from(5));
471    }
472
473    #[test]
474    fn practice_colloportus() {
475        let door = std::sync::Mutex::new(5);
476        let _guard = colloportus!(&door);
477    }
478
479    #[test]
480    fn practice_evanesco_and_apericium() {
481        let a = Box::new(vec![5; 100]);
482        let b: &mut Vec<i32> = evanesco!(a);
483        assert_eq!(unsafe { aparecium!(b) }, Box::new(vec![5; 100]));
484    }
485
486    #[test]
487    fn practice_reparo() {
488        fn foo(x: u8) -> Result<u8, u8> {
489            if x < 125 {
490                Ok(x)
491            } else {
492                Err(x)
493            }
494        }
495        let five = 5;
496        fn identity(x: u8) -> u8 {
497            x
498        }
499        assert_eq!(reparo!(foo(5), five), 5);
500        assert_eq!(reparo!(foo(255), u8::MAX), u8::MAX);
501        assert_eq!(reparo!(foo(255), |_| 5), 5);
502        assert_eq!(reparo!(foo(255), |_| identity(10)), 10);
503    }
504
505    #[test]
506    fn practice_capacious_extremis() {
507        let mut a = Vec::<i32>::new();
508        let b = &mut a;
509        capacious_extremis!(b, 5);
510        capacious_extremis!(&mut a, 10);
511        assert!(a.capacity() >= 10);
512    }
513
514    #[test]
515    fn practice_imperio() {
516        let a = [0_u8; 4];
517        let b: u32 = unforgivable! { imperio!(a) };
518        assert_eq!(b, 0);
519        let c = unforgivable! { imperio!(b, u32 => [u8; 4]) };
520        assert_eq!(c, [0; 4]);
521    }
522}