opendal/types/builder.rs
1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements. See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership. The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License. You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied. See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18use std::collections::HashMap;
19use std::fmt::Debug;
20
21use http::Uri;
22use serde::de::DeserializeOwned;
23use serde::Serialize;
24
25use crate::raw::*;
26use crate::*;
27
28/// Builder is used to set up underlying services.
29///
30/// This trait allows the developer to define a builder struct that can:
31///
32/// - build a service via builder style API.
33/// - configure in-memory options like `http_client` or `customized_credential_load`.
34///
35/// Usually, users don't need to use or import this trait directly, they can use `Operator` API instead.
36///
37/// For example:
38///
39/// ```
40/// # use anyhow::Result;
41/// use opendal::services::Fs;
42/// use opendal::Operator;
43/// async fn test() -> Result<()> {
44/// // Create fs backend builder.
45/// let mut builder = Fs::default().root("/tmp");
46///
47/// // Build an `Operator` to start operating the storage.
48/// let op: Operator = Operator::new(builder)?.finish();
49///
50/// Ok(())
51/// }
52/// ```
53pub trait Builder: Default + 'static {
54 /// Associated configuration for this builder.
55 type Config: Configurator;
56
57 /// Consume the accessor builder to build a service.
58 fn build(self) -> Result<impl Access>;
59}
60
61/// Dummy implementation of builder
62impl Builder for () {
63 type Config = ();
64
65 fn build(self) -> Result<impl Access> {
66 Ok(())
67 }
68}
69
70/// Configurator is used to configure the underlying service.
71///
72/// This trait allows the developer to define a configuration struct that can:
73///
74/// - deserialize from an iterator like hashmap or vector.
75/// - convert into a service builder and finally build the underlying services.
76///
77/// Usually, users don't need to use or import this trait directly, they can use `Operator` API instead.
78///
79/// For example:
80///
81/// ```
82/// # use anyhow::Result;
83/// use std::collections::HashMap;
84///
85/// use opendal::services::MemoryConfig;
86/// use opendal::Operator;
87/// async fn test() -> Result<()> {
88/// let mut cfg = MemoryConfig::default();
89/// cfg.root = Some("/".to_string());
90///
91/// // Build an `Operator` to start operating the storage.
92/// let op: Operator = Operator::from_config(cfg)?.finish();
93///
94/// Ok(())
95/// }
96/// ```
97///
98/// Some service builder might contain in memory options like `http_client` . Users can call
99/// `into_builder` to convert the configuration into a builder instead.
100///
101/// ```
102/// # use anyhow::Result;
103/// use std::collections::HashMap;
104///
105/// use opendal::raw::HttpClient;
106/// use opendal::services::S3Config;
107/// use opendal::Configurator;
108/// use opendal::Operator;
109///
110/// async fn test() -> Result<()> {
111/// let mut cfg = S3Config::default();
112/// cfg.root = Some("/".to_string());
113/// cfg.bucket = "test".to_string();
114///
115/// let builder = cfg.into_builder();
116/// let builder = builder.http_client(HttpClient::new()?);
117///
118/// // Build an `Operator` to start operating the storage.
119/// let op: Operator = Operator::new(builder)?.finish();
120///
121/// Ok(())
122/// }
123/// ```
124pub trait Configurator: Serialize + DeserializeOwned + Debug + 'static {
125 /// Associated builder for this configuration.
126 type Builder: Builder;
127
128 /// Build configuration from a URI plus merged options.
129 fn from_uri(_uri: &Uri, _options: &HashMap<String, String>) -> Result<Self> {
130 Err(Error::new(ErrorKind::Unsupported, "uri is not supported"))
131 }
132
133 /// Deserialize from an iterator.
134 ///
135 /// This API is provided by opendal, developer should not implement it.
136 fn from_iter(iter: impl IntoIterator<Item = (String, String)>) -> Result<Self> {
137 let cfg = ConfigDeserializer::new(iter.into_iter().collect());
138
139 Self::deserialize(cfg).map_err(|err| {
140 Error::new(ErrorKind::ConfigInvalid, "failed to deserialize config").set_source(err)
141 })
142 }
143
144 /// Convert this configuration into a service builder.
145 fn into_builder(self) -> Self::Builder;
146}
147
148impl Configurator for () {
149 type Builder = ();
150
151 fn into_builder(self) -> Self::Builder {}
152}