## accio
__This crate is mostly an experiment, and is not intended for production!__
`accio` retrieves code blocks distributed to multiple sites in the build path,
and puts them together in the call site.
It does this at the compile time; therefore no code execution takes place in
load-time (`ctor`) or runtime (any kind of lazy initialization).
It allows for partial implementations of functions, enums,
struct fields, match statements and more.
There are still many quirks with it; and they are __not likely to be
solved in the future__. Just to name a few;
- Macro execution paths are not checked __AT ALL__,
- Conditional compilation flags are blatantly disregarded,
- Incremental compilation might cause some problems with when the macros are re-evaluated,
- Error messages will point to incorrect places,
- The `accio_emit` macro is only matched by name; and name overlaps are not checked for,
- None of the macros in this crate can be nested,
- There is no way for an `accio_emit` statement to dynamically refer to its own path,
- The source path is simply recursively traversed for `.rs` files; instead
of verifying that any of these files are imported somewhere,
- There are many possible errors during parsing that are silently omitted,
- It does not work with documentation examples! (Yes, every example in the docs is `no_run`.)
- I simply didn't test how it would behave with multiple crates.
For most use-cases; I can recommend `inventory`, `linkme`, or `ctor` crates.
For automatically importing all modules in a directory, you can use `automod`.
# Contribution
I'm unlikely to respond to issues in this crate; but if you think
you can make this usable in any way; go for it. So PRs are welcome I guess.
# Use cases
`accio` can be used for collecting statements in a function body as follows:
```no_run
use accio::*;
// some_file.rs
accio_emit! {
// accio_emit's block must be written
// as `scope_name { code_block }` pairs.
// multiple blocks can be listed as follows:
first_scope {
val = 1;
}
second_scope {
val += 2;
}
}
// some_other_file.rs
accio_emit! {
// the same scope name can have multiple
// blocks; these are merged in an
// undetermined order.
second_scope {
val += 3;
}
}
// another_file.rs
let mut val = 0;
assert_eq!(val, 0);
// include the first scope:
// this will evaluate to `val = 1;`
accio!(first_scope);
assert_eq!(val, 1);
// include the second scope:
// this will evaluate to either
// `val += 2; val += 3;` or
// `val += 3; val += 2;`.
accio!(second_scope);
assert_eq!(val, 6);
```
A more meaningful use case is automatically gathering enum variants.
However, due to Rust's grammar rules, the `accio!` macro cannot be
placed inside the braces of an enum or a struct. The following would
not compile:
```compile_fail
use accio::*;
enum SomeEnum {
accio!(enum_variants)
}
```
This would yield:
```no_compile
error: expected one of `(`, `,`, `=`, `{`, or `}`, found `!`
--> src/lib.rs:60:10
|
```
Instead, we can use the `accio_body` attribute macro:
```no_run
use accio::*;
#[accio_body(enum_variants)]
enum SomeEnum {
// this part MUST be empty!
}
#[accio_body(struct_fields)]
struct SomeStruct {
/* this part MUST be empty! */
}
#[accio_body(array_elems)]
static SOME_ARRAY: &[i32] = &[];
accio_emit! {
enum_variants {
FirstVariant,
}
enum_variants {
SecondVariant(String),
}
struct_fields {
pub name: String,
}
array_elems: {
42,
}
}
// ...and so on
```
Note that `accio_body` implementation places the code into the
first __empty__ curly brace (`{}`) or square bracket (`[]`) scope.
Therefore the following variants will fail:
```no_run
use accio::*;
#[accio_body(enum_variants)]
enum FailingEnum {
// there is code within the braces
AlreadySomeVariant,
}
#[accio_body(struct_fields)]
struct FailingStruct; // no braces!
```
You can still add comments, they do not cause issues.
See `examples/` for more detailed examples.