Skip to main content

apcore_toolkit/output/
mod.rs

1// Output writers for ScannedModule data.
2//
3// Provides writers for different output formats (YAML, registry, HTTP proxy).
4
5pub mod errors;
6pub mod registry_writer;
7pub mod types;
8pub mod verifiers;
9pub mod yaml_writer;
10
11#[cfg(feature = "http-proxy")]
12pub mod http_proxy_writer;
13
14use serde::{Deserialize, Serialize};
15use thiserror::Error;
16
17/// Error returned by [`get_writer`] when an unrecognised format string is supplied.
18#[derive(Debug, Error, PartialEq)]
19pub enum OutputFormatError {
20    /// The format string does not map to a known [`OutputFormat`] variant.
21    #[error("Unknown output format: {0}")]
22    Unknown(String),
23}
24
25/// Supported output format variants.
26///
27/// Used by `get_writer` to select the appropriate writer implementation.
28/// Each variant corresponds to a distinct writer struct with its own `write()`
29/// signature, so the factory returns the enum itself rather than a trait object.
30#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
31pub enum OutputFormat {
32    /// Write `.binding.yaml` files to disk.
33    Yaml,
34    /// Register modules directly into an apcore Registry.
35    Registry,
36    /// Register modules as HTTP proxy modules (requires `http-proxy` feature).
37    #[cfg(feature = "http-proxy")]
38    HttpProxy,
39}
40
41/// Convenience factory that returns the `OutputFormat` variant for a given
42/// format string.
43///
44/// # Accepted values (case-insensitive)
45///
46/// | Input | Variant |
47/// |-------|---------|
48/// | `"yaml"` | `OutputFormat::Yaml` |
49/// | `"registry"` | `OutputFormat::Registry` |
50/// | `"http_proxy"` / `"http-proxy"` / `"httpproxy"` | `OutputFormat::HttpProxy` |
51///
52/// Returns `Err` for unrecognised strings.
53///
54/// # Usage
55///
56/// ```rust
57/// use apcore_toolkit::output::get_writer;
58/// use apcore_toolkit::output::OutputFormat;
59///
60/// let fmt = get_writer("yaml").unwrap();
61/// assert_eq!(fmt, OutputFormat::Yaml);
62///
63/// // Then instantiate the concrete writer:
64/// match fmt {
65///     OutputFormat::Yaml => { /* use YAMLWriter */ }
66///     OutputFormat::Registry => { /* use RegistryWriter */ }
67///     // OutputFormat::HttpProxy (feature "http-proxy") => use HTTPProxyRegistryWriter
68///     #[allow(unreachable_patterns)]
69///     _ => { /* other variants (e.g. HttpProxy when the `http-proxy` feature is enabled) */ }
70/// }
71/// ```
72pub fn get_writer(format: &str) -> Result<OutputFormat, OutputFormatError> {
73    match format.to_ascii_lowercase().as_str() {
74        "yaml" => Ok(OutputFormat::Yaml),
75        "registry" => Ok(OutputFormat::Registry),
76        #[cfg(feature = "http-proxy")]
77        "http_proxy" | "http-proxy" | "httpproxy" => Ok(OutputFormat::HttpProxy),
78        _ => Err(OutputFormatError::Unknown(format.to_string())),
79    }
80}
81
82#[cfg(test)]
83mod tests {
84    use super::*;
85
86    #[test]
87    fn test_get_writer_yaml() {
88        assert_eq!(get_writer("yaml"), Ok(OutputFormat::Yaml));
89    }
90
91    #[test]
92    fn test_get_writer_registry() {
93        assert_eq!(get_writer("registry"), Ok(OutputFormat::Registry));
94    }
95
96    #[cfg(feature = "http-proxy")]
97    #[test]
98    fn test_get_writer_http_proxy_variants() {
99        assert_eq!(get_writer("http_proxy"), Ok(OutputFormat::HttpProxy));
100        assert_eq!(get_writer("http-proxy"), Ok(OutputFormat::HttpProxy));
101        assert_eq!(get_writer("httpproxy"), Ok(OutputFormat::HttpProxy));
102    }
103
104    #[test]
105    fn test_get_writer_case_insensitive() {
106        assert_eq!(get_writer("YAML"), Ok(OutputFormat::Yaml));
107        assert_eq!(get_writer("Registry"), Ok(OutputFormat::Registry));
108    }
109
110    #[cfg(feature = "http-proxy")]
111    #[test]
112    fn test_get_writer_case_insensitive_http_proxy() {
113        assert_eq!(get_writer("HTTP_PROXY"), Ok(OutputFormat::HttpProxy));
114    }
115
116    #[test]
117    fn test_get_writer_unknown() {
118        assert!(get_writer("xml").is_err());
119        assert!(get_writer("").is_err());
120        assert!(get_writer("xml")
121            .unwrap_err()
122            .to_string()
123            .contains("Unknown output format"));
124    }
125
126    #[test]
127    fn test_output_format_serde_roundtrip() {
128        let fmt = OutputFormat::Yaml;
129        let json = serde_json::to_string(&fmt).unwrap();
130        let deserialized: OutputFormat = serde_json::from_str(&json).unwrap();
131        assert_eq!(deserialized, fmt);
132    }
133}