Crates.io | defamed |
lib.rs | defamed |
version | 0.2.0 |
source | src |
created_at | 2024-09-17 09:50:20.865331 |
updated_at | 2024-10-06 09:05:51.013093 |
description | Default, positional and named parameters |
homepage | |
repository | https://github.com/cruzerngz/defamed |
max_upload_size | |
id | 1377282 |
size | 83,797 |
Tag supported items with #[defamed::defamed]
, default parameters with #[def]
and use the generated macro with any combination of positional and named parameters.
#[defamed::defamed]
fn complex_function(
lhs: i32,
rhs: i32,
// literals can be used as default values
#[def(true)] add: bool,
// if no default value is provided, the type must implement Default
#[def] divide_result_by: Option<i32>,
) -> i32 {
let intermediate = if add { lhs + rhs } else { lhs - rhs };
match divide_result_by {
Some(div) => intermediate / div,
None => intermediate,
}
}
assert_eq!(10, complex_function!(5, 5));
assert_eq!(10, complex_function!(rhs = 5, lhs = 15, add = false));
assert_eq!(5, complex_function!(5, 5, divide_result_by = Some(2)));
Struct macros can be used in-place of the builder pattern.
/// A struct that does not fully implement core::default::Default
#[defamed::defamed]
#[derive(Debug, PartialEq, Default)]
struct PartialDefault<'a> {
pub inner: &'a [u8],
#[def]
pub idx: usize,
#[def]
pub len: usize,
}
// use struct update syntax `..` to fill in all remaining fields
let pd = PartialDefault! {inner: &[1, 2, 3], idx: 1, ..};
let reference = PartialDefault { inner: &[1, 2, 3], idx: 1, len: 0 };
assert_eq!(reference, pd);
/// Tuple structs work very similarly to functions - but all parameters are positional
#[derive(Debug, PartialEq)]
#[defamed::defamed]
struct TupleStruct(i32, #[def] i32, #[def] bool);
let ts_a = TupleStruct!(5);
let ts_b = TupleStruct!(5, 0);
let reference = TupleStruct(5, 0, false);
assert_eq!(reference, ts_a);
assert_eq!(reference, ts_b);
default_args
macro requires explicit import to call underlying function
The macro accepts parameters in any permutation as long as the following conditions are met:
/// Add/sub 2 numbers, then take the absolute value, if applicable
#[defamed::defamed]
fn pos_and_def(
lhs: i32,
rhs: i32,
#[def(true)]
add: bool,
#[def]
abs_val: bool
) -> i32 {
let inter = if add {lhs + rhs} else {lhs - rhs};
if abs_val {inter.abs()} else {inter}
}
// original fn
assert_eq!(20, pos_and_def(5, 15, true, false));
// all positional
assert_eq!(20, pos_and_def!(5, 15, true, false));
// all named
assert_eq!(20, pos_and_def!(lhs=5, rhs=15, add=true, abs_val=false));
// all named, in any order, defaults last
assert_eq!(20, pos_and_def!(rhs=15, lhs=5, abs_val=false, add=true));
// defaults excluded
assert_eq!(20, pos_and_def!(5, 15));
// defaults excluded, positional in any order
assert_eq!(20, pos_and_def!(rhs=15, lhs=5));
// some positional, some named
assert_eq!(20, pos_and_def!(5, rhs=15));
// overriding first default parameter as positional
assert_eq!(20, pos_and_def!(25, 5, false));
// overriding second default parameter as named
assert_eq!(20, pos_and_def!(5, -25, abs_val=true));
Macros generated by defamed
can be exported and used by other crates if the path to the underlying function is public.
For functions that are used in the same module as they are defined, the macro resolves the call directly.
#[defamed::defamed]
fn local_scope() {}
// macro resolves to:
local_scope!() => local_scope()
When private functions are used inside child modules, the module path relative to the crate root needs to be provided.
#[defamed::defamed(crate)]
fn top_level_local_scope() {}
mod inner_consumer {
fn inner() {
super::top_level_local_scope!()
}
}
Functions with non-private visibility are called with their corresponding fully qualified path relative to the crate root. The macro will require the module path to the function relative to the crate root.
For functions defined in the crate root, use crate
as a path instead.
These macros can be used inside or imported by other crates as the macro substitutes metavariables.
// public vis in root scope
#[defamed::defamed(crate)]
pub fn root_scope() {}
pub mod inner {
// restricted vis in module `inner`
#[defamed::defamed(inner)]
pub(crate) fn crate_scope() {}
}
// macros resolve to:
crate_scope!() => $crate::inner::crate_scope()
root_scope!() => $crate::root_scope()
Struct fields must be at least as visible as the struct itself. Public structs may be constructed by external crates, so the macro will require all fields to be public.
Valid examples:
#[defamed::defamed]
struct Private {
field: i32
}
// restricted visibility or higher
#[defamed::defamed(crate)]
pub(crate) struct Restricted {
#[def]
pub field: i32
}
#[defamed::defamed(crate)]
pub struct Public {
#[def]
pub field: i32
}
#[defamed::defamed(crate)]
pub struct PublicTuple(pub i32, #[def] pub i32);
Invalid examples:
#[defamed::defamed(crate)]
pub struct Public {
pub field: i32
}
#[defamed::defamed(crate)]
pub struct InvalidOrder {
/// default fields must be defined last - compile error
#[def]
pub field_a: i32,
pub field_b: u32,
}
// all fields must be public
#[defamed::defamed(crate)]
pub struct PublicTuple(pub i32, #[def] i32);
// will not compile - unit structs do not have any fields
#[defamed::defamed]
struct UnitStruct;
[!CAUTION] The size of the macro generated (number of match arms) is exponentially related to $max(positional, default)$. This is because the macro contains all permutations of positional and default parameters.
It is recommended that items do not exceed 9 positional and/or 9 default parameters. Exceeding this number will cause the build times to increase significantly.
impl
block