Skip to content

Commit b162068

Browse files
committed
Allow skipping the Msg variant
While the `Msg` variant may be a useful option for some users, many will prefer to stick to more descriptive error types, and won't want this variant present. This allows a `skip_msg_variant` flag to be passed to `error_chain!`, which will cause no `Msg` variant to be present in the generated code. I've also refactored the body of `impl_error_chain_processing` to not care about the number of arguments other than the final branch, so more cases can be added in the future without having to touch as many places as I did. Fixes rust-lang-deprecated#200.
1 parent 92a54ba commit b162068

File tree

3 files changed

+109
-45
lines changed

3 files changed

+109
-45
lines changed

src/error_chain.rs

Lines changed: 84 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,68 @@ macro_rules! impl_error_chain_processed {
3333
#[allow(unused)]
3434
pub type $result_name<T> = ::std::result::Result<T, $error_name>;
3535
};
36-
// Without `Result` wrapper.
36+
37+
// With `Msg` variant.
38+
(
39+
types {
40+
$error_name:ident, $error_kind_name:ident, $($types:tt)*
41+
}
42+
links $links:tt
43+
foreign_links $foreign_links:tt
44+
errors { $($errors:tt)* }
45+
) => {
46+
impl_error_chain_processed! {
47+
types {
48+
$error_name, $error_kind_name, $($types)*
49+
}
50+
skip_msg_variant
51+
links $links
52+
foreign_links $foreign_links
53+
errors {
54+
/// A convenient variant for String.
55+
Msg(s: String) {
56+
description(&s)
57+
display("{}", s)
58+
}
59+
60+
$($errors)*
61+
}
62+
}
63+
64+
impl<'a> From<&'a str> for $error_kind_name {
65+
fn from(s: &'a str) -> Self {
66+
$error_kind_name::Msg(s.into())
67+
}
68+
}
69+
70+
impl From<String> for $error_kind_name {
71+
fn from(s: String) -> Self {
72+
$error_kind_name::Msg(s)
73+
}
74+
}
75+
76+
impl<'a> From<&'a str> for $error_name {
77+
fn from(s: &'a str) -> Self {
78+
Self::from_kind(s.into())
79+
}
80+
}
81+
82+
impl From<String> for $error_name {
83+
fn from(s: String) -> Self {
84+
Self::from_kind(s.into())
85+
}
86+
}
87+
};
88+
89+
// Without `Result` wrapper or `Msg` variant.
3790
(
3891
types {
3992
$error_name:ident, $error_kind_name:ident,
4093
$result_ext_name:ident;
4194
}
4295

96+
skip_msg_variant
97+
4398
links {
4499
$( $link_variant:ident ( $link_error_path:path, $link_kind_path:path )
45100
$( #[$meta_links:meta] )*; ) *
@@ -233,33 +288,13 @@ macro_rules! impl_error_chain_processed {
233288
}
234289
}
235290

236-
impl<'a> From<&'a str> for $error_name {
237-
fn from(s: &'a str) -> Self {
238-
$error_name::from_kind(s.into())
239-
}
240-
}
241-
242-
impl From<String> for $error_name {
243-
fn from(s: String) -> Self {
244-
$error_name::from_kind(s.into())
245-
}
246-
}
247-
248-
249291
// The ErrorKind type
250292
// --------------
251293

252294
impl_error_chain_kind! {
253295
/// The kind of an error.
254296
#[derive(Debug)]
255297
pub enum $error_kind_name {
256-
257-
/// A convenient variant for String.
258-
Msg(s: String) {
259-
description(&s)
260-
display("{}", s)
261-
}
262-
263298
$(
264299
$(#[$meta_links])*
265300
$link_variant(e: $link_kind_path) {
@@ -289,18 +324,6 @@ macro_rules! impl_error_chain_processed {
289324
}
290325
) *
291326

292-
impl<'a> From<&'a str> for $error_kind_name {
293-
fn from(s: &'a str) -> Self {
294-
$error_kind_name::Msg(s.to_string())
295-
}
296-
}
297-
298-
impl From<String> for $error_kind_name {
299-
fn from(s: String) -> Self {
300-
$error_kind_name::Msg(s)
301-
}
302-
}
303-
304327
impl From<$error_name> for $error_kind_name {
305328
fn from(e: $error_name) -> Self {
306329
e.0
@@ -350,48 +373,64 @@ macro_rules! impl_error_chain_processed {
350373
#[macro_export]
351374
macro_rules! error_chain_processing {
352375
(
353-
({}, $b:tt, $c:tt, $d:tt)
376+
({}, $($rest:tt)*)
354377
types $content:tt
355378
$( $tail:tt )*
356379
) => {
357380
error_chain_processing! {
358-
($content, $b, $c, $d)
381+
($content, $($rest)*)
359382
$($tail)*
360383
}
361384
};
385+
362386
(
363-
($a:tt, {}, $c:tt, $d:tt)
387+
($a:tt, {}, $($rest:tt)*)
364388
links $content:tt
365389
$( $tail:tt )*
366390
) => {
367391
error_chain_processing! {
368-
($a, $content, $c, $d)
392+
($a, $content, $($rest)*)
369393
$($tail)*
370394
}
371395
};
396+
372397
(
373-
($a:tt, $b:tt, {}, $d:tt)
398+
($a:tt, $b:tt, {}, $($rest:tt)*)
374399
foreign_links $content:tt
375400
$( $tail:tt )*
376401
) => {
377402
error_chain_processing! {
378-
($a, $b, $content, $d)
403+
($a, $b, $content, $($rest)*)
379404
$($tail)*
380405
}
381406
};
407+
382408
(
383-
($a:tt, $b:tt, $c:tt, {})
409+
($a:tt, $b:tt, $c:tt, {}, $($rest:tt)*)
384410
errors $content:tt
385411
$( $tail:tt )*
386412
) => {
387413
error_chain_processing! {
388-
($a, $b, $c, $content)
414+
($a, $b, $c, $content, $($rest)*)
415+
$($tail)*
416+
}
417+
};
418+
419+
(
420+
($a:tt, $b:tt, $c:tt, $d:tt, {}, $($rest:tt)*)
421+
skip_msg_variant
422+
$( $tail:tt )*
423+
) => {
424+
error_chain_processing! {
425+
($a, $b, $c, $d, {skip_msg_variant}, $($rest)*)
389426
$($tail)*
390427
}
391428
};
392-
( ($a:tt, $b:tt, $c:tt, $d:tt) ) => {
429+
430+
( ($a:tt, $b:tt, $c:tt, $d:tt, {$($e:tt)*},) ) => {
393431
impl_error_chain_processed! {
394432
types $a
433+
$($e)*
395434
links $b
396435
foreign_links $c
397436
errors $d
@@ -402,10 +441,10 @@ macro_rules! error_chain_processing {
402441
/// Macro for generating error types and traits. See crate level documentation for details.
403442
#[macro_export]
404443
macro_rules! error_chain {
405-
( $( $block_name:ident { $( $block_content:tt )* } )* ) => {
444+
( $($args:tt)* ) => {
406445
error_chain_processing! {
407-
({}, {}, {}, {})
408-
$($block_name { $( $block_content )* })*
446+
({}, {}, {}, {}, {},)
447+
$($args)*
409448
}
410449
};
411450
}

src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,10 @@
164164
//! display("unknown toolchain version: '{}'", v), // trailing comma is allowed
165165
//! }
166166
//! }
167+
//!
168+
//! // If this annotation is left off, a variant `Msg(s: String)` will be added, and `From`
169+
//! // impls will be provided for `String` and `&str`
170+
//! skip_msg_variant
167171
//! }
168172
//!
169173
//! # fn main() {}

tests/tests.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -641,3 +641,24 @@ fn trailing_comma_in_errors_impl() {
641641
}
642642
};
643643
}
644+
645+
#[test]
646+
fn skipping_msg_variant() {
647+
error_chain! {
648+
skip_msg_variant
649+
650+
errors {
651+
MyMsg(s: String) {
652+
description(&s)
653+
display("{}", s)
654+
}
655+
}
656+
}
657+
658+
let x = Error::from_kind(ErrorKind::MyMsg("some string".into()));
659+
// This would fail to compile if we generate a `Msg` variant
660+
match *x.kind() {
661+
ErrorKind::MyMsg(_) => {}
662+
ErrorKind::__Nonexhaustive {} => {}
663+
}
664+
}

0 commit comments

Comments
 (0)