History

Vendor `exn` from https://github.com/fast/exn@bb4d8ea4e4df335c46d4fa3f4f260121f9f84305

This is the basis for substantial changes to make it usable for the `gix-*` crates. The wonderful aspect about this is not only a great reduction in dependencies, but it also removes most proc-macro invocations.

Sebastian Thiel committed 10 months ago

Commit 0eaab701 parent 5ab19a716 files · +846 −0Browse files

Unified · Split

16 files
  1. gix-error/src/exn/Cargo.toml +37 −0
  2. gix-error/src/exn/src/debug.rs +108 −0
  3. gix-error/src/exn/src/display.rs +24 −0
  4. gix-error/src/exn/src/impls.rs +157 −0
  5. gix-error/src/exn/src/lib.rs +124 −0
  6. gix-error/src/exn/src/macros.rs +90 −0
  7. gix-error/src/exn/src/option.rs +45 −0
  8. gix-error/src/exn/src/result.rs +76 −0
  9. gix-error/src/exn/tests/simple.rs +118 −0
  10. gix-error/src/exn/tests/snapshots/simple__bail.snap +5 −0
  11. gix-error/src/exn/tests/snapshots/simple__ensure_fail.snap +5 −0
  12. gix-error/src/exn/tests/snapshots/simple__error_straightforward.snap +13 −0
  13. gix-error/src/exn/tests/snapshots/simple__error_tree.snap +27 −0
  14. gix-error/src/exn/tests/snapshots/simple__from_error.snap +5 −0
  15. gix-error/src/exn/tests/snapshots/simple__option_ext.snap +5 −0
  16. gix-error/src/exn/tests/snapshots/simple__result_ext.snap +7 −0
gix-error/src/exn/Cargo.toml+37−0
@@ -0,0 +1,37 @@
1# Copyright 2025 FastLabs Developers
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15[package]
16name = "exn"
17version = "0.2.1"
18
19description = "A context-aware concrete Error type built on `std::error::Error`."
20
21edition.workspace = true
22homepage.workspace = true
23license.workspace = true
24readme.workspace = true
25repository.workspace = true
26
27[package.metadata.docs.rs]
28all-features = true
29rustdoc-args = ["--cfg", "docsrs"]
30
31[dependencies]
32
33[dev-dependencies]
34insta = { workspace = true }
35
36[lints]
37workspace = true
gix-error/src/exn/src/debug.rs+108−0
@@ -0,0 +1,108 @@
1// Copyright 2025 FastLabs Developers
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::fmt;
16use std::fmt::Formatter;
17
18use crate::Error;
19use crate::Exn;
20use crate::Frame;
21
22impl<E: Error> fmt::Debug for Exn<E> {
23 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
24 write_exn(f, self.as_frame(), 0, "")
25 }
26}
27
28impl fmt::Debug for Frame {
29 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
30 write_exn(f, self, 0, "")
31 }
32}
33
34fn write_exn(f: &mut Formatter<'_>, frame: &Frame, level: usize, prefix: &str) -> fmt::Result {
35 write!(f, "{}", frame.as_error())?;
36 write_location(f, frame)?;
37
38 let children = frame.children();
39 let children_len = children.len();
40
41 for (i, child) in children.iter().enumerate() {
42 write!(f, "\n{}|", prefix)?;
43 write!(f, "\n{}|-> ", prefix)?;
44
45 let child_child_len = child.children().len();
46 if level == 0 && children_len == 1 && child_child_len == 1 {
47 write_exn(f, child, 0, prefix)?;
48 } else if i < children_len - 1 {
49 write_exn(f, child, level + 1, &format!("{}| ", prefix))?;
50 } else {
51 write_exn(f, child, level + 1, &format!("{} ", prefix))?;
52 }
53 }
54
55 Ok(())
56}
57
58#[cfg(not(windows_test))]
59fn write_location(f: &mut Formatter<'_>, exn: &Frame) -> fmt::Result {
60 let location = exn.location();
61 write!(
62 f,
63 ", at {}:{}:{}",
64 location.file(),
65 location.line(),
66 location.column()
67 )
68}
69
70#[cfg(windows_test)]
71fn write_location(f: &mut Formatter<'_>, exn: &Frame) -> fmt::Result {
72 let location = exn.location();
73 use std::os::windows::ffi::OsStrExt;
74 use std::path::Component;
75 use std::path::MAIN_SEPARATOR;
76 use std::path::Path;
77
78 let file = location.file();
79 let path = Path::new(file);
80
81 let mut resolved = String::new();
82
83 for c in path.components() {
84 match c {
85 Component::RootDir => {}
86 Component::CurDir => resolved.push('.'),
87 Component::ParentDir => resolved.push_str(".."),
88 Component::Prefix(prefix) => {
89 resolved.push_str(&prefix.as_os_str().to_string_lossy());
90 continue;
91 }
92 Component::Normal(s) => resolved.push_str(&s.to_string_lossy()),
93 }
94 resolved.push('/');
95 }
96
97 if path.as_os_str().encode_wide().last() != Some(MAIN_SEPARATOR as u16)
98 && resolved != "/"
99 && resolved.ends_with('/')
100 {
101 resolved.pop(); // Pop last '/'
102 }
103
104 let line = location.line();
105 let column = location.column();
106
107 write!(f, ", at {resolved}:{line}:{column}")
108}
gix-error/src/exn/src/display.rs+24−0
@@ -0,0 +1,24 @@
1// Copyright 2025 FastLabs Developers
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::fmt;
16
17use crate::Error;
18use crate::Exn;
19
20impl<E: Error> fmt::Display for Exn<E> {
21 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
22 write!(f, "{}", self.as_error())
23 }
24}
gix-error/src/exn/src/impls.rs+157−0
@@ -0,0 +1,157 @@
1// Copyright 2025 FastLabs Developers
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::fmt;
16use std::marker::PhantomData;
17use std::panic::Location;
18
19use crate::Error;
20
21/// An exception type that can hold an error tree and additional context.
22pub struct Exn<E: Error> {
23 // trade one more indirection for less stack size
24 frame: Box<Frame>,
25 phantom: PhantomData<E>,
26}
27
28impl<E: Error> From<E> for Exn<E> {
29 #[track_caller]
30 fn from(error: E) -> Self {
31 Exn::new(error)
32 }
33}
34
35impl<E: Error> Exn<E> {
36 /// Create a new exception with the given error.
37 ///
38 /// This will automatically walk the [source chain of the error] and add them as children
39 /// frames.
40 ///
41 /// See also [`Error::raise`] for a fluent way to convert an error into an `Exn` instance.
42 ///
43 /// [source chain of the error]: std::error::Error::source
44 #[track_caller]
45 pub fn new(error: E) -> Self {
46 struct SourceError(String);
47
48 impl fmt::Debug for SourceError {
49 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50 fmt::Debug::fmt(&self.0, f)
51 }
52 }
53
54 impl fmt::Display for SourceError {
55 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56 fmt::Display::fmt(&self.0, f)
57 }
58 }
59
60 impl std::error::Error for SourceError {}
61
62 fn walk(error: &dyn std::error::Error, location: &'static Location<'static>) -> Vec<Frame> {
63 if let Some(source) = error.source() {
64 let children = vec![Frame {
65 error: Box::new(SourceError(source.to_string())),
66 location,
67 children: walk(source, location),
68 }];
69 children
70 } else {
71 vec![]
72 }
73 }
74
75 let location = Location::caller();
76 let children = walk(&error, location);
77 let frame = Frame {
78 error: Box::new(error),
79 location,
80 children,
81 };
82
83 Self {
84 frame: Box::new(frame),
85 phantom: PhantomData,
86 }
87 }
88
89 /// Create a new exception with the given error and children.
90 #[track_caller]
91 pub fn from_iter<T, I>(children: I, err: E) -> Self
92 where
93 T: Error,
94 I: IntoIterator,
95 I::Item: Into<Exn<T>>,
96 {
97 let mut new_exn = Exn::new(err);
98 for exn in children {
99 let exn = exn.into();
100 new_exn.frame.children.push(*exn.frame);
101 }
102 new_exn
103 }
104
105 /// Raise a new exception; this will make the current exception a child of the new one.
106 #[track_caller]
107 pub fn raise<T: Error>(self, err: T) -> Exn<T> {
108 let mut new_exn = Exn::new(err);
109 new_exn.frame.children.push(*self.frame);
110 new_exn
111 }
112
113 /// Return the current exception.
114 pub fn as_error(&self) -> &E {
115 self.frame
116 .as_any()
117 .downcast_ref()
118 .expect("error type must match")
119 }
120
121 /// Return the underlying exception frame.
122 pub fn as_frame(&self) -> &Frame {
123 &self.frame
124 }
125}
126
127/// A frame in the exception tree.
128pub struct Frame {
129 /// The error that occurred at this frame.
130 error: Box<dyn Error>,
131 /// The source code location where this exception frame was created.
132 location: &'static Location<'static>,
133 /// Child exception frames that provide additional context or source errors.
134 children: Vec<Frame>,
135}
136
137impl Frame {
138 /// Return the error as a reference to [`std::any::Any`].
139 pub fn as_any(&self) -> &dyn std::any::Any {
140 &*self.error
141 }
142
143 /// Return the error as a reference to [`std::error::Error`].
144 pub fn as_error(&self) -> &dyn std::error::Error {
145 &*self.error
146 }
147
148 /// Return the source code location where this exception frame was created.
149 pub fn location(&self) -> &'static Location<'static> {
150 self.location
151 }
152
153 /// Return a slice of the children of the exception.
154 pub fn children(&self) -> &[Frame] {
155 &self.children
156 }
157}
gix-error/src/exn/src/lib.rs+124−0
@@ -0,0 +1,124 @@
1// Copyright 2025 FastLabs Developers
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! A context-aware concrete Error type built on `std::error::Error`
16//!
17//! # Examples
18//!
19//! ```
20//! use exn::Result;
21//! use exn::ResultExt;
22//! use exn::bail;
23//!
24//! // It's recommended to define errors as structs. Exn will maintain the error tree automatically.
25//! #[derive(Debug)]
26//! struct LogicError(String);
27//!
28//! impl std::fmt::Display for LogicError {
29//! fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
30//! write!(f, "logic error: {}", self.0)
31//! }
32//! }
33//!
34//! impl std::error::Error for LogicError {}
35//!
36//! fn do_logic() -> Result<(), LogicError> {
37//! bail!(LogicError("0 == 1".to_string()));
38//! }
39//!
40//! // Errors can be enum but notably don't need to chain source error.
41//! #[derive(Debug)]
42//! enum AppError {
43//! Fatal { consequences: &'static str },
44//! Trivial,
45//! }
46//!
47//! impl std::fmt::Display for AppError {
48//! fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
49//! match self {
50//! AppError::Fatal { consequences } => write!(f, "fatal error: {consequences}"),
51//! AppError::Trivial => write!(f, "trivial error"),
52//! }
53//! }
54//! }
55//!
56//! impl std::error::Error for AppError {}
57//!
58//! fn main() {
59//! if let Err(err) = do_logic().or_raise(|| AppError::Fatal {
60//! consequences: "math no longer works",
61//! }) {
62//! eprintln!("{err:?}");
63//! }
64//! }
65//! ```
66//!
67//! The above program will print an error message like:
68//!
69//! ```text
70//! fatal error: math no longer works, at exn/src/lib.rs:44:16
71//! |
72//! |-> logic error: 0 == 1, at exn/src/lib.rs:40:5
73//! ```
74
75#![cfg_attr(docsrs, feature(doc_cfg))]
76#![deny(missing_docs)]
77
78mod debug;
79mod display;
80mod impls;
81mod macros;
82mod option;
83mod result;
84
85pub use self::impls::Exn;
86pub use self::impls::Frame;
87pub use self::option::OptionExt;
88pub use self::result::Result;
89pub use self::result::ResultExt;
90
91/// A trait bound of the supported error type of [`Exn`].
92pub trait Error: std::error::Error + std::any::Any + Send + Sync + 'static {
93 /// Raise this error as a new exception.
94 #[track_caller]
95 fn raise(self) -> Exn<Self>
96 where
97 Self: Sized,
98 {
99 Exn::new(self)
100 }
101}
102
103impl<T> Error for T where T: std::error::Error + std::any::Any + Send + Sync + 'static {}
104
105/// Equivalent to `Ok::<_, Exn<E>>(value)`.
106///
107/// This simplifies creation of an `exn::Result` in places where type inference cannot deduce the
108/// `E` type of the result &mdash; without needing to write `Ok::<_, Exn<E>>(value)`.
109///
110/// One might think that `exn::Result::Ok(value)` would work in such cases, but it does not.
111///
112/// ```console
113/// error[E0282]: type annotations needed for `std::result::Result<i32, E>`
114/// --> src/main.rs:11:13
115/// |
116/// 11 | let _ = exn::Result::Ok(1);
117/// | - ^^^^^^^^^^^^^^^ cannot infer type for type parameter `E` declared on the enum `Result`
118/// | |
119/// | consider giving this pattern the explicit type `std::result::Result<i32, E>`, where the type parameter `E` is specified
120/// ```
121#[expect(non_snake_case)]
122pub fn Ok<T, E: Error>(value: T) -> Result<T, E> {
123 Result::Ok(value)
124}
gix-error/src/exn/src/macros.rs+90−0
@@ -0,0 +1,90 @@
1// Copyright 2025 FastLabs Developers
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15/// Creates an [`Exn`] and returns it as [`Result`].
16///
17/// Shorthand for `return Err(Exn::from(err))`.
18///
19/// # Examples
20///
21/// Create an [`Exn`] from [`Error`]:
22///
23/// [`Exn`]: crate::Exn
24/// [`Error`]: std::error::Error
25///
26/// ```
27/// use std::fs;
28///
29/// use exn::bail;
30/// # fn wrapper() -> exn::Result<(), impl exn::Error> {
31/// match fs::read_to_string("/path/to/file") {
32/// Ok(content) => println!("file contents: {content}"),
33/// Err(err) => bail!(err),
34/// }
35/// # Ok(()) }
36/// ```
37#[macro_export]
38macro_rules! bail {
39 ($err:expr) => {{
40 return ::std::result::Result::Err($crate::Exn::from($err));
41 }};
42}
43
44/// Ensures `$cond` is met; otherwise return an error.
45///
46/// Shorthand for `if !$cond { bail!(...); }`.
47///
48/// # Examples
49///
50/// Create an [`Exn`] from an [`Error`]:
51///
52/// [`Exn`]: crate::Exn
53/// [`Error`]: std::error::Error
54///
55/// ```
56/// # fn has_permission(_: &u32, _: &u32) -> bool { true }
57/// # type User = u32;
58/// # let user = 0;
59/// # type Resource = u32;
60/// # let resource = 0;
61/// use std::error::Error;
62/// use std::fmt;
63///
64/// use exn::ensure;
65///
66/// #[derive(Debug)]
67/// struct PermissionDenied(User, Resource);
68///
69/// impl fmt::Display for PermissionDenied {
70/// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
71/// write!(fmt, "permission denied")
72/// }
73/// }
74///
75/// impl Error for PermissionDenied {}
76///
77/// ensure!(
78/// has_permission(&user, &resource),
79/// PermissionDenied(user, resource),
80/// );
81/// # Ok(())
82/// ```
83#[macro_export]
84macro_rules! ensure {
85 ($cond:expr, $err:expr $(,)?) => {{
86 if !bool::from($cond) {
87 $crate::bail!($err)
88 }
89 }};
90}
gix-error/src/exn/src/option.rs+45−0
@@ -0,0 +1,45 @@
1// Copyright 2025 FastLabs Developers
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use crate::Error;
16use crate::Exn;
17use crate::Result;
18
19/// An extension trait for [`Option`] to provide raising new exceptions on `None`.
20pub trait OptionExt {
21 /// The `Some` type.
22 type Some;
23
24 /// Construct a new [`Exn`] on the `None` variant.
25 fn ok_or_raise<A, F>(self, err: F) -> Result<Self::Some, A>
26 where
27 A: Error,
28 F: FnOnce() -> A;
29}
30
31impl<T> OptionExt for Option<T> {
32 type Some = T;
33
34 #[track_caller]
35 fn ok_or_raise<A, F>(self, err: F) -> Result<T, A>
36 where
37 A: Error,
38 F: FnOnce() -> A,
39 {
40 match self {
41 Some(v) => Ok(v),
42 None => Err(Exn::new(err())),
43 }
44 }
45}
gix-error/src/exn/src/result.rs+76−0
@@ -0,0 +1,76 @@
1// Copyright 2025 FastLabs Developers
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use crate::Error;
16use crate::Exn;
17
18/// A reasonable return type to use throughout an application.
19pub type Result<T, E> = std::result::Result<T, Exn<E>>;
20
21/// An extension trait for [`Result`] to provide context information on [`Exn`]s.
22pub trait ResultExt {
23 /// The `Ok` type.
24 type Success;
25
26 /// The `Err` type that would be wrapped in an [`Exn`].
27 type Error: Error;
28
29 /// Raise a new exception on the [`Exn`] inside the [`Result`].
30 ///
31 /// Apply [`Exn::raise`] on the `Err` variant, refer to it for more information.
32 fn or_raise<A, F>(self, err: F) -> Result<Self::Success, A>
33 where
34 A: Error,
35 F: FnOnce() -> A;
36}
37
38impl<T, E> ResultExt for std::result::Result<T, E>
39where
40 E: Error,
41{
42 type Success = T;
43 type Error = E;
44
45 #[track_caller]
46 fn or_raise<A, F>(self, err: F) -> Result<Self::Success, A>
47 where
48 A: Error,
49 F: FnOnce() -> A,
50 {
51 match self {
52 Ok(v) => Ok(v),
53 Err(e) => Err(Exn::new(e).raise(err())),
54 }
55 }
56}
57
58impl<T, E> ResultExt for std::result::Result<T, Exn<E>>
59where
60 E: Error,
61{
62 type Success = T;
63 type Error = E;
64
65 #[track_caller]
66 fn or_raise<A, F>(self, err: F) -> Result<Self::Success, A>
67 where
68 A: Error,
69 F: FnOnce() -> A,
70 {
71 match self {
72 Ok(v) => Ok(v),
73 Err(e) => Err(e.raise(err())),
74 }
75 }
76}
gix-error/src/exn/tests/simple.rs+118−0
@@ -0,0 +1,118 @@
1// Copyright 2025 FastLabs Developers
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use exn::Error;
16use exn::Exn;
17use exn::OptionExt;
18use exn::ResultExt;
19
20#[derive(Debug)]
21struct SimpleError(&'static str);
22
23impl std::fmt::Display for SimpleError {
24 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
25 write!(f, "{}", self.0)
26 }
27}
28
29impl std::error::Error for SimpleError {}
30
31#[test]
32fn test_error_straightforward() {
33 let e1 = SimpleError("E1").raise();
34 let e2 = e1.raise(SimpleError("E2"));
35 let e3 = e2.raise(SimpleError("E3"));
36 let e4 = e3.raise(SimpleError("E4"));
37 let e5 = e4.raise(SimpleError("E5"));
38 insta::assert_debug_snapshot!(e5);
39}
40
41#[test]
42fn test_error_tree() {
43 let e1 = SimpleError("E1").raise();
44 let e3 = e1.raise(SimpleError("E3"));
45
46 let e9 = SimpleError("E9").raise();
47 let e10 = e9.raise(SimpleError("E10"));
48
49 let e11 = SimpleError("E11").raise();
50 let e12 = e11.raise(SimpleError("E12"));
51
52 let e5 = Exn::from_iter([e3, e10, e12], SimpleError("E5"));
53
54 let e2 = SimpleError("E2").raise();
55 let e4 = e2.raise(SimpleError("E4"));
56
57 let e7 = SimpleError("E7").raise();
58 let e8 = e7.raise(SimpleError("E8"));
59
60 let e6 = Exn::from_iter([e5, e4, e8], SimpleError("E6"));
61 insta::assert_debug_snapshot!(e6);
62}
63
64#[test]
65fn test_result_ext() {
66 let result: Result<(), SimpleError> = Err(SimpleError("An error"));
67 let result = result.or_raise(|| SimpleError("Another error"));
68 insta::assert_debug_snapshot!(result.unwrap_err());
69}
70
71#[test]
72fn test_option_ext() {
73 let result: Option<()> = None;
74 let result = result.ok_or_raise(|| SimpleError("An error"));
75 insta::assert_debug_snapshot!(result.unwrap_err());
76}
77
78#[test]
79fn test_from_error() {
80 fn foo() -> exn::Result<(), SimpleError> {
81 Err(SimpleError("An error"))?;
82 Ok(())
83 }
84
85 let result = foo();
86 insta::assert_debug_snapshot!(result.unwrap_err());
87}
88
89#[test]
90fn test_bail() {
91 fn foo() -> exn::Result<(), SimpleError> {
92 exn::bail!(SimpleError("An error"));
93 }
94
95 let result = foo();
96 insta::assert_debug_snapshot!(result.unwrap_err());
97}
98
99#[test]
100fn test_ensure_ok() {
101 fn foo() -> exn::Result<(), SimpleError> {
102 exn::ensure!(true, SimpleError("An error"));
103 Ok(())
104 }
105
106 foo().unwrap();
107}
108
109#[test]
110fn test_ensure_fail() {
111 fn foo() -> exn::Result<(), SimpleError> {
112 exn::ensure!(false, SimpleError("An error"));
113 Ok(())
114 }
115
116 let result = foo();
117 insta::assert_debug_snapshot!(result.unwrap_err());
118}
gix-error/src/exn/tests/snapshots/simple__bail.snap+5−0
@@ -0,0 +1,5 @@
1---
2source: exn/tests/simple.rs
3expression: result.unwrap_err()
4---
5An error, at exn/tests/simple.rs:92:9
gix-error/src/exn/tests/snapshots/simple__ensure_fail.snap+5−0
@@ -0,0 +1,5 @@
1---
2source: exn/tests/simple.rs
3expression: result.unwrap_err()
4---
5An error, at exn/tests/simple.rs:112:9
gix-error/src/exn/tests/snapshots/simple__error_straightforward.snap+13−0
@@ -0,0 +1,13 @@
1---
2source: exn/tests/simple.rs
3expression: e5
4---
5E5, at exn/tests/simple.rs:37:17
6|
7|-> E4, at exn/tests/simple.rs:36:17
8|
9|-> E3, at exn/tests/simple.rs:35:17
10|
11|-> E2, at exn/tests/simple.rs:34:17
12|
13|-> E1, at exn/tests/simple.rs:33:32
gix-error/src/exn/tests/snapshots/simple__error_tree.snap+27−0
@@ -0,0 +1,27 @@
1---
2source: exn/tests/simple.rs
3expression: e6
4---
5E6, at exn/tests/simple.rs:60:14
6|
7|-> E5, at exn/tests/simple.rs:52:14
8| |
9| |-> E3, at exn/tests/simple.rs:44:17
10| | |
11| | |-> E1, at exn/tests/simple.rs:43:32
12| |
13| |-> E10, at exn/tests/simple.rs:47:18
14| | |
15| | |-> E9, at exn/tests/simple.rs:46:32
16| |
17| |-> E12, at exn/tests/simple.rs:50:19
18| |
19| |-> E11, at exn/tests/simple.rs:49:34
20|
21|-> E4, at exn/tests/simple.rs:55:17
22| |
23| |-> E2, at exn/tests/simple.rs:54:32
24|
25|-> E8, at exn/tests/simple.rs:58:17
26 |
27 |-> E7, at exn/tests/simple.rs:57:32
gix-error/src/exn/tests/snapshots/simple__from_error.snap+5−0
@@ -0,0 +1,5 @@
1---
2source: exn/tests/simple.rs
3expression: result.unwrap_err()
4---
5An error, at exn/tests/simple.rs:81:9
gix-error/src/exn/tests/snapshots/simple__option_ext.snap+5−0
@@ -0,0 +1,5 @@
1---
2source: exn/tests/simple.rs
3expression: result.unwrap_err()
4---
5An error, at exn/tests/simple.rs:74:25
gix-error/src/exn/tests/snapshots/simple__result_ext.snap+7−0
@@ -0,0 +1,7 @@
1---
2source: exn/tests/simple.rs
3expression: result.unwrap_err()
4---
5Another error, at exn/tests/simple.rs:67:25
6|
7|-> An error, at exn/tests/simple.rs:67:25

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t