Skip to content

Commit

Permalink
feat: initial implementation of flat_error
Browse files Browse the repository at this point in the history
  • Loading branch information
coroiu committed Oct 11, 2024
1 parent 8f1ba7c commit a75585f
Show file tree
Hide file tree
Showing 7 changed files with 168 additions and 0 deletions.
16 changes: 16 additions & 0 deletions Cargo.lock

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

23 changes: 23 additions & 0 deletions crates/bitwarden-error-macro/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
[package]
name = "bitwarden-error-macro"
version.workspace = true
authors.workspace = true
edition.workspace = true
rust-version.workspace = true
homepage.workspace = true
repository.workspace = true
license-file.workspace = true
keywords.workspace = true

[dependencies]
quote = "1.0.37"
syn = "2.0.79"

[dev-dependencies]
bitwarden-error = { path = "../bitwarden-error" }

[lib]
proc-macro = true

[lints]
workspace = true
51 changes: 51 additions & 0 deletions crates/bitwarden-error-macro/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, Data, DeriveInput, Fields};

#[proc_macro_derive(FlatError)]
pub fn derive_flat_error(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let name = &input.ident;

// Generate match arms without converting variant names to strings
let variant_matches: Vec<_> = if let Data::Enum(data_enum) = &input.data {
data_enum
.variants
.iter()
.map(|variant| {
let variant_ident = &variant.ident;
let message = match &variant.fields {
Fields::Unnamed(_) | Fields::Named(_) => {
format!("Error: {}", variant_ident)
}
Fields::Unit => {
format!("{}", variant_ident)
}
};
quote! {
#name::#variant_ident { .. } => (stringify!(#variant_ident), #message),
}
})
.collect()
} else {
panic!("FlatError can only be derived for enums");
};

let expanded = quote! {
impl FlatError for #name {
fn get_variant(&self) -> &str {
match self {
#(#variant_matches)*
}.0
}

fn get_message(&self) -> &str {
match self {
#(#variant_matches)*
}.1
}
}
};

TokenStream::from(expanded)
}
50 changes: 50 additions & 0 deletions crates/bitwarden-error-macro/tests/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
use bitwarden_error::prelude::*;

#[test]
fn flattens_basic_enums() {
#[derive(FlatError)]
enum Errors {
Foo,
Bar,
Baz,
}

let foo = Errors::Foo;
let bar = Errors::Bar;
let baz = Errors::Baz;

assert_eq!(foo.get_variant(), "Foo");
assert_eq!(bar.get_variant(), "Bar");
assert_eq!(baz.get_variant(), "Baz");

assert_eq!(foo.get_message(), "Foo");
assert_eq!(bar.get_message(), "Bar");
assert_eq!(baz.get_message(), "Baz");
}

#[test]
fn flattens_enums_with_fields() {
#[derive(FlatError)]
enum Errors {
#[allow(dead_code)]
Foo(String),
#[allow(dead_code)]
Bar(u32),
Baz,
}

let foo = Errors::Foo("hello".to_string());
let bar = Errors::Bar(42);
let baz = Errors::Baz;

assert_eq!(foo.get_variant(), "Foo");
assert_eq!(bar.get_variant(), "Bar");
assert_eq!(baz.get_variant(), "Baz");

// The message is always "Error: <variant>"
// TODO: Add support for getting the message from the fields
// or maybe just remove get_message and rely on ToString
assert_eq!(foo.get_message(), "Error: Foo");
assert_eq!(bar.get_message(), "Error: Bar");
assert_eq!(baz.get_message(), "Baz");
}
16 changes: 16 additions & 0 deletions crates/bitwarden-error/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[package]
name = "bitwarden-error"
version.workspace = true
authors.workspace = true
edition.workspace = true
rust-version.workspace = true
homepage.workspace = true
repository.workspace = true
license-file.workspace = true
keywords.workspace = true

[dependencies]
bitwarden-error-macro = { path = "../bitwarden-error-macro" }

[lints]
workspace = true
4 changes: 4 additions & 0 deletions crates/bitwarden-error/src/flat_error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
pub trait FlatError {
fn get_variant(&self) -> &str;
fn get_message(&self) -> &str;
}
8 changes: 8 additions & 0 deletions crates/bitwarden-error/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
mod flat_error;

pub use flat_error::FlatError;

pub mod prelude {
pub use crate::FlatError;
pub use bitwarden_error_macro::FlatError;
}

0 comments on commit a75585f

Please sign in to comment.