1use thiserror::Error;
4
5pub type BondResult<T> = Result<T, BondError>;
7
8#[derive(Error, Debug, Clone, PartialEq, Eq)]
10pub enum IdentifierError {
11 #[error("Invalid {id_type} length: expected {expected}, got {actual}")]
13 InvalidLength {
14 id_type: &'static str,
16 expected: usize,
18 actual: usize,
20 },
21
22 #[error("Invalid {id_type} check digit for '{value}'")]
24 InvalidCheckDigit {
25 id_type: &'static str,
27 value: String,
29 },
30
31 #[error("Invalid character '{ch}' at position {position} in {id_type}")]
33 InvalidCharacter {
34 id_type: &'static str,
36 ch: char,
38 position: usize,
40 },
41
42 #[error("Invalid {id_type} format: {reason}")]
44 InvalidFormat {
45 id_type: &'static str,
47 reason: String,
49 },
50}
51
52#[derive(Error, Debug, Clone)]
54pub enum BondError {
55 #[error("Invalid bond specification: {reason}")]
57 InvalidSpec {
58 reason: String,
60 },
61
62 #[error("Missing required field: {field}")]
64 MissingField {
65 field: String,
67 },
68
69 #[error("Pricing failed: {reason}")]
71 PricingFailed {
72 reason: String,
74 },
75
76 #[error("Yield calculation failed to converge after {iterations} iterations")]
78 YieldConvergenceFailed {
79 iterations: u32,
81 },
82
83 #[error("Invalid price: {reason}")]
85 InvalidPrice {
86 reason: String,
88 },
89
90 #[error("Cash flow generation failed: {reason}")]
92 CashFlowFailed {
93 reason: String,
95 },
96
97 #[error("Settlement date {settlement} is after maturity {maturity}")]
99 SettlementAfterMaturity {
100 settlement: String,
102 maturity: String,
104 },
105
106 #[error("Invalid schedule: {message}")]
108 InvalidSchedule {
109 message: String,
111 },
112
113 #[error("Core error: {0}")]
115 CoreError(#[from] convex_core::ConvexError),
116
117 #[error("Curve error: {0}")]
119 CurveError(#[from] convex_curves::CurveError),
120}
121
122impl BondError {
123 #[must_use]
125 pub fn invalid_spec(reason: impl Into<String>) -> Self {
126 Self::InvalidSpec {
127 reason: reason.into(),
128 }
129 }
130
131 #[must_use]
133 pub fn missing_field(field: impl Into<String>) -> Self {
134 Self::MissingField {
135 field: field.into(),
136 }
137 }
138
139 #[must_use]
141 pub fn pricing_failed(reason: impl Into<String>) -> Self {
142 Self::PricingFailed {
143 reason: reason.into(),
144 }
145 }
146}