[−][src]Macro index_vec::define_index_type
Generate the boilerplate for a newtyped index struct, for use with
IndexVec
.
In the future, if the compile-time overhead of doing so is reduced, this may be replaced with a proc macro.
Usage
Standard
The rough usage pattern of this macro is:
index_vec::define_index_type! { // Note that isn't actually a type alias, `MyIndex` is // actually defined as a struct. XXX is this too confusing? pub struct MyIndex = u32; // optional extra configuration here of the form: // `OPTION_NAME = stuff;` // See below for details. }
Note that you can use other index types than u32
, and you can set it to be
MyIndex(pub u32)
as well. Currently, the wrapped item be a tuple struct,
however (patches welcome).
Customization
After the struct declaration, there are a number of configuration options the macro uses to customize how the type it generates behaves. For example:
index_vec::define_index_type! { pub struct Span = u32; // Don't allow any spans with values higher this. MAX_INDEX = 0x7fff_ff00; // But I also am not too worried about it, so only // perform the asserts in debug builds. DISABLE_MAX_INDEX_CHECK = cfg!(not(debug_assertions)); }
Configuration options
This macro has a few ways you can customize it's output behavior. There's not really any great syntax I can think of for them, but, well.
MAX_INDEX = <expr producing usize>
Assert if anything tries to construct an index above that value.
By default, this is $raw_type::max_value() as usize
, e.g. we check that
our cast from usize
to our wrapper is lossless, but we assume any all
instance of $raw_type
is valid in this index domain.
Note that these tests can be disabled entirely, or conditionally, with
DISABLE_MAX_INDEX_CHECK
. Additionally, the generated type has
from_usize_unchecked
and from_raw_unchecked
functions which can be used
to ignore these checks.
DISABLE_MAX_INDEX_CHECK = <expr>;
Set to true to disable the assertions mentioned above. False by default.
To be clear, if this is set to false, we blindly assume all casts between
usize
and $raw_type
succeed.
A common use is setting DISABLE_MAX_INDEX_CHECK = !cfg!(debug_assertions)
to avoid the tests at compile time
For the sake of clarity, disabling this cannot lead to memory unsafety -- we still go through bounds checks when accessing slices, and no unsafe code should rely on on these checks (unless you write some, and don't! only use this for correctness!).
DEFAULT = <expr>;
If provided, we'll implement Default
for the index type using this
expresson.
Example:
index_vec::define_index_type! { pub struct MyIdx = u16; MAX_INDEX = (u16::max_value() - 1) as usize; // Set the default index to be an invalid index, as // a hacky way of having this type behave somewhat // like it were an Option<MyIdx> without consuming // extra space. DEFAULT = (MyIdx::from_raw_unchecked(u16::max_value())); }
DEBUG_FORMAT = <expr>;
By default we write the underlying integer out in a Debug implementation
with {:?}
. Sometimes you'd like more info though. For example, the type of
the index. This can be done via DEBUG_FORMAT
:
index_vec::define_index_type! { struct FooIdx = usize; DEBUG_FORMAT = "Foo({})"; } // Then ... let v = FooIdx::new(10); assert_eq!("Foo(10)", format!("{:?}", v));
DISPLAY_FORMAT = <expr>;
Similarly to DEBUG_FORMAT
, we can implement Display for you. Unlike
DEBUG_FORMAT
, if you do not set this, we will not implement Display
for
the index type.
index_vec::define_index_type! { struct FooIdx = usize; DISPLAY_FORMAT = "{}"; // Note that you can use both DEBUG_FORMAT and DISPLAY_FORMAT. DEBUG_FORMAT = "#<foo {}>"; } // Then ... let v = FooIdx::new(10); assert_eq!("10", format!("{}", v)); assert_eq!("#<foo 10>", format!("{:?}", v));
IMPL_RAW_CONVERSIONS = true;
We always automatically implement From<usize> for YourIndex
and
From<YourIndex> for usize
. We don't do this for the "raw" type (e.g. u32
if your type is declared as struct FooIdx = u32;
), unless you request it
via this option. It's an error to use this if your raw type is usize.
index_vec::define_index_type! { struct FooIdx = u32; IMPL_RAW_CONVERSIONS = true; } let as_index = FooIdx::from(5u32); let as_u32 = u32::from(as_index); assert_eq!(as_u32, 5);