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}