typedb_driver/common/address/addresses.rs
1/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20use std::{
21 collections::HashMap,
22 fmt,
23 fmt::{Formatter, Write},
24};
25
26use itertools::Itertools;
27
28use crate::common::address::{Address, address_translation::AddressTranslation};
29
30/// A collection of server addresses used for connection.
31#[derive(Debug, Clone, Eq, PartialEq)]
32pub enum Addresses {
33 Direct(Vec<Address>),
34 Translated(HashMap<Address, Address>),
35}
36
37impl Addresses {
38 /// Prepare addresses based on a single "host:port" string.
39 ///
40 /// # Examples
41 ///
42 /// ```rust
43 /// Addresses::try_from_address_str("127.0.0.1:11729")
44 /// ```
45 pub fn try_from_address_str(address_str: impl AsRef<str>) -> crate::Result<Self> {
46 let address = address_str.as_ref().parse()?;
47 Ok(Self::from_address(address))
48 }
49
50 /// Prepare addresses based on a single TypeDB address.
51 ///
52 /// # Examples
53 ///
54 /// ```rust
55 /// let address = "127.0.0.1:11729".parse().unwrap();
56 /// Addresses::from_address(address)
57 /// ```
58 pub fn from_address(address: Address) -> Self {
59 Self::Direct(Vec::from([address]))
60 }
61
62 /// Prepare addresses based on multiple "host:port" strings.
63 /// Is used to specify multiple addresses connect to.
64 ///
65 /// # Examples
66 ///
67 /// ```rust
68 /// Addresses::try_from_addresses_str(["127.0.0.1:11729", "127.0.0.1:11730", "127.0.0.1:11731"])
69 /// ```
70 pub fn try_from_addresses_str(addresses_str: impl IntoIterator<Item = impl AsRef<str>>) -> crate::Result<Self> {
71 let addresses: Vec<Address> =
72 addresses_str.into_iter().map(|address_str| address_str.as_ref().parse()).try_collect()?;
73 Ok(Self::from_addresses(addresses))
74 }
75
76 /// Prepare addresses based on multiple TypeDB addresses.
77 ///
78 /// # Examples
79 ///
80 /// ```rust
81 /// let address1 = "127.0.0.1:11729".parse().unwrap();
82 /// let address2 = "127.0.0.1:11730".parse().unwrap();
83 /// let address3 = "127.0.0.1:11731".parse().unwrap();
84 /// Addresses::from_addresses([address1, address2, address3])
85 /// ```
86 pub fn from_addresses(addresses: impl IntoIterator<Item = Address>) -> Self {
87 Self::Direct(addresses.into_iter().collect())
88 }
89
90 /// Prepare addresses based on multiple key-value (public-private) "key:port" string pairs.
91 /// Translation map from addresses to be used by the driver for connection to addresses received
92 /// from the TypeDB server(s).
93 ///
94 /// # Examples
95 ///
96 /// ```rust
97 /// Addresses::try_from_addresses_str(
98 /// [
99 /// ("typedb-cloud.ext:11729", "127.0.0.1:11729"),
100 /// ("typedb-cloud.ext:11730", "127.0.0.1:11730"),
101 /// ("typedb-cloud.ext:11731", "127.0.0.1:11731")
102 /// ].into()
103 /// )
104 /// ```
105 pub fn try_from_translation_str(addresses_str: HashMap<impl AsRef<str>, impl AsRef<str>>) -> crate::Result<Self> {
106 let mut addresses = HashMap::new();
107 for (address_key, address_value) in addresses_str.into_iter() {
108 addresses.insert(address_key.as_ref().parse()?, address_value.as_ref().parse()?);
109 }
110 Ok(Self::from_translation(addresses))
111 }
112
113 /// Prepare addresses based on multiple key-value (public-private) TypeDB address pairs.
114 /// Translation map from addresses to be used by the driver for connection to addresses received
115 /// from the TypeDB server(s).
116 ///
117 /// # Examples
118 ///
119 /// ```rust
120 /// let translation: HashMap<Address, Address> = [
121 /// ("typedb-cloud.ext:11729".parse()?, "127.0.0.1:11729".parse()?),
122 /// ("typedb-cloud.ext:11730".parse()?, "127.0.0.1:11730".parse()?),
123 /// ("typedb-cloud.ext:11731".parse()?, "127.0.0.1:11731".parse()?)
124 /// ].into();
125 /// Addresses::from_translation(translation)
126 /// ```
127 pub fn from_translation(addresses: HashMap<Address, Address>) -> Self {
128 Self::Translated(addresses)
129 }
130
131 /// Returns the number of address entries (addresses or address pairs) in the collection.
132 ///
133 /// # Examples
134 ///
135 /// ```rust
136 /// addresses.len()
137 /// ```
138 pub fn len(&self) -> usize {
139 match self {
140 Addresses::Direct(vec) => vec.len(),
141 Addresses::Translated(map) => map.len(),
142 }
143 }
144
145 /// Checks if the public address is a part of the addresses.
146 ///
147 /// # Examples
148 ///
149 /// ```rust
150 /// addresses.contains(&address)
151 /// ```
152 pub fn contains(&self, address: &Address) -> bool {
153 match self {
154 Addresses::Direct(vec) => vec.contains(address),
155 Addresses::Translated(map) => map.contains_key(address),
156 }
157 }
158
159 pub(crate) fn addresses(&self) -> AddressIter<'_> {
160 match self {
161 Addresses::Direct(vec) => AddressIter::Direct(vec.iter()),
162 Addresses::Translated(map) => AddressIter::Translated(map.keys()),
163 }
164 }
165
166 pub(crate) fn address_translation(&self) -> AddressTranslation {
167 match self {
168 Addresses::Direct(addresses) => AddressTranslation::Mapping(
169 addresses.into_iter().map(|address| (address.clone(), address.clone())).collect(),
170 ),
171 Addresses::Translated(translation) => AddressTranslation::Mapping(translation.clone()),
172 }
173 }
174
175 pub(crate) fn exclude_addresses(&mut self, excluded_addresses: &Addresses) {
176 match self {
177 Addresses::Direct(addresses) => {
178 addresses.retain(|address| excluded_addresses.contains(address));
179 }
180 Addresses::Translated(translation) => translation.retain(|address, _| excluded_addresses.contains(address)),
181 }
182 }
183}
184
185impl fmt::Display for Addresses {
186 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
187 match self {
188 Addresses::Direct(addresses) => {
189 f.write_char('[')?;
190 for (i, address) in addresses.iter().enumerate() {
191 if i > 0 {
192 f.write_str(", ")?;
193 }
194 write!(f, "{address}")?;
195 }
196 f.write_char(']')
197 }
198 Addresses::Translated(translation) => {
199 f.write_char('{')?;
200 for (i, (public, private)) in translation.iter().enumerate() {
201 if i > 0 {
202 f.write_str(", ")?;
203 }
204 write!(f, "{public}: {private}")?;
205 }
206 f.write_char('}')
207 }
208 }
209 }
210}
211
212impl Default for Addresses {
213 fn default() -> Self {
214 Self::Direct(Vec::default())
215 }
216}
217
218pub(crate) enum AddressIter<'a> {
219 Direct(std::slice::Iter<'a, Address>),
220 Translated(std::collections::hash_map::Keys<'a, Address, Address>),
221}
222
223impl<'a> Iterator for AddressIter<'a> {
224 type Item = &'a Address;
225
226 fn next(&mut self) -> Option<Self::Item> {
227 match self {
228 AddressIter::Direct(iter) => iter.next(),
229 AddressIter::Translated(iter) => iter.next(),
230 }
231 }
232}