maybe_error.rs 3.24 KB
Newer Older
1
// SPDX-FileCopyrightText: Copyright (c) 2024-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2
3
// SPDX-License-Identifier: Apache-2.0

4
5
6
7
8
//! MaybeError trait for types that may contain error information.
//!
//! This module provides the `MaybeError` trait which allows types to represent
//! either successful data or error states. It integrates with the `DynamoError`
//! system to provide structured error handling.
9

10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
use crate::error::DynamoError;

/// A trait for types that may contain error information.
///
/// This trait allows a type to represent either a successful value or an error state.
/// It integrates with `DynamoError` for structured error information.
///
/// # Example
///
/// ```rust,ignore
/// use dynamo_runtime::protocols::maybe_error::MaybeError;
/// use dynamo_runtime::error::DynamoError;
///
/// struct MyResponse {
///     data: Option<String>,
///     error: Option<DynamoError>,
/// }
///
/// impl MaybeError for MyResponse {
///     fn from_err(err: impl std::error::Error + 'static) -> Self {
///         MyResponse {
///             data: None,
///             error: Some(DynamoError::from(
///                 Box::new(err) as Box<dyn std::error::Error + 'static>
///             )),
///         }
///     }
///
///     fn err(&self) -> Option<DynamoError> {
///         self.error.clone()
///     }
/// }
/// ```
43
44
pub trait MaybeError {
    /// Construct an instance from an error.
45
46
47
    ///
    /// The error is converted to a `DynamoError` for serialization.
    fn from_err(err: impl std::error::Error + 'static) -> Self;
48

49
50
51
52
    /// Get the error as a `DynamoError` if this represents an error state.
    ///
    /// Returns `Some(DynamoError)` if this instance represents an error, `None` otherwise.
    fn err(&self) -> Option<DynamoError>;
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69

    /// Check if the current instance represents a success.
    fn is_ok(&self) -> bool {
        !self.is_err()
    }

    /// Check if the current instance represents an error.
    fn is_err(&self) -> bool {
        self.err().is_some()
    }
}

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

    struct TestError {
70
        error: Option<DynamoError>,
71
    }
72

73
    impl MaybeError for TestError {
74
        fn from_err(err: impl std::error::Error + 'static) -> Self {
75
            TestError {
76
77
78
                error: Some(DynamoError::from(
                    Box::new(err) as Box<dyn std::error::Error + 'static>
                )),
79
80
            }
        }
81
82
83

        fn err(&self) -> Option<DynamoError> {
            self.error.clone()
84
85
86
87
88
        }
    }

    #[test]
    fn test_maybe_error_default_implementations() {
89
90
91
        let dynamo_err = DynamoError::msg("Test error");
        let err = TestError::from_err(dynamo_err);
        assert!(err.err().unwrap().to_string().contains("Test error"));
92
93
94
        assert!(!err.is_ok());
        assert!(err.is_err());
    }
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111

    #[test]
    fn test_from_std_error() {
        let std_err = std::io::Error::other("io failure");
        let test_err = TestError::from_err(std_err);

        assert!(test_err.is_err());
        assert!(test_err.err().unwrap().to_string().contains("io failure"));
    }

    #[test]
    fn test_not_error() {
        let test = TestError { error: None };
        assert!(test.is_ok());
        assert!(!test.is_err());
        assert!(test.err().is_none());
    }
112
}