Skip to content

Commit 198fe27

Browse files
committed
Adadpt exn to most pressing needs of gitoxide
- Top-level `Error` - dissolve `Exn` back to `Box<E>` - Use `dyn Error + Send + Sync + 'static'`
1 parent 0eaab70 commit 198fe27

File tree

34 files changed

+426
-637
lines changed

34 files changed

+426
-637
lines changed

Cargo.lock

Lines changed: 4 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

gix-date/src/parse/function.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use crate::{
99
time::format::{DEFAULT, GITOXIDE, ISO8601, ISO8601_STRICT, SHORT},
1010
Error, OffsetInSeconds, SecondsSinceUnixEpoch, Time,
1111
};
12-
use gix_error::{Result, ResultExt};
12+
use gix_error::{Exn, ResultExt};
1313

1414
/// Parse `input` as any time that Git can parse when inputting a date.
1515
///
@@ -72,7 +72,7 @@ use gix_error::{Result, ResultExt};
7272
/// If `now` is October 27, 2023 at 10:00:00 UTC:
7373
/// * `2 minutes ago` (October 27, 2023 at 09:58:00 UTC)
7474
/// * `3 hours ago` (October 27, 2023 at 07:00:00 UTC)
75-
pub fn parse(input: &str, now: Option<SystemTime>) -> Result<Time, Error> {
75+
pub fn parse(input: &str, now: Option<SystemTime>) -> Result<Time, Exn<Error>> {
7676
Ok(if let Ok(val) = Date::strptime(SHORT.0, input) {
7777
let val = val
7878
.to_zoned(TimeZone::UTC)

gix-date/src/parse/relative.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
use std::{str::FromStr, time::SystemTime};
22

33
use crate::Error;
4-
use gix_error::{ensure, ParseError, Result, ResultExt};
4+
use gix_error::{ensure, Exn, ParseError, ResultExt};
55
use jiff::{tz::TimeZone, Span, Timestamp, Zoned};
66

7-
fn parse_inner(input: &str) -> Option<Result<Span, Error>> {
7+
fn parse_inner(input: &str) -> Option<Result<Span, Exn<Error>>> {
88
let mut split = input.split_whitespace();
99
let units = i64::from_str(split.next()?).ok()?;
1010
let period = split.next()?;
@@ -14,8 +14,8 @@ fn parse_inner(input: &str) -> Option<Result<Span, Error>> {
1414
span(period, units)
1515
}
1616

17-
pub fn parse(input: &str, now: Option<SystemTime>) -> Option<Result<Zoned, Error>> {
18-
parse_inner(input).map(|result| -> Result<Zoned, Error> {
17+
pub fn parse(input: &str, now: Option<SystemTime>) -> Option<Result<Zoned, Exn<Error>>> {
18+
parse_inner(input).map(|result| -> Result<Zoned, Exn<Error>> {
1919
let span = result?;
2020
// This was an error case in a previous version of this code, where
2121
// it would fail when converting from a negative signed integer
@@ -36,7 +36,7 @@ pub fn parse(input: &str, now: Option<SystemTime>) -> Option<Result<Zoned, Error
3636
})
3737
}
3838

39-
fn span(period: &str, units: i64) -> Option<Result<Span, Error>> {
39+
fn span(period: &str, units: i64) -> Option<Result<Span, Exn<Error>>> {
4040
let period = period.strip_suffix('s').unwrap_or(period);
4141
let result = match period {
4242
"second" => Span::new().try_seconds(units),

gix-date/tests/time/parse/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::time::SystemTime;
22

33
use gix_date::Time;
4+
use gix_error::Exn;
45

56
#[test]
67
fn time_without_offset_defaults_to_utc() {
@@ -63,7 +64,7 @@ fn git_rfc2822() {
6364
}
6465

6566
#[test]
66-
fn raw() -> gix_error::Result<(), gix_date::Error> {
67+
fn raw() -> Result<(), Exn<gix_date::Error>> {
6768
assert_eq!(
6869
gix_date::parse("1660874655 +0800", None)?,
6970
Time {

gix-error/Cargo.toml

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,9 @@ edition = "2021"
1111
include = ["src/**/*", "LICENSE-*"]
1212
rust-version = "1.82"
1313

14-
[lib]
15-
doctest = false
16-
1714
[dependencies]
18-
bstr = { version = "1.12.0", default-features = false }
19-
exn = { version = "0.2.1", default-features = false }
15+
bstr = { version = "1.12.0", default-features = false, features = ["std"] }
16+
17+
[dev-dependencies]
18+
insta = "1.46.0"
2019

gix-error/src/exn/Cargo.toml

Lines changed: 0 additions & 37 deletions
This file was deleted.

gix-error/src/exn/debug.rs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
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+
use std::fmt;
16+
use std::fmt::Formatter;
17+
18+
use crate::exn::Exn;
19+
use crate::exn::Frame;
20+
21+
impl<E: std::error::Error + Send + Sync + 'static> fmt::Debug for Exn<E> {
22+
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
23+
write_exn(f, self.as_frame(), 0, "")
24+
}
25+
}
26+
27+
impl fmt::Debug for Frame {
28+
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
29+
write_exn(f, self, 0, "")
30+
}
31+
}
32+
33+
fn write_exn(f: &mut Formatter<'_>, frame: &Frame, level: usize, prefix: &str) -> fmt::Result {
34+
write!(f, "{}", frame.as_error())?;
35+
write_location(f, frame)?;
36+
37+
let children = frame.children();
38+
let children_len = children.len();
39+
40+
for (i, child) in children.iter().enumerate() {
41+
write!(f, "\n{prefix}|")?;
42+
write!(f, "\n{prefix}|-> ")?;
43+
44+
let child_child_len = child.children().len();
45+
if level == 0 && children_len == 1 && child_child_len == 1 {
46+
write_exn(f, child, 0, prefix)?;
47+
} else if i < children_len - 1 {
48+
write_exn(f, child, level + 1, &format!("{prefix}| "))?;
49+
} else {
50+
write_exn(f, child, level + 1, &format!("{prefix} "))?;
51+
}
52+
}
53+
54+
Ok(())
55+
}
56+
57+
fn write_location(f: &mut Formatter<'_>, exn: &Frame) -> fmt::Result {
58+
let location = exn.location();
59+
write!(f, ", at {}:{}:{}", location.file(), location.line(), location.column())
60+
}
Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,9 @@
1414

1515
use std::fmt;
1616

17-
use crate::Error;
18-
use crate::Exn;
17+
use crate::exn::Exn;
1918

20-
impl<E: Error> fmt::Display for Exn<E> {
19+
impl<E: std::error::Error + Send + Sync + 'static> fmt::Display for Exn<E> {
2120
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2221
write!(f, "{}", self.as_error())
2322
}

gix-error/src/exn/ext.rs

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
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+
use crate::exn::Exn;
16+
17+
/// A trait bound of the supported error type of [`Exn`].
18+
pub trait ErrorExt: std::error::Error + Send + Sync + 'static {
19+
/// Raise this error as a new exception.
20+
#[track_caller]
21+
fn raise(self) -> Exn<Self>
22+
where
23+
Self: Sized,
24+
{
25+
Exn::new(self)
26+
}
27+
}
28+
29+
impl<T> ErrorExt for T where T: std::error::Error + Send + Sync + 'static {}
30+
31+
/// An extension trait for [`Option`] to provide raising new exceptions on `None`.
32+
pub trait OptionExt {
33+
/// The `Some` type.
34+
type Some;
35+
36+
/// Construct a new [`Exn`] on the `None` variant.
37+
fn ok_or_raise<A, F>(self, err: F) -> Result<Self::Some, Exn<A>>
38+
where
39+
A: std::error::Error + Send + Sync + 'static,
40+
F: FnOnce() -> A;
41+
}
42+
43+
impl<T> OptionExt for Option<T> {
44+
type Some = T;
45+
46+
#[track_caller]
47+
fn ok_or_raise<A, F>(self, err: F) -> Result<T, Exn<A>>
48+
where
49+
A: std::error::Error + Send + Sync + 'static,
50+
F: FnOnce() -> A,
51+
{
52+
match self {
53+
Some(v) => Ok(v),
54+
None => Err(Exn::new(err())),
55+
}
56+
}
57+
}
58+
59+
/// An extension trait for [`Result`] to provide context information on [`Exn`]s.
60+
pub trait ResultExt {
61+
/// The `Ok` type.
62+
type Success;
63+
64+
/// The `Err` type that would be wrapped in an [`Exn`].
65+
type Error: std::error::Error + Send + Sync + 'static;
66+
67+
/// Raise a new exception on the [`Exn`] inside the [`Result`].
68+
///
69+
/// Apply [`Exn::raise`] on the `Err` variant, refer to it for more information.
70+
fn or_raise<A, F>(self, err: F) -> Result<Self::Success, Exn<A>>
71+
where
72+
A: std::error::Error + Send + Sync + 'static,
73+
F: FnOnce() -> A;
74+
}
75+
76+
impl<T, E> ResultExt for std::result::Result<T, E>
77+
where
78+
E: std::error::Error + Send + Sync + 'static,
79+
{
80+
type Success = T;
81+
type Error = E;
82+
83+
#[track_caller]
84+
fn or_raise<A, F>(self, err: F) -> Result<Self::Success, Exn<A>>
85+
where
86+
A: std::error::Error + Send + Sync + 'static,
87+
F: FnOnce() -> A,
88+
{
89+
match self {
90+
Ok(v) => Ok(v),
91+
Err(e) => Err(Exn::new(e).raise(err())),
92+
}
93+
}
94+
}
95+
96+
impl<T, E> ResultExt for std::result::Result<T, Exn<E>>
97+
where
98+
E: std::error::Error + Send + Sync + 'static,
99+
{
100+
type Success = T;
101+
type Error = E;
102+
103+
#[track_caller]
104+
fn or_raise<A, F>(self, err: F) -> Result<Self::Success, Exn<A>>
105+
where
106+
A: std::error::Error + Send + Sync + 'static,
107+
F: FnOnce() -> A,
108+
{
109+
match self {
110+
Ok(v) => Ok(v),
111+
Err(e) => Err(e.raise(err())),
112+
}
113+
}
114+
}

0 commit comments

Comments
 (0)