update readme, set add nix shell
This commit is contained in:
@@ -1 +1,4 @@
|
||||
target/
|
||||
|
||||
.direnv
|
||||
.envrc
|
||||
@@ -2,6 +2,95 @@
|
||||
|
||||
**Misses** is a DSL compiler that transforms `.mrs` macro definitions into ready-to-use Rust proc macro source files. Write your macro once in a concise, readable syntax; Misses generates the full `syn`/`quote` boilerplate for you.
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Why Misses?
|
||||
|
||||
Writing proc macros means wrestling with `syn` parsing, `quote!` boilerplate, error handling, and variadic patterns. You write the same patterns over and over.
|
||||
|
||||
**Misses lets you write the macro once, in readable syntax, and generates all the boilerplate for you.**
|
||||
|
||||
Here's a real example:
|
||||
|
||||
### `derive_getters.mrs`
|
||||
|
||||
```mrs
|
||||
macro derive_getters! {
|
||||
struct $name:ident { $($field:ident : $ty:ty),* } => {
|
||||
T~{
|
||||
impl $name {
|
||||
for field in $fields =>
|
||||
pub fn $field.name(&self) -> &$field.ty { &self.$field.name }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<details>
|
||||
|
||||
<summary>
|
||||
<b>Generated output</b>
|
||||
</summary>
|
||||
|
||||
```rust
|
||||
|
||||
extern crate proc_macro;
|
||||
#[proc_macro]
|
||||
pub fn derive_rpc(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
let input = proc_macro2::TokenStream::from(input);
|
||||
use quote::format_ident;
|
||||
let (name, params, ret) = {
|
||||
use syn::parse::Parser as _;
|
||||
let __parser = |
|
||||
_input: syn::parse::ParseStream,
|
||||
| -> syn::Result<(syn::Ident, Vec<(syn::Ident, syn::Type)>, syn::Type)> {
|
||||
let name: syn::Ident = _input.parse()?;
|
||||
let params = {
|
||||
let mut __f = Vec::new();
|
||||
while !__brace_content.is_empty() {
|
||||
let __fn: syn::Ident = __brace_content.parse()?;
|
||||
__brace_content.parse::<syn::Token![:]>()?;
|
||||
let __ft: syn::Type = __brace_content.parse()?;
|
||||
__f.push((__fn, __ft));
|
||||
if __brace_content.peek(syn::Token![,]) {
|
||||
__brace_content.parse::<syn::Token![,]>()?;
|
||||
}
|
||||
}
|
||||
__f
|
||||
};
|
||||
let ret: syn::Type = _input.parse()?;
|
||||
Ok((name, params, ret))
|
||||
};
|
||||
match __parser.parse2(input.clone()) {
|
||||
Ok(v) => v,
|
||||
Err(e) => return e.into_compile_error().into(),
|
||||
}
|
||||
};
|
||||
let req_name = format_ident!("{}Request", name);
|
||||
let res_name = format_ident!("{}Response", name);
|
||||
let __spread_0: proc_macro2::TokenStream = params
|
||||
.iter()
|
||||
.map(|(__field_name, __field_ty)| {
|
||||
quote::quote! {
|
||||
pub # __field_name : # __field_ty,
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
let __output = quote::quote! {
|
||||
pub struct # req_name { # __spread_0 } pub struct # res_name { pub result : #
|
||||
ret, }
|
||||
};
|
||||
__output.into()
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Quick start
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
{ pkgs ? import <nixpkgs> {}}:
|
||||
pkgs.mkShell {
|
||||
buildInputs = with pkgs; [
|
||||
# Rust toolchain
|
||||
cargo
|
||||
rustc
|
||||
rustfmt
|
||||
clippy
|
||||
rust-analyzer
|
||||
|
||||
# Additional tools
|
||||
cargo-watch
|
||||
cargo-edit
|
||||
# Profiling tools
|
||||
cargo-flamegraph
|
||||
samply
|
||||
perf
|
||||
];
|
||||
|
||||
# Environment variables
|
||||
RUST_BACKTRACE = 1;
|
||||
}
|
||||
Reference in New Issue
Block a user