Skip to main content

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}