dtolnay / proc-macro-workshop Goto Github PK
View Code? Open in Web Editor NEWLearn to write Rust procedural macros [Rust Latam conference, Montevideo Uruguay, March 2019]
License: Apache License 2.0
Learn to write Rust procedural macros [Rust Latam conference, Montevideo Uruguay, March 2019]
License: Apache License 2.0
Thank you for creating this project! It's what I've been looking for to learn how to write procedural macros in rust.
I noticed that you are the co-author of the proc-macro2 crate; could you add some examples of how to use that crate here? Also, could you give examples of how to use darling?
I know nothing about writing macros, but want to learn how to do so correctly so that end users actually want to use my macros, instead of feeling that they have to use them. So once again, thank you for making this project!
If would if if gods if would if soon if would if references if self
if would if will if would if god if would if tests if would if fail?
use proc_macro::TokenStream;
use syn::{DeriveInput, __private::quote::quote, parse_macro_input};
#[proc_macro_derive(Builder)]
pub fn derive(input: TokenStream) -> TokenStream {
let ast = parse_macro_input!(input as DeriveInput);
let name = &ast.ident;
let bname = format!("{}Builder", name);
let bident = syn::Ident::new(&bname, name.span());
let expanded = quote! {
pub struct #bident {
executable: Option<String>,
args: Option<Vec<String>>,
env: Option<Vec<String>>,
current_dir: Option<String>,
}
impl #bident {
pub fn executable(&mut self, executable: String) -> &mut self {
self.executable = Some(executable);
self
}
pub fn args(&mut self, args: Vec<String>) -> &mut self {
self.args = Some(args);
self
}
pub fn env(&mut self, env: Vec<String>) -> &mut self {
self.env = Some(env);
self
}
pub fn current_dir(&mut self, current_dir: String) -> &mut self {
self.current_dir = Some(current_dir);
self
}
}
impl #name {
fn builder() -> #bident {
#bident {
executable: None,
args: None,
env: None,
current_dir: None
}
}
}
};
expanded.into()
}
if would if throws if gods if would if error?
expected type, found module `self`
--> $DIR/02-create-builder.rs:47:10
|
47 | #[derive(Builder)]
| ^^^^^^^ help: a self type with a similar name exists: `Self`
|
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
if would if could if would if post if would if answers if gods if would if solutions if to if would if lessons?
if would if is if gods https://www.youtube.com/watch?v=geovSK3wMB8&t=17s if minute if 42.22
In the build derive macro, 04-call-builder
, the build
function takes a &mut self
, and it returns a Command
with the ownership of the fields. So I have to clone
the fields in the implementation, which is not correct I suppose.
The build function should take the ownership of Builder, and return a builded result.
like this:
fn build(self) -> Result<Command, dyn Error>{
unimplemented!()
}
I'd like to see a basic implementation of a macro for Python-style list and map comprehensions, and decide whether it would be a better teaching example for function-like proc macros than the current seq!
project.
Something like:
let squares_map = c![n => n*n for n in 0..100 if n % 5 != 0];
Suggested by @jonhoo.
there's probably something i'm not getting here, but i checked out the builder and the bitfield code and they are empty. what's happening?
Hello. First things first, this is an excellent learning resource for Rust. If I was a recruiter, I would require passing this workshop before hiring. =) Now to the issue: In the builder project tests/07-repeated-field.rs , the test can't pass because the env field isn't optional but the test code doesn't set it before calling build(). A line like .env("FOO=1".to_owned())
just before the call to build (line 49) should fix this. It made it pass for me.
I am trying to solve 04 right now. There is just a small thing left where I was wondering how this was done in the reference implementation.
My error output currently looks like this:
EXPECTED:
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
error[E0277]: the trait bound `bitfield::checks::SevenMod8: bitfield::checks::TotalSizeIsMultipleOfEightBits` is not satisfied
--> tests/04-multiple-of-8bits.rs:53:1
|
53 | #[bitfield]
| ^^^^^^^^^^^ the trait `bitfield::checks::TotalSizeIsMultipleOfEightBits` is not implemented for `bitfield::checks::SevenMod8`
|
= help: the trait `bitfield::checks::TotalSizeIsMultipleOfEightBits` is implemented for `bitfield::checks::ZeroMod8`
= note: this error originates in the attribute macro `bitfield` (in Nightly builds, run with -Z macro-backtrace for more info)
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
ACTUAL OUTPUT:
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
error[E0277]: the trait bound `SevenMod8: TotalSizeIsMultipleOfEightsBits` is not satisfied
--> tests/04-multiple-of-8bits.rs:53:1
|
53 | #[bitfield]
| ^^^^^^^^^^^ the trait `TotalSizeIsMultipleOfEightsBits` is not implemented for `SevenMod8`
|
= help: the trait `TotalSizeIsMultipleOfEightsBits` is implemented for `ZeroMod8`
note: required by a bound in `width_check`
--> src/lib.rs
|
| pub fn width_check<T: TotalSizeIsMultipleOfEightsBits>() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `width_check`
= note: this error originates in the attribute macro `bitfield` (in Nightly builds, run with -Z macro-backtrace for more info)
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
I am happy with this, but I was curious why my output does not have the full paths as the reference implementation had and what to consider to get those full paths.
Kind Regards
Robin
I had generated the stderr files before writing the comments at the top of each test case.
Hello,
Thank you for the wonderful workshop. It is helping me learn macros!
One thing is that I am using the cargo expand
command... and I'm not getting clean expansion...
#![feature(prelude_import)]
#[prelude_import]
use std::prelude::rust_2021::*;
#[macro_use]
extern crate std;
extern crate proc_macro;
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, DeriveInput};
#[proc_macro_derive(Builder)]
pub fn derive(input: TokenStream) -> TokenStream {
let ast = match ::syn::parse_macro_input::parse::<DeriveInput>(input) {
::syn::__private::Ok(data) => data,
::syn::__private::Err(err) => {
return ::syn::__private::TokenStream::from(err.to_compile_error());
}
};
let name = &ast.ident;
let bname = syn::Ident::new(
&{
let res = ::alloc::fmt::format(::core::fmt::Arguments::new_v1(
&["", "Builder"],
&[::core::fmt::ArgumentV1::new_display(&name)],
));
res
},
name.span(),
);
let fields = if let syn::Data::Struct(syn::DataStruct {
fields: syn::Fields::Named(syn::FieldsNamed { ref named, .. }),
..
}) = ast.data
{
named
} else {
::core::panicking::panic("not implemented")
};
let bname_struct_fields = fields.iter().map(|field| {
let field_name = &field.ident;
let field_type = &field.ty;
{
let mut _s = ::quote::__private::TokenStream::new();
::quote::ToTokens::to_tokens(&field_name, &mut _s);
::quote::__private::push_colon(&mut _s);
::quote::__private::push_ident(&mut _s, "std");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "option");
::quote::__private::push_colon2(&mut _s);
::quote::__private::push_ident(&mut _s, "Option");
::quote::__private::push_lt(&mut _s);
::quote::ToTokens::to_tokens(&field_type, &mut _s);
::quote::__private::push_gt(&mut _s);
_s
}
});
let builder = {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "pub");
::quote::__private::push_ident(&mut _s, "struct");
::quote::ToTokens::to_tokens(&bname, &mut _s);
::quote::__private::push_group(&mut _s, ::quote::__private::Delimiter::Brace, {
let mut _s = ::quote::__private::TokenStream::new();
{
use ::quote::__private::ext::*;
let has_iter = ::quote::__private::ThereIsNoIteratorInRepetition;
#[allow(unused_mut)]
let (mut bname_struct_fields, i) = bname_struct_fields.quote_into_iter();
let has_iter = has_iter | i;
let _: ::quote::__private::HasIterator = has_iter;
while true {
let bname_struct_fields = match bname_struct_fields.next() {
Some(_x) => ::quote::__private::RepInterp(_x),
None => break,
};
::quote::ToTokens::to_tokens(&bname_struct_fields, &mut _s);
::quote::__private::push_comma(&mut _s);
}
};
_s
});
::quote::__private::push_ident(&mut _s, "impl");
::quote::ToTokens::to_tokens(&name, &mut _s);
::quote::__private::push_group(&mut _s, ::quote::__private::Delimiter::Brace, {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "pub");
::quote::__private::push_ident(&mut _s, "fn");
::quote::__private::push_ident(&mut _s, "builder");
::quote::__private::push_group(
&mut _s,
::quote::__private::Delimiter::Parenthesis,
::quote::__private::TokenStream::new(),
);
::quote::__private::push_rarrow(&mut _s);
::quote::ToTokens::to_tokens(&bname, &mut _s);
::quote::__private::push_group(&mut _s, ::quote::__private::Delimiter::Brace, {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "return");
::quote::ToTokens::to_tokens(&bname, &mut _s);
::quote::__private::push_group(&mut _s, ::quote::__private::Delimiter::Brace, {
let mut _s = ::quote::__private::TokenStream::new();
::quote::__private::push_ident(&mut _s, "executable");
::quote::__private::push_colon(&mut _s);
::quote::__private::push_ident(&mut _s, "None");
::quote::__private::push_comma(&mut _s);
::quote::__private::push_ident(&mut _s, "args");
::quote::__private::push_colon(&mut _s);
::quote::__private::push_ident(&mut _s, "None");
::quote::__private::push_comma(&mut _s);
::quote::__private::push_ident(&mut _s, "env");
::quote::__private::push_colon(&mut _s);
::quote::__private::push_ident(&mut _s, "None");
::quote::__private::push_comma(&mut _s);
::quote::__private::push_ident(&mut _s, "current_dir");
::quote::__private::push_colon(&mut _s);
::quote::__private::push_ident(&mut _s, "None");
::quote::__private::push_comma(&mut _s);
_s
});
_s
});
_s
});
_s
};
return builder.into();
}
const _: () = {
extern crate proc_macro;
#[rustc_proc_macro_decls]
#[allow(deprecated)]
static _DECLS: &[proc_macro::bridge::client::ProcMacro] =
&[proc_macro::bridge::client::ProcMacro::custom_derive(
"Builder",
&[],
derive,
)];
};
I've seen other output, per tutorial by Jon Gjengset](https://www.youtube.com/watch?v=geovSK3wMB8), and it looks clearer and helpful. While the current expand is filled with " ::quote::__private::push_comma"... Not sure if it is just a setting? Any direction or help would be really appreciated!
Thank you!
builder/tests/02-create-builder.rs
says "Before moving on, have the macro also generate:" and it shows the CommandBuilder
struct based on the input Command
type, but with each field made Option
al if it's not already.
I understand why they'd be optional -- the builder pattern requires adding individual fields before construction of the output type -- but is dynamically making fields optional an intended piece of test 2? It comes quite early in the workshop, but doing so seems rather complicated.
In particular, it seems to assume knowledge gained in test 6 (see #12) regarding detection of whether a field has Option
(because one field is already Option
) plus knowledge of modifying field types.
Simpler tasks, like building an ident, have a resource link, but there's no comment about type modification.
Sorry if I'm missing an obvious alternative for adding Option
!
I use rustc 1.54.0 (a178d0322 2021-07-26)
, in seq/tests/03-expand-four-errors.rs
, span in the expected error message doesn't include the ending ;
as shown below.
error: error number 0
--> tests/03-expand-four-errors.rs:20:5
|
20 | compile_error!(concat!("error number ", stringify!(N)));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
However, my solution gives an almost equal version except that the span ^
includes the ending ';'.
error: error number 0
--> tests/03-expand-four-errors.rs:20:5
|
20 | compile_error!(concat!("error number ", stringify!(N)));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
I try to add compile_error!
explicitly, and the error message also includes the ending ;
.
error: error number 0
--> main.rs:13:5
|
13 | compile_error!(concat!("error number ", stringify!(0)));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
I wonder whether it's just an compiler version issue or it's intended to be so and I should figure out how to control the span in error meesage generated by compile_error!
?
At least the seq!
project will require some rework because ident concatenation Variant#N
is no longer legal syntax lexically. There may be other incompatibilities in the other projects as well.
Very demoralizing, like I cannot even learn the first thing about writing a procedural macro here.
I will try copying
syn = "1.0"
quote = "1.0"
from the syn readme though.
I want parsing recursive like this ”any“,”all” proc content. Is there a simpler tool or example?
(command is convert fn to trait struct, like rocket get/post macros)
// get name content
#[event(command("hello {name}"))]
async fn hello( name: Option<String>) -> anyhow::Result<bool> {
if name.is_none() {
return Ok(false);
}
Ok(true)
}
// all , any
#[event(all(command("hello {name}", filter = "i_am_filter")))]
async fn hello( name: Option<String>) -> anyhow::Result<bool> {
if name.is_none() && name.unwrap().start_with("123") {
return Ok(false);
}
event.send_message_to_source(format!("hello {}", name.unwrap()).parse_message_chain()).await.unwrap();
Ok(true)
}
async fn i_am_filter( name: Option<String>) -> anyhow::Result<bool> {
if name.is_none() {
return Ok(false);
}
// do some
Ok(true)
}
#[event(regexp("^123$"))]
Thank you for creating this project; I'm moving through it very slowly, but I wanted to say thank you for putting it together. It's been a big help in learning to read macros in rust!
In the newer version of syn
and quote
this 08-unrecognized-attribute.rs
builder test fails.
EXPECTED:
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
error: expected `builder(each = "...")`
--> $DIR/08-unrecognized-attribute.rs:22:7
|
22 | #[builder(eac = "arg")]
| ^^^^^^^^^^^^^^^^^^^^
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
ACTUAL OUTPUT:
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
error: expected `builder(each = "...")`
--> $DIR/08-unrecognized-attribute.rs:22:15
|
22 | #[builder(eac = "arg")]
| ^^^^^^^^^^^
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
Rust version: rustc 1.57.0-nightly (c02371c44 2021-10-01)
syn: 1.0.78
quote: 1.0.9
Hi,
my code failed when executing seq test case 03, the output is:
ACTUAL OUTPUT:
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
error: error number 0
--> tests/03-expand-four-errors.rs:19:1
|
19 | / seq!(N in 0..4 {
20 | | compile_error!(concat!("error number ", stringify!(N)));
21 | | });
| |__^
|
= note: this error originates in the macro `seq` (in Nightly builds, run with -Z macro-backtrace for more info)
error: error number 1
--> tests/03-expand-four-errors.rs:19:1
|
19 | / seq!(N in 0..4 {
20 | | compile_error!(concat!("error number ", stringify!(N)));
21 | | });
| |__^
|
= note: this error originates in the macro `seq` (in Nightly builds, run with -Z macro-backtrace for more info)
error: error number 2
--> tests/03-expand-four-errors.rs:19:1
|
19 | / seq!(N in 0..4 {
20 | | compile_error!(concat!("error number ", stringify!(N)));
21 | | });
| |__^
|
= note: this error originates in the macro `seq` (in Nightly builds, run with -Z macro-backtrace for more info)
error: error number 3
--> tests/03-expand-four-errors.rs:19:1
|
19 | / seq!(N in 0..4 {
20 | | compile_error!(concat!("error number ", stringify!(N)));
21 | | });
| |__^
|
= note: this error originates in the macro `seq` (in Nightly builds, run with -Z macro-backtrace for more info)
I even tried to print the result TokenStream before returning and it looks totally correct (begin with "compile_error" as ident).
Download someone else's code from github and test, same output...
rust version: 1.75.0
dependencies:
proc-macro2 = "1.0.81"
syn = { version = "2.0.59", features = ["full", "extra-traits"] }
quote = "1.0.36"
prettyplease = "0.2.1"
repository: https://github.com/apodemakeles/proc-macro-workshop/blob/seq/seq/src/lib.rs
Hi
For a Path
type for Error::Fmt
, how to print it exactly same as the code?
When I convert it to tokenstream, then print it, it has space between path segments and punct.
EXPECTED:
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
error: Error::Fmt should sort before Error::Io
--> tests/06-pattern-path.rs:33:13
|
33 | Error::Fmt(e) => write!(f, "{}", e),
| ^^^^^^^^^^
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
ACTUAL OUTPUT:
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
error: Error :: Fmt should sort before Error :: Io
--> tests/06-pattern-path.rs:33:13
|
33 | Error::Fmt(e) => write!(f, "{}", e),
| ^^^^^^^^^^
At present, I have to use quite a long expression to get the string
path
.segments
.iter()
.map(|seg| seg.ident.to_string())
.collect::<Vec<_>>()
.join("::");
Is there a presentation or book or blog posts that can be followed to learn the necessary knowledge required to accomplish the workshop ?
Currently eprintln output from macros will be displayed but println will not. They should both be shown.
Seq05 introduced new rule to only repeat tokens inside #( ... )*
.
This new rule would cause other tests fall since they don't have their full body inside #( ... )*
.
Broken tests are Seq02, Seq03, Seq04, Seq08 .
So far totally untested on Windows.
Line 35 and 36 cause a "duplicate definitions with name 'env'" error.
Hi,
I spent a long time tracing down a bug in my implementation of the sorted
macro against the 06-pattern-path test. Namely, my output always looked like this:
error: Error::Fmt should sort before Error::Io
--> main.rs:23:7
|
23 | Error::Fmt(e) => write!(f, "{}", e),
| ^^^^^
where the error span is just Error
instead of the expected Error::Fmt
. I checked my code to made sure in my code that it's indeed the path's span being stored and emitted instead of the ident's. It's even more confusing because cargo expand
gives the expected output whereas the cargo test
and cargo run
gives different answer.
After more debugging and searching I finally stumbled upon this issue. So after switching my toolchain from stable to nightly, the test passes as expected. Now I see it's because the stable proc-macro doesn't allow joining of spans, thus only the first token of the syntax tree is returned upon calling the Spanned::span
function.
I think it may be good to indicate this trick somewhere in note since it's probably not a trivial bug. Anyway, to the future learners who had their head scratched hard for this error, I hope this issue can be helpful :)
Hi! I'm working on implementing the Seq macro and I'm getting a little stuck. It alludes to treating the body of the expression as a TokenStream
and not as some type of syn
AST structure.
I can parse out everything that's instructed in the 01-parse-header.rs
file, but when I get to 02-parse-body.rs
, I get stuck on how to treat the loop body of the macro as a TokenStream
. Additionally, when I attempt to run cargo test
, I get an error on unexpected tokens.
The error message:
Testing tests/01-parse-header.rs ... error
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
error: unexpected token
--> $DIR/01-parse-header.rs:25:16
|
25 | seq!(N in 0..8 {
| ________________^
26 | | // nothing
27 | | });
| |_^
┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈
Link to the code I have so far: https://github.com/ELD/proc-macro-workshop/blob/seq-macro/seq/src/lib.rs
Any guidance would be appreciated!
Sorry if its really obvious. Where do I find the article, video, or whatever I am supposed to follow along?
I received unused import warnings which lead to a compile error missmatch for an otherwise correct test 04.
I solved this issue by adding #![allow(unused_imports)]
to the 04 code and adapting the line numbers in the *.stderr file.
Hi
Following up on the builder tutorial, I found the transition to 06-optional-field
to the end is tough. It'd help a lot to explain a little in more details what to do or link to similar code about how to check whether Option
exists or not in 06
.
Hi.
I'm wondering if someone can point me to the industrial implementations mentioned in the description. so far I've only found seq here https://github.com/dtolnay/seq-macro.
Thanks
Hi @dtolnay @alexcrichton , any reference implementation for bitfield?
I am stucked at 04-multiple-of-8bits
, which I do not know how to emit codes based on #size % 8
, because we can't resolve the actual value from the expression in proc-macro,
em..........
.................
In sorted::check I forgot to update the last arm and ended comparing all arms with the first arm but still all tests (1-8) passed.
I only noticed my error because I was wondering why test 8 did not fail when having an arm that started with a lower case char (lower chase char > "-") before actually impl. it
EDIT:
For test 8 it also would be a good idea to use match arms that start with a lower case letter (e.g. io::Result) because otherwise the order is correct anyways because all upper case chars are less than "_". At least if you use string comparison.
I have found it to work more reliably than compiletest_rs and would be interested in trying to use it elsewhere.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.