Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
6aef01e
seed commit for fatality based errors
drahnr Dec 2, 2021
86cb205
fatality
drahnr Dec 2, 2021
61605f7
first draft of fatality
drahnr Dec 2, 2021
7789e08
cleanup
drahnr Dec 3, 2021
df37cbf
differnt approach
drahnr Dec 3, 2021
8254614
simplify
drahnr Dec 3, 2021
ec8564e
first working version for enums, with documentation
drahnr Dec 3, 2021
a59a2c4
add split
drahnr Jan 21, 2022
bef8549
fix simple split test case
drahnr Jan 21, 2022
226bbb4
extend README.md
drahnr Jan 21, 2022
fb14c73
update fatality impl
drahnr Jan 25, 2022
9a5e3ca
make tests passed
drahnr Jan 25, 2022
3e4dce0
apply fatality to first subsystem
drahnr Jan 26, 2022
ef4a734
fatality fixes
drahnr Jan 28, 2022
50b56ea
use fatality in a subsystem
drahnr Jan 30, 2022
664a1c9
fix subsystemg
drahnr Jan 30, 2022
0db9f15
fixup proc macro
drahnr Jan 30, 2022
a67484e
fix/test: log::*! do not execute when log handler is missing
drahnr Feb 1, 2022
eb6a205
fix spelling
drahnr Feb 1, 2022
d770480
rename Runtime2 to something sane
drahnr Feb 1, 2022
47b2335
allow nested split with `forward` annotations
drahnr Feb 4, 2022
e24e302
add free license
drahnr Feb 4, 2022
3fc6cd4
enable and fixup all tests
drahnr Feb 4, 2022
346fd5b
use external fatality
drahnr Feb 23, 2022
859922a
bump fatality dep
drahnr Feb 23, 2022
6b29441
migrate availability distribution
drahnr Feb 23, 2022
5b00044
more fatality usage
drahnr Feb 23, 2022
ffb66e3
chore: bump fatality to 0.0.6
drahnr Feb 23, 2022
df26cbf
fixup remaining subsystems
drahnr Feb 23, 2022
9466d1c
chore: fmt
drahnr Feb 23, 2022
6ca4079
make cargo spellcheck happy
drahnr Feb 23, 2022
721e1ec
remove single instance of `#[fatal(false)]`
drahnr Feb 24, 2022
3c3adba
last quality sweep
drahnr Feb 25, 2022
c5d7d10
fixup
drahnr Feb 25, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
first draft of fatality
  • Loading branch information
drahnr committed Feb 25, 2022
commit 61605f7c1c8230a2997cfc9b1108d2dfdb1e0a50
10 changes: 10 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions node/fatality/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
[package]
name = "fatality"
version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
edition = "2021"
description = "Fatality extension to crate thiserror"

[dependencies]
fatality-proc-macro = { path = "./proc-macro" }
Expand Down
2 changes: 2 additions & 0 deletions node/fatality/proc-macro/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
[package]
name = "fatality-proc-macro"
version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
edition = "2021"
description = "Fatality extension to crate thiserror - proc-macro part"

[lib]
proc-macro = true
Expand Down
115 changes: 61 additions & 54 deletions node/fatality/proc-macro/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,38 +1,30 @@
// Copyright 2021 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.

// Polkadot is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Polkadot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.


use proc_macro2::{Ident, TokenStream, Span};
use quote::{quote, ToTokens};
use syn::parse::Parse;
use syn::{Variant, ItemEnum, Path, parse2};
use syn::{Variant, ItemEnum, Path, parse2, Visibility};
use syn::spanned::Spanned;

// TODO
// pub mod keywords {
// syn::custom_keyword!(fatal);
// }



// enum Fatality {
// Fatal,
// Boring,
// }

// impl Parse for IsFatal {
// fn parse(input: ParseStream) -> Result<Fatality> {
// let lookahead = input.lookahead1();
// if lookahead.peek(keywords::fatal) {
// let _ = input.parse::<kw::fatal>()?;
// Ok(Argument::Fatal)
// } else if lookahead.peek(kw::str) {
// Ok(Argument::Str {
// str_token: input.parse::<kw::str>()?,
// eq_token: input.parse()?,
// value: input.parse()?,
// })
// } else {
// Err(lookahead.error())
// }
// }
// }

use proc_macro_crate::{crate_name, FoundCrate};

fn abs(what: impl Into<Path>, loco: Span) -> Path {
Expand Down Expand Up @@ -62,29 +54,29 @@ fn trait_fatality_impl(who: Ident, logic: TokenStream) -> TokenStream {
}
}

fn gen(item: &ItemEnum) -> TokenStream {
fn fatality_gen(item: &ItemEnum) -> TokenStream {
let mut item2 = item.clone();
let name = item.ident.clone();

let mut fatal_variants = Vec::<Variant>::new();
let mut jfyi_variants = Vec::<Variant>::new();
// if there is not a single fatal annotation, we can just replace `#[fatality]` with `3[thiserror::Error]`
// if there is not a single fatal annotation, we can just replace `#[fatality]` with `#[derive(thiserror::Error)]`
// without the intermediate type. But impl `trait Fatality` on-top.
let mut fatal_count = 0;
for variant in item2.variants.iter_mut() {
dbg!(&variant);
let mut is_fatal = false;
while let Some(idx) = variant.attrs
.iter().enumerate()
.find_map(|(idx, attr)| {
if dbg!(&attr.path).is_ident(&Ident::new("fatal", Span::call_site())) {
if attr.path.is_ident(&Ident::new("fatal", Span::call_site())) {
Some(idx)
} else {
None
}
})
{
dbg!(&mut variant.attrs).swap_remove(idx);
dbg!(&mut variant.attrs);
is_fatal = true;
}
if is_fatal {
Expand All @@ -107,26 +99,29 @@ fn gen(item: &ItemEnum) -> TokenStream {
let thiserror: Path = parse2(quote!(thiserror::Error)).unwrap();
let thiserror = abs(thiserror, name.span());
let wrapper_enum = quote! {
#[#thiserror]
#[derive(#thiserror)]
#[derive(Debug)]
#vis enum #name {
#[error(transparent)]
Fatal(#name_fatal),
#[error(transparent)]
Jfyi(#name_jfyi),
}
};
let jfyi_enum = quote! {
#[#thiserror]
#vis enum #name_jfyi {
#( #jfyi_variants ),*
}
};
let fatal_enum = quote! {
#[#thiserror]
#vis enum #name_fatal {
#( #fatal_variants ),*

fn generate_inner_enum(vis: &Visibility, name: &Ident, variants: Vec<Variant>, thiserror: &Path) -> TokenStream {
quote! {
#[derive(#thiserror)]
#[derive(Debug)]
#vis enum #name {
#( #variants , )*
}
}
};
}

let fatal_enum = generate_inner_enum(&vis, &name_fatal, fatal_variants, &thiserror);
let jfyi_enum = generate_inner_enum(&vis, &name_jfyi, jfyi_variants, &thiserror);

let mut ts = TokenStream::new();
ts.extend(wrapper_enum);
ts.extend(trait_fatality_impl(name, quote! {
Expand Down Expand Up @@ -159,24 +154,32 @@ fn gen(item: &ItemEnum) -> TokenStream {

}

fn fatality2(input: proc_macro2::TokenStream) -> proc_macro2::TokenStream {
let mut item: ItemEnum = match syn::parse2(input.clone()) {
fn fatality2(attr: proc_macro2::TokenStream, input: proc_macro2::TokenStream) -> proc_macro2::TokenStream {
let item: ItemEnum = match syn::parse2(input.clone()) {
Err(e) => {
let mut bail = input.into_token_stream();
bail.extend(e.to_compile_error());
return bail
}
Ok(item) => item,
};
let res = gen(&item);
if !attr.is_empty() {
return syn::Error::new_spanned(attr, "fatality does not take any arguments").into_compile_error().into_token_stream()
}
let res = fatality_gen(&item);
res
}

#[proc_macro]
pub fn fatality(input: proc_macro::TokenStream) -> proc_macro::TokenStream {

#[proc_macro_attribute]
pub fn fatality(
attr: proc_macro::TokenStream,
input: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
let attr = TokenStream::from(attr);
let input = TokenStream::from(input);

let output: TokenStream = fatality2(input);
let output: TokenStream = fatality2(attr, input);

proc_macro::TokenStream::from(output)
}
Expand All @@ -189,18 +192,20 @@ mod tests {
fn basic_full() {
let input = quote!{
enum Kaboom {
#[fatal, error(transparent)]
#[fatal]
#[error(transparent)]
A(X),
#[error(transparent)]
B(Y),
}
};
let output = fatality2(dbg!(input));
let output = fatality2(TokenStream::new(), input);
println!(r##">>>>>>>>>>>>>>>>>>>
{}
>>>>>>>>>>>>>>>>>>>"##, output.to_string());
assert_eq!(output.to_string(), quote!{
#[crate::thiserror::Error]
#[derive(crate::thiserror::Error)]
#[derive(Debug)]
enum Kaboom {
#[error(transparent)]
Fatal(FatalKaboom),
Expand All @@ -218,7 +223,8 @@ impl crate::Fatality for Kaboom {
}
}

#[crate::thiserror::Error]
#[derive(crate::thiserror::Error)]
#[derive(Debug)]
enum FatalKaboom {
#[error(transparent)]
A(X),
Expand All @@ -230,7 +236,8 @@ impl crate::Fatality for FatalKaboom {
}
}

#[crate::thiserror::Error]
#[derive(crate::thiserror::Error)]
#[derive(Debug)]
enum JfyiKaboom {
#[error(transparent)]
B(Y),
Expand Down
52 changes: 51 additions & 1 deletion node/fatality/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,57 @@
// Copyright 2021 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.

// Polkadot is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Polkadot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.

pub use fatality_proc_macro::fatality;
pub use thiserror;

/// Determine the fatality of an error.
pub trait Fatality {
fn is_fatal() -> bool;
fn is_fatal(&self) -> bool;
}


#[cfg(test)]
mod tests {
use super::*;

#[derive(Debug, thiserror::Error)]
#[error("X")]
struct X;

#[derive(Debug, thiserror::Error)]
#[error("Y")]
struct Y;

#[fatality]
#[derive(Debug)]
enum Fatal {
#[fatal]
#[error("X={0}")]
A(#[source] X),

#[error(transparent)]
B(Y),
}


#[test]
fn all_in_one() {
// TODO this must continue to work, so consider retaining the original error type as is, and only split
// TODO on `is_fatal() -> Result<Jfyi, Fatal>`
assert_eq!(true, Fatality::is_fatal(&Fatal::A(X)));
assert_eq!(false, Fatality::is_fatal(&Fatal::B(Y)));
}
}