1
2
3
4
5
6
7
8
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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
use std::path::PathBuf;

use thiserror::Error;

/// Wick Manifest's Errors.
#[derive(Error, Debug)]
#[non_exhaustive]
pub enum ManifestError {
  /// Invalid version found in the parsed manifest.
  #[error("Invalid Manifest Version '{0}'; if this is a valid version, ensure you have enabled the v{0} feature for the configuration")]
  VersionError(String),

  /// Error related to asset references.
  #[cfg(feature = "config")]
  #[error(transparent)]
  AssetReference(#[from] wick_asset_reference::Error),

  /// Error related to fetching asset references.
  #[cfg(feature = "config")]
  #[error(transparent)]
  AssetContainer(#[from] asset_container::Error),

  /// Error rendering liquid JSON configuration.
  #[error(transparent)]
  LiquidConfig(#[from] liquid_json::Error),

  /// Attempted to retrieve the types in a manifest before they've been fetched.
  #[error("Attempted to retrieve the types in a manifest before they've been fetched")]
  TypesNotFetched,

  /// Attempted to import a type that was not found in the manifest.
  #[error("Attempted to import a type that was not found in the manifest: {0}")]
  TypeNotFound(String),

  /// No format version or kind found in the parsed manifest.
  #[error("Manifest {} needs a format version (v0) or kind (v1+)", .0.as_ref().map_or("<raw>".to_owned(), |v|v.display().to_string()))]
  NoFormat(Option<PathBuf>),

  /// Manifest not found at the specified path.
  #[error("File not found {0}")]
  FileNotFound(String),

  /// Could not load file.
  #[error("Could not load file {0}")]
  LoadError(String),

  /// Thrown when a specific type of configuration was expected but a different type was found.
  #[cfg(feature = "config")]
  #[cfg_attr(
    feature = "config",
    error("Expected a {0} configuration but got a {1} configuration")
  )]
  UnexpectedConfigurationKind(crate::config::ConfigurationKind, crate::config::ConfigurationKind),

  /// Thrown when a specific type of component was expected but a different type was found.
  #[cfg(feature = "config")]
  #[cfg_attr(feature = "config", error("Expected a {0} component but got a {1} component"))]
  UnexpectedComponentType(crate::config::ComponentKind, crate::config::ComponentKind),

  /// Error deserializing YAML manifest.
  #[error("Could not parse manifest {} as YAML: {1} at line {}, column {}", .0.as_ref().map_or("<raw>".to_owned(), |v|v.display().to_string()), .2.as_ref().map_or("unknown".to_owned(),|l|l.line().to_string()), .2.as_ref().map_or("unknown".to_owned(),|l|l.column().to_string()))]
  YamlError(Option<PathBuf>, String, Option<serde_yaml::Location>),

  /// IP address in manifest is invalid.
  #[error("Invalid IP Address: {0}")]
  BadIpAddress(String),

  /// Invalid regular expression.
  #[error("Invalid regular expression: {0}")]
  InvalidRegex(String),

  /// Invalid format of passed data. Check the error message for details.
  #[error("Invalid format: {0}")]
  Invalid(serde_json::Error),

  /// Invalid operation expression. Must be in the form component_name::operation_name.
  #[error("Invalid operation expression '{0}'. Must be in the form component_name::operation_name.")]
  InvalidOperationExpression(String),

  /// Parser error.
  #[error(transparent)]
  Parser(#[from] flow_expression_parser::Error),

  /// Type Parser error.
  #[error(transparent)]
  TypeParser(#[from] wick_interface_types::ParserError),

  /// Error converting an enum to a specific variant.
  #[error("could not convert a {0} into a {1}")]
  VariantError(String, String),

  /// Error parsing YAML as a string.
  #[error("Error parsing YAML as a string")]
  Utf8,

  /// Invalid authority format
  #[error("Invalid authority: {0}")]
  InvalidUrl(String),

  /// Identifier not found.
  #[error("id '{id}' undefined, IDs in scope are: {}", .ids.join(", "))]
  IdNotFound {
    /// The lookup id.
    id: String,
    /// The ids that exist in the lookup scope
    ids: Vec<String>,
  },

  /// Attempted to use configuration before it was renderable.
  #[error("Could not render configuration template: {0}")]
  ConfigurationTemplate(String),

  /// Passed [wick_packet::RuntimeConfig] is invalid for the configuration required by this component.
  #[cfg(feature = "config")]
  #[error(transparent)]
  ConfigurationInvalid(#[from] wick_packet::Error),

  /// Attempted to serialize a complex [liquid_json::LiquidJson] template into a string.
  #[error("Invalid template: could not turn an object or an array into a string")]
  TemplateStructure,

  /// Attempted to create a template render context from a non-object value.
  #[error("Invalid template context, context must be an object")]
  ContextBase,

  /// Attempted to use configuration before it was rendered.
  #[error("Attempted to use configuration '{0}' before it was rendered")]
  UnrenderedConfiguration(String),

  /// Error resolving reference.
  #[cfg(feature = "config")]
  #[cfg_attr(feature = "config", error(transparent))]
  Reference(#[from] ReferenceError),

  /// Error building a configuration
  #[cfg(feature = "config")]
  #[error(transparent)]
  Builder(#[from] BuilderError),

  /// Error converting configured Packet flags.
  #[error("Error converting configured Packet flags, use the singular version instead")]
  InvalidPacketFlags,
}

#[cfg(feature = "config")]
#[derive(Error, Debug, Clone, Copy)]
/// Errors that can occur when trying to dereference a configuration name or id.
pub enum ReferenceError {
  /// The referenced item was not a component.
  #[error("Referenced item is not a component")]
  Component,

  /// The referenced item was not an imported types configuration.
  #[error("Referenced item is not an imported types configuration")]
  Types,

  /// The referenced item was not a resource.
  #[error("Referenced item is not a resource")]
  Resource,

  /// The resource was not the requested type.
  #[error("Expected a resource of type {expected}, found type {actual}")]
  ResourceType {
    /// The expected resource type.
    expected: crate::config::resources::ResourceKind,
    /// The actual resource type.
    actual: crate::config::resources::ResourceKind,
  },
}

#[cfg(feature = "config")]
/// Errors generated when building a configuration.
#[derive(Error, Debug)]
pub enum BuilderError {
  /// Uninitialized field
  #[error("Uninitialized field: {0}")]
  UninitializedField(&'static str),
  /// Invalid builder configuration
  #[error("Invalid builder configuration: {0}")]
  ValidationError(String),
}

#[cfg(feature = "config")]
impl From<String> for BuilderError {
  fn from(s: String) -> Self {
    Self::ValidationError(s)
  }
}

#[cfg(feature = "config")]
impl From<derive_builder::UninitializedFieldError> for BuilderError {
  fn from(value: derive_builder::UninitializedFieldError) -> Self {
    Self::UninitializedField(value.field_name())
  }
}