libnotcurses_sys/
macros.rs

1//! Macros
2//!
3//
4// NOTE: Use full paths everywhere. Don't assume anything will be in scope.
5
6#[allow(unused_imports)] // for doc comments
7use crate::{
8    c_api::{NCRESULT_ERR, NCRESULT_OK},
9    Nc, NcDirect, NcError, NcPlane, NcResult, NcVisual, NcVisualOptions,
10};
11
12// String & Print Macros -------------------------------------------------------
13
14/// Converts an `&str` into `*const c_char`.
15///
16/// See [`Cstring`].
17#[macro_export]
18#[doc(hidden)]
19#[cfg(feature = "std")]
20macro_rules! cstring {
21    ($s:expr) => {
22        std::ffi::CString::new($s).unwrap()
23    };
24}
25
26/// Converts an `&str` into `*const c_char`.
27///
28/// See [`Cstring`].
29#[macro_export]
30#[doc(hidden)]
31#[cfg(not(feature = "std"))]
32macro_rules! cstring {
33    ($s:expr) => {
34        alloc::ffi::CString::new($s).unwrap()
35    };
36}
37
38/// Converts a `*const c_char` into an `&str`.
39#[macro_export]
40#[doc(hidden)]
41macro_rules! rstring {
42    ($s:expr) => {
43        unsafe { core::ffi::CStr::from_ptr($s).to_str().unwrap() }
44        // possible alternative:
45        // unsafe { core::ffi::CStr::from_ptr($s).to_string_lossy() }
46    };
47}
48
49/// Converts a `*const c_char` into a `String`, freeing the original alloc.
50#[macro_export]
51#[doc(hidden)]
52#[cfg(feature = "std")]
53macro_rules! rstring_free {
54    ($s:expr) => {{
55        #[allow(unused_unsafe)]
56        let nc_string = unsafe { $s };
57        let string = $crate::rstring![nc_string].to_string();
58        unsafe { $crate::c_api::ffi::free(nc_string as *mut core::ffi::c_void) };
59        string
60    }};
61}
62
63/// Converts a `*const c_char` into a `String`, freeing the original alloc.
64#[macro_export]
65#[doc(hidden)]
66#[cfg(not(feature = "std"))]
67macro_rules! rstring_free {
68    ($s:expr) => {{
69        #[allow(unused_unsafe)]
70        let nc_string = unsafe { $s };
71        let string = alloc::string::ToString::to_string($crate::rstring![nc_string]);
72        unsafe { $crate::c_api::ffi::free(nc_string as *mut core::ffi::c_void) };
73        string
74    }};
75}
76
77/// Wrapper around [`libc::printf`][c_api::libc::printf].
78#[macro_export]
79#[doc(hidden)]
80macro_rules! printf {
81    ($s:expr) => {
82        let cs = cstring![$s];
83        unsafe { $crate::c_api::libc::printf(cs.as_ptr()) }
84    };
85    ($s:expr $(, $opt:expr)*) => {
86        let cs = cstring![$s];
87        unsafe { $crate::c_api::libc::printf(cs.as_ptr(), $($opt),*) }
88    };
89}
90
91/// Wrapper around [`NcPlane.putstr`][NcPlane#method.putstr],
92/// rendering and rasterizing the plane afterwards.
93///
94/// Returns an `NcResult` with the number of columns advanced,
95/// with newlines counting as 1 column.
96///
97/// # Example
98/// ```
99/// # use libnotcurses_sys::*;
100/// # fn main() -> NcResult<()> {
101/// let nc = unsafe { Nc::new_cli()? };
102/// let splane = unsafe { nc.stdplane() };
103/// splane.set_scrolling(true);
104/// assert_eq![12, putstr!(splane, "hello\nworld\n")?];
105/// putstr!(splane, "formatted text: {:?}\n", (0, 1.0, "two") )?;
106/// # unsafe { nc.stop()? };
107/// # Ok(())
108/// # }
109/// ```
110#[macro_export]
111macro_rules! putstr {
112    ($plane:ident, $($args:tt)*) => {
113        {
114            let res = $plane.putstr(&format![$($args)*])?;
115            $plane.render()?;
116            $plane.rasterize()?;
117            Ok(res)
118        }
119    };
120}
121
122/// Wrapper around [`NcPlane.putstrln`][NcPlane#method.putstrln].
123/// rendering and rasterizing the plane afterwards.
124///
125/// Returns an `NcResult` with the number of columns advanced,
126/// with newlines counting as 1 column.
127///
128/// # Example
129/// ```
130/// # use libnotcurses_sys::*;
131/// # fn main() -> NcResult<()> {
132/// let nc = unsafe { Nc::new_cli()? };
133/// let splane = unsafe { nc.stdplane() };
134/// splane.set_scrolling(true);
135/// assert_eq![12, putstrln!(splane, "hello world")?];
136/// putstrln!(splane, "formatted text: {:?}", (0, 1.0, "two") )?;
137/// # unsafe { nc.stop()? };
138/// # Ok(())
139/// # }
140/// ```
141#[macro_export]
142macro_rules! putstrln {
143    ($plane:ident) => {
144        {
145            $plane.putln()?;
146            $plane.render()?;
147            $plane.rasterize()?;
148            Ok(())
149        }
150    };
151    ($plane:ident, $($args:tt)*) => {
152        {
153            let res = $plane.putstrln(&format![$($args)*])?;
154            $plane.render()?;
155            $plane.rasterize()?;
156            Ok(res)
157        }
158    };
159}
160
161// Error Wrappers Macros -------------------------------------------------------
162
163/// Returns an `Ok($ok)`,
164/// or an `Err(`[`NcError`]`)` if `$res` < [`NCRESULT_OK`].
165///
166/// In other words:
167/// Returns Ok(`$ok`) if `$res` >= [NCRESULT_OK], otherwise returns
168/// Err([NcError]::[new][NcError#method.new](`$res`, `$msg`)).
169///
170/// `$ok` & `$msg` are optional. By default they will be the unit
171/// type `()`, and an empty `&str` `""`, respectively.
172#[macro_export]
173#[doc(hidden)]
174macro_rules! error {
175    ($res:expr, $msg:expr, $ok:expr) => {{
176        let res = $res;
177        if res >= $crate::c_api::NCRESULT_OK {
178            return Ok($ok);
179        } else {
180            return Err($crate::NcError::with_msg(res, $msg));
181        }
182    }};
183    ($res:expr, $msg:expr) => {
184        error![$res, $msg, ()]
185    };
186    ($res:expr) => {
187        error![$res, "", ()]
188    };
189}
190
191/// Returns an `Ok(&T)` from a `*const T` pointer,
192/// or an `Err(`[`NcError`]`)` if the pointer is null.
193///
194/// In other words:
195/// Returns Ok(&*`$ptr`) if `!$ptr.is_null()`, otherwise returns
196/// Err([NcError]]::[new][NcError#method.new]([NCRESULT_ERR], `$msg`)).
197///
198/// `$msg` is optional. By default it will be an empty `&str` `""`.
199#[macro_export]
200#[doc(hidden)]
201macro_rules! error_ref {
202    ($ptr:expr, $msg:expr, $ok:expr) => {{
203        let ptr = $ptr; // avoid calling a function multiple times
204        if ptr.is_null() {
205            return Err($crate::NcError::with_msg($crate::c_api::NCRESULT_ERR, $msg));
206        } else {
207            #[allow(unused_unsafe)]
208            return Ok(unsafe { $ok });
209        }
210    }};
211    ($ptr:expr, $msg:expr) => {{
212        let ptr = $ptr;
213        error_ref![$ptr, $msg, unsafe { &*ptr }];
214    }};
215    ($ptr:expr) => {{
216        let ptr = $ptr;
217        error_ref![$ptr, "", unsafe { &*ptr }];
218    }};
219}
220
221/// Returns an `Ok(&mut T)` from a `*mut T` pointer,
222/// or an `Err(`[`NcError`]`)` if the pointer is null.
223///
224/// In other words:
225/// Returns Ok(&mut *`$ptr`) if `!$ptr._is_null()`, otherwise returns
226/// Err([NcError]]::[new][NcError#method.new]([NCRESULT_ERR], `$msg`)).
227///
228/// `$msg` is optional. By default it will be an empty `&str` `""`.
229#[macro_export]
230#[doc(hidden)]
231macro_rules! error_ref_mut {
232    ($ptr:expr, $msg:expr, $ok:expr) => {{
233        let ptr = $ptr; // avoid calling a function multiple times
234        if ptr.is_null() {
235            return Err($crate::NcError::with_msg($crate::c_api::NCRESULT_ERR, $msg));
236        } else {
237            #[allow(unused_unsafe)]
238            return Ok(unsafe { $ok });
239        }
240    }};
241    ($ptr:expr, $msg:expr) => {{
242        let ptr = $ptr;
243        error_ref_mut![ptr, $msg, unsafe { &mut *ptr }];
244    }};
245    ($ptr:expr) => {{
246        let ptr = $ptr;
247        error_ref_mut![ptr, "", unsafe { &mut *ptr }];
248    }};
249}
250
251/// Returns an `Ok(String)` from a `*const` pointer to a C string,
252/// or an `Err(`[`NcError`]`)` if the pointer is null.
253///
254/// In other words:
255/// Returns Ok((&*`$str`).to_string()) if `!$str.is_null()`, otherwise returns
256/// Err([NcError]]::[new][NcError#method.new]([NCRESULT_ERR], `$msg`)).
257///
258/// `$msg` is optional. By default it will be an empty `&str` `""`.
259#[macro_export]
260#[doc(hidden)]
261#[cfg(feature = "std")]
262macro_rules! error_str {
263    ($str:expr, $msg:expr) => {
264        if !$str.is_null() {
265            #[allow(unused_unsafe)]
266            return Ok(unsafe { $crate::rstring!($str).to_string() });
267        } else {
268            return Err($crate::NcError::with_msg($crate::c_api::NCRESULT_ERR, $msg));
269        }
270    };
271    ($str:expr) => {
272        error_str![$str, ""];
273    };
274}
275
276/// Returns an `Ok(String)` from a `*const` pointer to a C string,
277/// or an `Err(`[`NcError`]`)` if the pointer is null.
278///
279/// In other words:
280/// Returns Ok((&*`$str`).to_string()) if `!$str.is_null()`, otherwise returns
281/// Err([NcError]]::[new][NcError#method.new]([NCRESULT_ERR], `$msg`)).
282///
283/// `$msg` is optional. By default it will be an empty `&str` `""`.
284#[macro_export]
285#[doc(hidden)]
286#[cfg(not(feature = "std"))]
287macro_rules! error_str {
288    ($str:expr, $msg:expr) => {
289        if !$str.is_null() {
290            #[allow(unused_unsafe)]
291            return Ok(unsafe { alloc::string::ToString::to_string($crate::rstring!($str)) });
292        } else {
293            return Err($crate::NcError::with_msg($crate::c_api::NCRESULT_ERR, $msg));
294        }
295    };
296    ($str:expr) => {
297        error_str![$str, ""];
298    };
299}
300
301// Implementation Helper Macros ------------------------------------------------
302
303/// Implements methods and constants for an existing type.
304//
305// Allows to have full doc-comments both in the trait definition
306// and in the concrete implementation.
307#[macro_export]
308#[doc(hidden)]
309macro_rules! impl_api {
310    ($type:ident, $trait:ident, $($i:item),*) => {
311        #[doc = concat!("Enables the [`", stringify!($type), "`] associated methods and constants.")]
312        pub trait $trait {
313            $($i)*
314        }
315
316        impl $trait for $type {
317            $($i)*
318        }
319    };
320}
321
322/// Implements multiple variants of `From` between a primitive
323/// and a unit struct containing that primitive.
324#[macro_export]
325#[doc(hidden)]
326macro_rules! unit_impl_from [
327    ($struct:ty, $prim:ty ) => {
328        // from prim
329        impl From<$prim> for $struct {
330            fn from(p: $prim) -> Self { <$struct>::from_primitive(p) }
331        }
332        impl<'a> From<&'a $prim> for $struct {
333            fn from(p: &'a $prim) -> Self { <$struct>::from_primitive(*p) }
334        }
335        impl<'a> From<&'a mut $prim> for $struct {
336            fn from(p: &'a mut $prim) -> Self { <$struct>::from_primitive(*p) }
337        }
338
339        // from struct
340        impl From<$struct> for $prim {
341            fn from(s: $struct) -> Self { s.0 }
342        }
343        impl<'a> From<&'a $struct> for &'a $prim {
344            fn from(s: &'a $struct) -> Self { &s.0 }
345        }
346        impl<'a> From<&'a mut $struct> for &'a mut $prim {
347            fn from(s: &'a mut $struct) -> Self { &mut s.0 }
348        }
349        impl From<&$struct> for *const $prim {
350            fn from(s: &$struct) -> Self { &s.0 as *const $prim}
351        }
352        impl From<&mut $struct> for *mut $prim {
353            fn from(s: &mut $struct) -> Self { &mut s.0 as *mut $prim}
354        }
355    };
356];
357
358/// Implements overloadable operators for a unit struct containing a primitive.
359///
360/// # Usage
361///
362/// - (bitwise; outer_type, inner_type)
363/// - (arithmetic; outer_type, inner_type)
364/// - (neg; outer_type)
365///
366/// # Note
367///
368/// - The output type will always be the unit struct.
369/// - There are no implemented ops between unit struct and &mut primitiv.
370#[macro_export]
371#[doc(hidden)]
372macro_rules! unit_impl_ops [
373    // # external API: implements sets of operations
374    // -------------------------------------------------------------------------
375
376    // ## implements the bitwise operators.
377    (bitwise; $outer:ty, $inner:ty) => {
378        // (struct)
379        $crate::unit_impl_ops![op_refs_u; Not, not, $outer];
380        // (struct OP struct)
381        $crate::unit_impl_ops![op_refs_ss; BitAnd, bitand, $outer, $outer];
382        $crate::unit_impl_ops![op_refs_ss; BitOr, bitor, $outer, $outer];
383        $crate::unit_impl_ops![op_refs_ss; BitXor, bitxor, $outer, $outer];
384        $crate::unit_impl_ops![op_refs_ss; Shl, shl, $outer, $outer];
385        $crate::unit_impl_ops![op_refs_ss; Shr, shr, $outer, $outer];
386        $crate::unit_impl_ops![op_refs_ss_a; BitAndAssign, bitand_assign, $outer, $outer];
387        $crate::unit_impl_ops![op_refs_ss_a; BitOrAssign, bitor_assign, $outer, $outer];
388        $crate::unit_impl_ops![op_refs_ss_a; BitXorAssign, bitxor_assign, $outer, $outer];
389        $crate::unit_impl_ops![op_refs_ss_a; ShlAssign, shl_assign, $outer, $outer];
390        $crate::unit_impl_ops![op_refs_ss_a; ShrAssign, shr_assign, $outer, $outer];
391        // (struct OP primitive)
392        $crate::unit_impl_ops![op_refs_sp; BitAnd, bitand, $outer, $inner];
393        $crate::unit_impl_ops![op_refs_sp; BitOr, bitor, $outer, $inner];
394        $crate::unit_impl_ops![op_refs_sp; BitXor, bitxor, $outer, $inner];
395        $crate::unit_impl_ops![op_refs_sp; Shl, shl, $outer, $inner];
396        $crate::unit_impl_ops![op_refs_sp; Shr, shr, $outer, $inner];
397        $crate::unit_impl_ops![op_refs_sp_a; BitAndAssign, bitand_assign, $outer, $inner];
398        $crate::unit_impl_ops![op_refs_sp_a; BitOrAssign, bitor_assign, $outer, $inner];
399        $crate::unit_impl_ops![op_refs_sp_a; BitXorAssign, bitxor_assign, $outer, $inner];
400        $crate::unit_impl_ops![op_refs_sp_a; ShlAssign, shl_assign, $outer, $inner];
401        $crate::unit_impl_ops![op_refs_sp_a; ShrAssign, shr_assign, $outer, $inner];
402        // (primitive OP struct)
403        $crate::unit_impl_ops![op_refs_ps; BitAnd, bitand, $outer, $inner];
404        $crate::unit_impl_ops![op_refs_ps; BitOr, bitor, $outer, $inner];
405        $crate::unit_impl_ops![op_refs_ps; BitXor, bitxor, $outer, $inner];
406        $crate::unit_impl_ops![op_refs_ps; Shl, shl, $outer, $inner];
407        $crate::unit_impl_ops![op_refs_ps; Shr, shr, $outer, $inner];
408        $crate::unit_impl_ops![op_refs_ps_a; BitAndAssign, bitand_assign, $outer, $inner];
409        $crate::unit_impl_ops![op_refs_ps_a; BitOrAssign, bitor_assign, $outer, $inner];
410        $crate::unit_impl_ops![op_refs_ps_a; BitXorAssign, bitxor_assign, $outer, $inner];
411        $crate::unit_impl_ops![op_refs_ps_a; ShlAssign, shl_assign, $outer, $inner];
412        $crate::unit_impl_ops![op_refs_ps_a; ShrAssign, shr_assign, $outer, $inner];
413    };
414
415    // ## implements the arithmetic operators, except Neg.
416    (arithmetic; $outer:ty, $inner:ty) => {
417        // (struct OP struct)
418        $crate::unit_impl_ops![op_refs_ss; Add, add, $outer, $outer];
419        $crate::unit_impl_ops![op_refs_ss; Sub, sub, $outer, $outer];
420        $crate::unit_impl_ops![op_refs_ss; Mul, mul, $outer, $outer];
421        $crate::unit_impl_ops![op_refs_ss; Div, div, $outer, $outer];
422        $crate::unit_impl_ops![op_refs_ss; Rem, rem, $outer, $outer];
423        $crate::unit_impl_ops![op_refs_ss; Rem, rem, $outer, $outer];
424        $crate::unit_impl_ops![op_refs_ss_a; AndAssign, and_assign, $outer, $outer];
425        $crate::unit_impl_ops![op_refs_ss_a; OrAssign, or_assign, $outer, $outer];
426        $crate::unit_impl_ops![op_refs_ss_a; XorAssign, xor_assign, $outer, $outer];
427        $crate::unit_impl_ops![op_refs_ss_a; ShlAssign, shl_assign, $outer, $outer];
428        $crate::unit_impl_ops![op_refs_ss_a; ShrAssign, shr_assign, $outer, $outer];
429        // (struct OP primitive)
430        $crate::unit_impl_ops![op_refs_sp; Add, add, $outer, $inner];
431        $crate::unit_impl_ops![op_refs_sp; Sub, sub, $outer, $inner];
432        $crate::unit_impl_ops![op_refs_sp; Mul, mul, $outer, $inner];
433        $crate::unit_impl_ops![op_refs_sp; Div, div, $outer, $inner];
434        $crate::unit_impl_ops![op_refs_sp; Rem, rem, $outer, $inner];
435        $crate::unit_impl_ops![op_refs_sp; Rem, rem, $outer, $inner];
436        $crate::unit_impl_ops![op_refs_sp_a; AndAssign, and_assign, $outer, $inner];
437        $crate::unit_impl_ops![op_refs_sp_a; OrAssign, or_assign, $outer, $inner];
438        $crate::unit_impl_ops![op_refs_sp_a; XorAssign, xor_assign, $outer, $inner];
439        $crate::unit_impl_ops![op_refs_sp_a; ShlAssign, shl_assign, $outer, $inner];
440        $crate::unit_impl_ops![op_refs_sp_a; ShrAssign, shr_assign, $outer, $inner];
441        // (primitive OP struct)
442        $crate::unit_impl_ops![op_refs_ps; Add, add, $outer, $inner];
443        $crate::unit_impl_ops![op_refs_ps; Sub, sub, $outer, $inner];
444        $crate::unit_impl_ops![op_refs_ps; Mul, mul, $outer, $inner];
445        $crate::unit_impl_ops![op_refs_ps; Div, div, $outer, $inner];
446        $crate::unit_impl_ops![op_refs_ps; Rem, rem, $outer, $inner];
447        $crate::unit_impl_ops![op_refs_ps; Rem, rem, $outer, $inner];
448        $crate::unit_impl_ops![op_refs_ps_a; AndAssign, and_assign, $outer, $inner];
449        $crate::unit_impl_ops![op_refs_ps_a; OrAssign, or_assign, $outer, $inner];
450        $crate::unit_impl_ops![op_refs_ps_a; XorAssign, xor_assign, $outer, $inner];
451        $crate::unit_impl_ops![op_refs_ps_a; ShlAssign, shl_assign, $outer, $inner];
452        $crate::unit_impl_ops![op_refs_ps_a; ShrAssign, shr_assign, $outer, $inner];
453    };
454
455    // # implements Neg.
456    (neg; $type:ty) => {
457        $crate::unit_impl_ops![op_refs_u; Neg, neg, $type];
458    };
459
460    // # internal API: implements multiple variants of an operation
461    // -------------------------------------------------------------------------
462
463    // ## implements all the variants of a single `non-assign` operator
464    //
465    // (struct OP struct)
466    (op_refs_ss; $op:tt, $fn:ident, $T1:ty, $T2:ty) => {
467        $crate::unit_impl_ops![op_ss; $T1, $op, $fn, $T1, $T2];
468        $crate::unit_impl_ops![op_ss; $T1, $op, $fn, $T1, &'b $T2];
469        $crate::unit_impl_ops![op_ss; $T1, $op, $fn, $T1, &'b mut $T2];
470        $crate::unit_impl_ops![op_ss; $T1, $op, $fn, &'a $T1, $T2];
471        $crate::unit_impl_ops![op_ss; $T1, $op, $fn, &'a $T1, &'b $T2];
472        $crate::unit_impl_ops![op_ss; $T1, $op, $fn, &'a $T1, &'b mut $T2];
473        $crate::unit_impl_ops![op_ss; $T1, $op, $fn, &'a mut $T1, $T2];
474        $crate::unit_impl_ops![op_ss; $T1, $op, $fn, &'a mut $T1, &'b $T2];
475        $crate::unit_impl_ops![op_ss; $T1, $op, $fn, &'a mut $T1, &'b mut $T2];
476    };
477    // (struct OP primitive)
478    (op_refs_sp; $op:tt, $fn:ident, $T1:ty, $T2:ty) => {
479        $crate::unit_impl_ops![op_sp; $T1, $op, $fn, $T1, $T2];
480        $crate::unit_impl_ops![op_sp; $T1, $op, $fn, $T1, &'b $T2];
481        $crate::unit_impl_ops![op_sp; $T1, $op, $fn, &'a $T1, $T2];
482        $crate::unit_impl_ops![op_sp; $T1, $op, $fn, &'a $T1, &'b $T2];
483        $crate::unit_impl_ops![op_sp; $T1, $op, $fn, &'a mut $T1, $T2];
484        $crate::unit_impl_ops![op_sp; $T1, $op, $fn, &'a mut $T1, &'b $T2];
485        // Note: no implementation for `&mut primitive`
486        // $crate::unit_impl_ops![op_sp; $T1, $op, $fn, $T1, &'b mut $T2];
487        // $crate::unit_impl_ops![op_sp; $T1, $op, $fn, &'a $T1, &'b mut $T2];
488        // $crate::unit_impl_ops![op_sp; $T1, $op, $fn, &'a mut $T1, &'b mut $T2];
489    };
490    // (primitive OP struct)
491    (op_refs_ps; $op:tt, $fn:ident, $T1:ty, $T2:ty) => {
492        $crate::unit_impl_ops![op_ps; $T1, $op, $fn, $T2, $T1];
493        $crate::unit_impl_ops![op_ps; $T1, $op, $fn, $T2, &'b $T1];
494        $crate::unit_impl_ops![op_ps; $T1, $op, $fn, $T2, &'b mut $T1];
495        $crate::unit_impl_ops![op_ps; $T1, $op, $fn, &'a $T2, $T1];
496        $crate::unit_impl_ops![op_ps; $T1, $op, $fn, &'a $T2, &'b $T1];
497        $crate::unit_impl_ops![op_ps; $T1, $op, $fn, &'a $T2, &'b mut $T1];
498        // Note: no implementation for `&mut primitive`
499        // $crate::unit_impl_ops![op_ps; $T1, $op, $fn, &'a mut $T2, $T1];
500        // $crate::unit_impl_ops![op_ps; $T1, $op, $fn, &'a mut $T2, &'a $T1];
501        // $crate::unit_impl_ops![op_ps; $T1, $op, $fn, &'a mut $T2, &'a mut $T1];
502    };
503
504    // ## implements all the variants of a single `assign` operator
505    //
506    // (struct OP struct)
507    (op_refs_ss_a; $op:tt, $fn:ident, $T1:ty, $T2:ty) => {
508        $crate::unit_impl_ops![op_ss_a; $op, $fn, $T1, $T2];
509        $crate::unit_impl_ops![op_ss_a; $op, $fn, $T1, &'b $T2];
510        $crate::unit_impl_ops![op_ss_a; $op, $fn, $T1, &'b mut $T2];
511        $crate::unit_impl_ops![op_ss_a; $op, $fn, &'a mut $T1, $T2];
512        $crate::unit_impl_ops![op_ss_a; $op, $fn, &'a mut $T1, &'b $T2];
513        $crate::unit_impl_ops![op_ss_a; $op, $fn, &'a mut $T1, &'b mut $T2];
514    };
515    // (struct OP primitive)
516    (op_refs_sp_a; $op:tt, $fn:ident, $T1:ty, $T2:ty) => {
517        $crate::unit_impl_ops![op_sp_a; $op, $fn, $T1, $T2];
518        $crate::unit_impl_ops![op_sp_a; $op, $fn, $T1, &'b $T2];
519        $crate::unit_impl_ops![op_sp_a; $op, $fn, &'a mut $T1, $T2];
520        $crate::unit_impl_ops![op_sp_a; $op, $fn, &'a mut $T1, &'b $T2];
521        // Note: no implementation for `&mut primitive`
522        // $crate::unit_impl_ops![op_sp_a; $op, $fn, $T1, &'b mut $T2];
523        // $crate::unit_impl_ops![op_sp_a; $op, $fn, &'a mut $T1, &'b mut $T2];
524    };
525    // (struct OP primitive)
526    (op_refs_ps_a; $op:tt, $fn:ident, $T1:ty, $T2:ty) => {
527        $crate::unit_impl_ops![op_ps_a; $op, $fn, $T2, $T1];
528        $crate::unit_impl_ops![op_ps_a; $op, $fn, $T2, &'b $T1];
529        $crate::unit_impl_ops![op_ps_a; $op, $fn, $T2, &'b mut $T1];
530        // Note: no implementation for `&mut primitive`
531        // $$crate::unit_impl_ops![op_ps_a; $op, $fn, &'a mut $T2, $T1];
532        // $crate::unit_impl_ops![op_ps_a; $op, $fn, &'a mut $T2, &'b $T1];
533        // $crate::unit_impl_ops![op_ps_a; $op, $fn, &'a mut $T2, &'b mut $T1];
534    };
535
536    // ## implements all the variants of a single `unary` operator.
537    (op_refs_u; $op:tt, $fn:ident, $T1:ty) => {
538        $crate::unit_impl_ops![op_u; $T1, $op, $fn, $T1];
539        $crate::unit_impl_ops![op_u; $T1, $op, $fn, &'a $T1];
540        $crate::unit_impl_ops![op_u; $T1, $op, $fn, &'a mut $T1];
541    };
542
543    // # internal API: implements a single variant of an operator
544    // -------------------------------------------------------------------------
545
546    // ## implements a single `non-assign` operator
547    //
548    // (struct OP struct)
549    //
550    // ### Arguments
551    //
552    // - $type:  the return type for the implementation.
553    // - $op:    the operator trait
554    // - $fn:    the operator function
555    // - $for:   the main type for the implementation, can be a reference.
556    // - $rhs:   the right hand side of the operation, can be a reference.
557    //
558    (op_ss; $type:ty, $op:tt, $fn: ident, $for:ty, $rhs:ty) => {
559        #[allow(clippy::extra_unused_lifetimes)]
560        impl<'a, 'b> core::ops::$op<$rhs> for $for {
561            type Output = $type;
562            fn $fn(self, rhs: $rhs) -> Self::Output {
563                <$type>::from_primitive(self.0.$fn(rhs.0))
564            }
565        }
566    };
567    // (struct OP primitive)
568    (op_sp; $type:ty, $op:tt, $fn: ident, $for:ty, $rhs:ty) => {
569        #[allow(clippy::extra_unused_lifetimes)]
570        impl<'a, 'b> core::ops::$op<$rhs> for $for {
571            type Output = $type;
572            fn $fn(self, rhs: $rhs) -> Self::Output {
573                <$type>::from_primitive(self.0.$fn(rhs))
574            }
575        }
576    };
577    // (primitive OP struct)
578    (op_ps; $type:ty, $op:tt, $fn: ident, $for:ty, $rhs:ty) => {
579        #[allow(clippy::extra_unused_lifetimes)]
580        impl<'a, 'b> core::ops::$op<$rhs> for $for {
581            type Output = $type;
582            fn $fn(self, rhs: $rhs) -> Self::Output {
583                <$type>::from_primitive(self.$fn(rhs.0))
584            }
585        }
586    };
587
588    // ## implements a single `assign` operator
589    //
590    // (struct OP primitive)
591    (op_ss_a; $op:tt, $fn: ident, $for:ty, $rhs:ty) => {
592        #[allow(clippy::extra_unused_lifetimes)]
593        impl<'a, 'b> core::ops::$op<$rhs> for $for {
594            fn $fn(&mut self, rhs: $rhs) {
595                self.0.$fn(rhs.0)
596            }
597        }
598    };
599    // (struct OP primitive)
600    (op_sp_a; $op:tt, $fn: ident, $for:ty, $rhs:ty) => {
601        #[allow(clippy::extra_unused_lifetimes)]
602        impl<'a, 'b> core::ops::$op<$rhs> for $for {
603            fn $fn(&mut self, rhs: $rhs) {
604                self.0.$fn(rhs)
605            }
606        }
607    };
608    // (primitive OP struct)
609    (op_ps_a; $op:tt, $fn: ident, $for:ty, $rhs:ty) => {
610        #[allow(clippy::extra_unused_lifetimes)]
611        impl<'a, 'b> core::ops::$op<$rhs> for $for {
612            fn $fn(&mut self, rhs: $rhs) {
613                self.$fn(rhs.0)
614            }
615        }
616    };
617
618    // ## implements a single `unary` operator.
619    (op_u; $type:ty, $op:tt, $fn: ident, $for:ty) => {
620        #[allow(clippy::extra_unused_lifetimes)]
621        impl<'a> core::ops::$op for $for {
622            type Output = $type;
623            fn $fn(self) -> Self::Output {
624                <$type>::from_primitive(self.0.$fn())
625            }
626        }
627    };
628];
629
630/// Implements formatting traits for a unit struct containing a primitive.
631#[macro_export]
632#[doc(hidden)]
633macro_rules! unit_impl_fmt [
634    (all; $type:ty) => {
635        $crate::unit_impl_fmt![bases+display; $type];
636        $crate::unit_impl_fmt![scientific; $type];
637    };
638
639    (bases+display; $type:ty) => {
640        $crate::unit_impl_fmt![bases; $type];
641        $crate::unit_impl_fmt![display; $type];
642    };
643
644    (bases; $type:ty) => {
645        $crate::unit_impl_fmt![single; Binary, $type];
646        $crate::unit_impl_fmt![single; Octal, $type];
647        $crate::unit_impl_fmt![single; LowerHex, $type];
648        $crate::unit_impl_fmt![single; UpperHex, $type];
649    };
650
651    (scientific; $type:ty) => {
652        $crate::unit_impl_fmt![single; UpperExp, $type];
653        $crate::unit_impl_fmt![single; LowerExp, $type];
654    };
655
656    (display; $type:ty) => {
657        $crate::unit_impl_fmt![single; Display, $type];
658    };
659
660    (single; $trait:ident, $type:ty) => {
661        impl core::fmt::$trait for $type {
662            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
663                let val = self.0;
664                core::fmt::$trait::fmt(&val, f)
665            }
666        }
667    };
668];
669
670/// Implements a constructor for unit structs from its inner value type,
671/// intended to be called from the `unit_impl_*` macros.
672#[macro_export]
673#[doc(hidden)]
674macro_rules! from_primitive [
675    ($outer:ty, $inner:ty) => {
676        impl $outer {
677            pub(crate) fn from_primitive(value: $inner) -> Self {
678                Self(value)
679            }
680        }
681    }
682];