[tor-commits] [tor/maint-0.3.3] rust: Add new protover::ProtoEntry type which uses new datatypes.

nickm at torproject.org nickm at torproject.org
Tue Apr 3 23:16:04 UTC 2018


commit 54c964332b27104e56442128f8ce85110af89c96
Author: Isis Lovecruft <isis at torproject.org>
Date:   Wed Mar 21 01:18:02 2018 +0000

    rust: Add new protover::ProtoEntry type which uses new datatypes.
    
    This replaces the `protover::SupportedProtocols` (why would you have a type just
    for things which are supported?) with a new, more generic type,
    `protover::ProtoEntry`, which utilises the new, more memory-efficient datatype
    in protover::protoset.
    
     * REMOVE `get_supported_protocols()` and `SupportedProtocols::tor_supported()`
       (since they were never used separately) and collapse their functionality into
       a single `ProtoEntry::supported()` method.
     * REMOVE `SupportedProtocols::from_proto_entries()` and reimplement its
       functionality as the more rusty `impl FromStr for ProtoEntry`.
     * REMOVE `get_proto_and_vers()` function and refactor it into the more rusty
       `impl FromStr for ProtoEntry`.
     * FIXES part of #24031: https://bugs.torproject.org/24031
---
 src/rust/protover/protover.rs | 144 ++++++++++++++++++++++--------------------
 1 file changed, 75 insertions(+), 69 deletions(-)

diff --git a/src/rust/protover/protover.rs b/src/rust/protover/protover.rs
index 1ccad4af4..1f62e70f1 100644
--- a/src/rust/protover/protover.rs
+++ b/src/rust/protover/protover.rs
@@ -1,20 +1,19 @@
 // Copyright (c) 2016-2017, The Tor Project, Inc. */
 // See LICENSE for licensing information */
 
-use external::c_tor_version_as_new_as;
-
+use std::collections::HashMap;
+use std::collections::hash_map;
+use std::fmt;
 use std::str;
 use std::str::FromStr;
-use std::fmt;
-use std::collections::{HashMap, HashSet};
-use std::ops::Range;
 use std::string::String;
-use std::u32;
 
 use tor_util::strings::NUL_BYTE;
+use external::c_tor_version_as_new_as;
 
 use errors::ProtoverError;
 use protoset::Version;
+use protoset::ProtoSet;
 
 /// The first version of Tor that included "proto" entries in its descriptors.
 /// Authorities should use this to decide whether to guess proto lines.
@@ -142,82 +141,89 @@ pub fn get_supported_protocols() -> &'static str {
         .unwrap_or("")
 }
 
-pub struct SupportedProtocols(HashMap<Proto, Versions>);
-
-impl SupportedProtocols {
-    pub fn from_proto_entries<I, S>(protocol_strs: I) -> Result<Self, &'static str>
-    where
-        I: Iterator<Item = S>,
-        S: AsRef<str>,
-    {
-        let mut parsed = HashMap::new();
-        for subproto in protocol_strs {
-            let (name, version) = get_proto_and_vers(subproto.as_ref())?;
-            parsed.insert(name, version);
-        }
-        Ok(SupportedProtocols(parsed))
+/// A map of protocol names to the versions of them which are supported.
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub struct ProtoEntry(HashMap<Protocol, ProtoSet>);
+
+impl Default for ProtoEntry {
+    fn default() -> ProtoEntry {
+        ProtoEntry( HashMap::new() )
     }
+}
 
-    /// Translates a string representation of a protocol list to a
-    /// SupportedProtocols instance.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use protover::SupportedProtocols;
-    ///
-    /// let supported_protocols = SupportedProtocols::from_proto_entries_string(
-    ///     "HSDir=1-2 HSIntro=3-4"
-    /// );
-    /// ```
-    pub fn from_proto_entries_string(
-        proto_entries: &str,
-    ) -> Result<Self, &'static str> {
-        Self::from_proto_entries(proto_entries.split(" "))
+impl ProtoEntry {
+    /// Get an iterator over the `Protocol`s and their `ProtoSet`s in this `ProtoEntry`.
+    pub fn iter(&self) -> hash_map::Iter<Protocol, ProtoSet> {
+        self.0.iter()
     }
 
     /// Translate the supported tor versions from a string into a
-    /// HashMap, which is useful when looking up a specific
+    /// ProtoEntry, which is useful when looking up a specific
     /// subprotocol.
-    ///
-    fn tor_supported() -> Result<Self, &'static str> {
-        Self::from_proto_entries_string(get_supported_protocols())
+    pub fn supported() -> Result<Self, ProtoverError> {
+        let supported: &'static str = get_supported_protocols();
+
+        supported.parse()
+    }
+
+    pub fn get(&self, protocol: &Protocol) -> Option<&ProtoSet> {
+        self.0.get(protocol)
+    }
+
+    pub fn insert(&mut self, key: Protocol, value: ProtoSet) {
+        self.0.insert(key, value);
+    }
+
+    pub fn remove(&mut self, key: &Protocol) -> Option<ProtoSet> {
+        self.0.remove(key)
+    }
+
+    pub fn is_empty(&self) -> bool {
+        self.0.is_empty()
     }
 }
 
-/// Parse the subprotocol type and its version numbers.
-///
-/// # Inputs
-///
-/// * A `protocol_entry` string, comprised of a keyword, an "=" sign, and one
-/// or more version numbers.
-///
-/// # Returns
-///
-/// A `Result` whose `Ok` value is a tuple of `(Proto, HashSet<u32>)`, where the
-/// first element is the subprotocol type (see `protover::Proto`) and the last
-/// element is a(n unordered) set of unique version numbers which are supported.
-/// Otherwise, the `Err` value of this `Result` is a description of the error
-///
-fn get_proto_and_vers<'a>(
-    protocol_entry: &'a str,
-) -> Result<(Proto, Versions), &'static str> {
-    let mut parts = protocol_entry.splitn(2, "=");
+impl FromStr for ProtoEntry {
+    type Err = ProtoverError;
 
-    let proto = match parts.next() {
-        Some(n) => n,
-        None => return Err("invalid protover entry"),
-    };
+    /// Parse a string of subprotocol types and their version numbers.
+    ///
+    /// # Inputs
+    ///
+    /// * A `protocol_entry` string, comprised of a keywords, an "=" sign, and
+    /// one or more version numbers, each separated by a space.  For example,
+    /// `"Cons=3-4 HSDir=1"`.
+    ///
+    /// # Returns
+    ///
+    /// A `Result` whose `Ok` value is a `ProtoEntry`, where the
+    /// first element is the subprotocol type (see `protover::Protocol`) and the last
+    /// element is an ordered set of `(low, high)` unique version numbers which are supported.
+    /// Otherwise, the `Err` value of this `Result` is a `ProtoverError`.
+    fn from_str(protocol_entry: &str) -> Result<ProtoEntry, ProtoverError> {
+        let mut proto_entry: ProtoEntry = ProtoEntry::default();
+        let entries = protocol_entry.split(' ');
+
+        for entry in entries {
+            let mut parts = entry.splitn(2, '=');
+
+            let proto = match parts.next() {
+                Some(n) => n,
+                None => return Err(ProtoverError::Unparseable),
+            };
 
-    let vers = match parts.next() {
-        Some(n) => n,
-        None => return Err("invalid protover entry"),
-    };
+            let vers = match parts.next() {
+                Some(n) => n,
+                None => return Err(ProtoverError::Unparseable),
+            };
+            let versions: ProtoSet = vers.parse()?;
+            let proto_name: Protocol = proto.parse()?;
 
-    let versions = Versions::from_version_string(vers)?;
-    let proto_name = proto.parse()?;
+            proto_entry.insert(proto_name, versions);
+        }
 
-    Ok((proto_name, versions))
+        Ok(proto_entry)
+    }
 }
 
 /// Parses a single subprotocol entry string into subprotocol and version





More information about the tor-commits mailing list