opendal/services/swift/
config.rs1use std::fmt::Debug;
19
20use serde::Deserialize;
21use serde::Serialize;
22
23use super::SWIFT_SCHEME;
24use super::backend::SwiftBuilder;
25
26#[derive(Default, Serialize, Deserialize, Clone, PartialEq, Eq)]
28#[serde(default)]
29#[non_exhaustive]
30pub struct SwiftConfig {
31 pub endpoint: Option<String>,
33 pub container: Option<String>,
35 pub root: Option<String>,
37 pub token: Option<String>,
39}
40
41impl Debug for SwiftConfig {
42 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
43 f.debug_struct("SwiftConfig")
44 .field("endpoint", &self.endpoint)
45 .field("container", &self.container)
46 .field("root", &self.root)
47 .finish_non_exhaustive()
48 }
49}
50
51impl crate::Configurator for SwiftConfig {
52 type Builder = SwiftBuilder;
53
54 fn from_uri(uri: &crate::types::OperatorUri) -> crate::Result<Self> {
55 let mut map = uri.options().clone();
56
57 if let Some(authority) = uri.authority() {
58 map.entry("endpoint".to_string())
59 .or_insert_with(|| format!("https://{authority}"));
60 } else if !map.contains_key("endpoint") {
61 return Err(
62 crate::Error::new(crate::ErrorKind::ConfigInvalid, "endpoint is required")
63 .with_context("service", SWIFT_SCHEME),
64 );
65 }
66
67 if let Some(path) = uri.root() {
68 if let Some((container, rest)) = path.split_once('/') {
69 if !container.is_empty() {
70 map.insert("container".to_string(), container.to_string());
71 }
72 if !rest.is_empty() {
73 map.insert("root".to_string(), rest.to_string());
74 }
75 } else if !path.is_empty() {
76 map.insert("container".to_string(), path.to_string());
77 }
78 }
79
80 if !map.contains_key("container") {
81 return Err(crate::Error::new(
82 crate::ErrorKind::ConfigInvalid,
83 "container is required",
84 )
85 .with_context("service", SWIFT_SCHEME));
86 }
87
88 Self::from_iter(map)
89 }
90
91 fn into_builder(self) -> Self::Builder {
92 SwiftBuilder { config: self }
93 }
94}
95
96#[cfg(test)]
97mod tests {
98 use super::*;
99 use crate::Configurator;
100 use crate::types::OperatorUri;
101
102 #[test]
103 fn from_uri_sets_endpoint_container_and_root() {
104 let uri = OperatorUri::new(
105 "swift://swift.example.com/container/assets/images",
106 Vec::<(String, String)>::new(),
107 )
108 .unwrap();
109
110 let cfg = SwiftConfig::from_uri(&uri).unwrap();
111 assert_eq!(cfg.endpoint.as_deref(), Some("https://swift.example.com"));
112 assert_eq!(cfg.container.as_deref(), Some("container"));
113 assert_eq!(cfg.root.as_deref(), Some("assets/images"));
114 }
115
116 #[test]
117 fn from_uri_accepts_container_from_query() {
118 let uri = OperatorUri::new(
119 "swift://swift.example.com",
120 vec![("container".to_string(), "logs".to_string())],
121 )
122 .unwrap();
123
124 let cfg = SwiftConfig::from_uri(&uri).unwrap();
125 assert_eq!(cfg.container.as_deref(), Some("logs"));
126 assert_eq!(cfg.endpoint.as_deref(), Some("https://swift.example.com"));
127 }
128}