1use crate::core::values;
2use crate::sys;
3use crate::HasMqNames;
4use std::fmt::{Debug, Display};
5
6pub type ReasonCode = values::MQRC;
8
9pub type CompletionCode = values::MQCC;
11
12impl Default for ReasonCode {
13 fn default() -> Self {
14 Self(sys::MQRC_NONE)
15 }
16}
17
18impl Default for CompletionCode {
19 fn default() -> Self {
20 Self(sys::MQCC_UNKNOWN)
21 }
22}
23
24impl ReasonCode {
25 #[must_use]
26 pub fn ibm_reference_url(&self, language: &str, version: Option<&str>) -> Option<String> {
27 let name = self.mq_primary_name()?.to_lowercase().replace('_', "-");
28 let version = version.unwrap_or("latest");
29 let code = self.value();
30 Some(format!(
31 "https://www.ibm.com/docs/{language}/ibm-mq/{version}?topic=codes-{code}-{code:04x}-rc{code}-{name}"
32 ))
33 }
34}
35#[derive(Debug, Clone, derive_more::Deref, derive_more::DerefMut, derive_more::AsRef, derive_more::AsMut)]
37#[must_use]
38pub struct Completion<T>(
39 #[deref]
40 #[deref_mut]
41 #[as_ref]
42 #[as_mut]
43 pub T,
44 pub Option<(ReasonCode, &'static str)>,
45);
46
47impl<T> Completion<T> {
48 pub const fn new(value: T) -> Self {
49 Self(value, None)
50 }
51
52 pub const fn new_warning(value: T, warning: (ReasonCode, &'static str)) -> Self {
53 Self(value, Some(warning))
54 }
55}
56
57impl<T: std::process::Termination> std::process::Termination for Completion<T> {
58 fn report(self) -> std::process::ExitCode {
59 self.discard_warning().report()
60 }
61}
62
63impl<T> Completion<T> {
64 pub fn map<U, F: FnOnce(T) -> U>(self, op: F) -> Completion<U> {
65 let Self(value, warning) = self;
66 Completion(op(value), warning)
67 }
68
69 pub fn discard_warning(self) -> T {
71 let Self(value, ..) = self;
72 value
73 }
74
75 #[must_use]
77 pub const fn warning(&self) -> Option<(ReasonCode, &'static str)> {
78 let Self(_, warning) = self;
79 *warning
80 }
81}
82
83impl<I: Iterator> Iterator for Completion<I> {
84 type Item = I::Item;
85
86 fn next(&mut self) -> Option<Self::Item> {
87 let iter = &mut **self;
88 iter.next()
89 }
90
91 fn size_hint(&self) -> (usize, Option<usize>) {
92 let iter = &**self;
93 iter.size_hint()
94 }
95}
96
97impl<T: Display> Display for Completion<T> {
98 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
99 match self {
100 Self(value, Some((warning, verb))) => write!(f, "MQCC_WARNING: {verb} {warning} {value}"),
101 Self(value, None) => write!(f, "MQCC_OK: {value}"),
102 }
103 }
104}
105
106#[derive(Debug, derive_more::Error, derive_more::Display)]
108#[display("{_0}: {_1} - {_2}")]
109pub struct Error(pub CompletionCode, pub &'static str, pub ReasonCode);
110
111pub type ResultCompErr<T, E> = Result<Completion<T>, E>;
113pub type ResultComp<T> = Result<Completion<T>, Error>;
115pub type ResultErr<T> = Result<T, Error>;
117
118pub trait ResultCompExt<T, E> {
120 fn warn_as_error(self) -> Result<T, E>;
122}
123
124pub trait WithMQError {
125 fn mqi_error(&self) -> Option<&Error>;
126}
127
128impl WithMQError for Error {
129 fn mqi_error(&self) -> Option<&Error> {
130 Some(self)
131 }
132}
133
134pub trait ResultCompErrExt<T, E> {
136 fn map_completion<U, F: FnOnce(T) -> U>(self, op: F) -> ResultCompErr<U, E>;
138
139 fn discard_warning(self) -> Result<T, E>;
141
142 fn unwrap_completion(self) -> T;
149}
150
151impl<T, E> ResultCompErrExt<T, E> for ResultCompErr<T, E>
152where
153 E: std::fmt::Debug, {
155 fn map_completion<U, F: FnOnce(T) -> U>(self, op: F) -> ResultCompErr<U, E> {
156 self.map(|mq| mq.map(op))
157 }
158
159 #[expect(clippy::unwrap_used)]
160 fn unwrap_completion(self) -> T {
161 self.unwrap().discard_warning()
162 }
163
164 fn discard_warning(self) -> Result<T, E> {
165 self.map(Completion::discard_warning)
166 }
167}
168
169impl<T, E: From<Error>> ResultCompExt<T, E> for ResultCompErr<T, E> {
170 fn warn_as_error(self) -> Result<T, E> {
171 match self {
172 Ok(Completion(_, Some((warn_cc, verb)))) => {
173 Err(E::from(Error(CompletionCode::from(sys::MQCC_WARNING), verb, warn_cc)))
174 }
175 other => other.map(|Completion(value, ..)| value),
176 }
177 }
178}
179
180#[cfg(test)]
181mod tests {
182 use crate::sys;
183 use crate::ReasonCode;
184
185 #[test]
186 fn mqmd_new() {
187 let d = sys::MQMD2::default();
188 assert_eq!(d.Version, 2);
189 }
190
191 #[test]
192 fn reason_code_display() {
193 assert_eq!(ReasonCode::from(sys::MQRC_Q_MGR_ACTIVE).to_string(), "MQRC_Q_MGR_ACTIVE");
194 assert_eq!(ReasonCode::from(sys::MQRC_NONE).to_string(), "MQRC_NONE");
195 assert_eq!(ReasonCode::from(-1).to_string(), "-1");
196 }
197
198 #[test]
199 fn ibm_reference_url() {
200 assert_eq!(
201 ReasonCode::from(sys::MQRC_Q_ALREADY_EXISTS).ibm_reference_url("en", None),
202 Some("https://www.ibm.com/docs/en/ibm-mq/latest?topic=codes-2290-08f2-rc2290-mqrc-q-already-exists".to_owned())
203 );
204 }
205}