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}