cyclonedx_bom/
errors.rs

1/*
2 * This file is part of CycloneDX Rust Cargo.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 * SPDX-License-Identifier: Apache-2.0
17 */
18
19use std::convert::Infallible;
20
21use xml::name::OwnedName;
22
23use crate::models::bom::SpecVersion;
24
25#[derive(Debug, thiserror::Error)]
26#[non_exhaustive]
27pub enum BomError {
28    #[error("Failed to serialize BOM to JSON: {0}")]
29    JsonSerializationError(#[from] serde_json::Error),
30
31    #[error("Failed to serialize BOM to XML: {0}")]
32    XmlSerializationError(String),
33
34    #[error("Failed to serialize BOM with version {0:?}: {1}")]
35    BomSerializationError(SpecVersion, String),
36
37    #[error("Unsupported Spec Version '{0}'")]
38    UnsupportedSpecVersion(String),
39}
40
41// This allows to use `TryFrom` when a type only implements `From` inside a
42// `TryFrom<Error = BomError>` implementation.
43impl From<Infallible> for BomError {
44    fn from(err: Infallible) -> Self {
45        match err {}
46    }
47}
48
49#[derive(Debug, thiserror::Error)]
50#[non_exhaustive]
51pub enum JsonWriteError {
52    #[error("Failed to serialize JSON: {error}")]
53    JsonElementWriteError {
54        #[from]
55        error: serde_json::Error,
56    },
57    #[error("Failed to convert Bom: {error}")]
58    BomError {
59        #[from]
60        error: BomError,
61    },
62}
63
64#[derive(Debug, thiserror::Error)]
65#[non_exhaustive]
66pub enum XmlWriteError {
67    #[error("Failed to serialize XML while writing {element}: {error}")]
68    XmlElementWriteError {
69        #[source]
70        error: xml::writer::Error,
71        element: String,
72    },
73    #[error("Failed to convert Bom: {error}")]
74    BomError {
75        #[from]
76        error: BomError,
77    },
78}
79
80#[derive(Debug, thiserror::Error)]
81#[non_exhaustive]
82pub enum JsonReadError {
83    #[error("Failed to deserialize JSON: {error}")]
84    JsonElementReadError {
85        #[from]
86        error: serde_json::Error,
87    },
88    #[error("Invalid input format found: {error}")]
89    BomError {
90        #[from]
91        error: BomError,
92    },
93}
94
95#[derive(Debug, thiserror::Error)]
96#[non_exhaustive]
97pub enum XmlReadError {
98    #[error("Failed to deserialize XML while reading {element}: {error}")]
99    ElementReadError {
100        #[source]
101        error: xml::reader::Error,
102        element: String,
103    },
104    #[error("Got unexpected XML element when reading {element}: {error}")]
105    UnexpectedElementReadError { error: String, element: String },
106
107    #[error("Ended element {element} without data for required field {required_field}")]
108    RequiredDataMissing {
109        required_field: String,
110        element: String,
111    },
112
113    #[error("Required attribute {attribute} not found in element {element}")]
114    RequiredAttributeMissing { attribute: String, element: String },
115
116    #[error("Could not parse {value} as {data_type} on {element}")]
117    InvalidParseError {
118        value: String,
119        data_type: String,
120        element: String,
121    },
122
123    #[error(
124        "Expected document to be in the form {expected_namespace}, but received {}", .actual_namespace.as_ref().unwrap_or(&"no CycloneDX namespace".to_string())
125    )]
126    InvalidNamespaceError {
127        expected_namespace: String,
128        actual_namespace: Option<String>,
129    },
130}
131
132impl XmlReadError {
133    pub fn required_data_missing(required_field: &str, element: &OwnedName) -> Self {
134        Self::RequiredDataMissing {
135            required_field: required_field.to_string(),
136            element: element.local_name.to_string(),
137        }
138    }
139}