commit d9826b0a30f42754dc5764ce02c7b0271d996c92 Merge: af049657e 124caf28e Author: Nick Mathewson nickm@torproject.org Date: Thu Feb 8 17:45:17 2018 -0500
Merge remote-tracking branch 'frewsxcv/frewsxcv-protover'
src/rust/protover/protover.rs | 295 ++++++++++++++++++++++-------------------- 1 file changed, 152 insertions(+), 143 deletions(-)
diff --cc src/rust/protover/protover.rs index 069b1088c,af0049a41..826f1b73f --- a/src/rust/protover/protover.rs +++ b/src/rust/protover/protover.rs @@@ -105,102 -94,124 +105,116 @@@ impl FromStr for Proto /// /// "HSDir=1-1 LinkAuth=1" /// -pub fn get_supported_protocols() -> String { - SUPPORTED_PROTOCOLS.join(" ") +pub fn get_supported_protocols() -> &'static str { + // The `len() - 1` is to remove the NUL byte. + // The `unwrap` is safe becauase we SUPPORTED_PROTOCOLS is under + // our control. + str::from_utf8(&SUPPORTED_PROTOCOLS[..SUPPORTED_PROTOCOLS.len() - 1]) + .unwrap() }
- /// Translates a vector representation of a protocol list into a HashMap - fn parse_protocols<P, S>( - protocols: P, - ) -> Result<HashMap<Proto, HashSet<u32>>, &'static str> - where - P: Iterator<Item = S>, - S: AsRef<str>, - { - let mut parsed = HashMap::new(); - - for subproto in protocols { - let (name, version) = get_proto_and_vers(subproto.as_ref())?; - parsed.insert(name, version); + pub struct SupportedProtocols(HashMap<Proto, Versions>); + + impl SupportedProtocols { - /// # 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(" ")) - } - - /// ``` - /// use protover::SupportedProtocols; - /// - /// let supported_protocols = SupportedProtocols::from_proto_entries([ - /// "HSDir=1-2", - /// "HSIntro=3-4", - /// ].iter()); - /// ``` + 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)) } - Ok(parsed) - }
- /// Translates a string representation of a protocol list to a HashMap - fn parse_protocols_from_string<'a>( - protocol_string: &'a str, - ) -> Result<HashMap<Proto, HashSet<u32>>, &'static str> { - parse_protocols(protocol_string.split(" ")) - } - - /// Translates supported tor versions from a string into a HashMap, which is - /// useful when looking up a specific subprotocol. - /// - /// # Returns - /// - /// A `Result` whose `Ok` value is a `HashMap<Proto, <u32>>` holding all - /// subprotocols and versions currently supported by tor. - /// - /// The returned `Result`'s `Err` value is an `&'static str` with a description - /// of the error. - /// - fn tor_supported() -> Result<HashMap<Proto, HashSet<u32>>, &'static str> { - parse_protocols(get_supported_protocols().split(" ")) - } - /// Translates supported tor versions from a string into a HashMap, which - /// is useful when looking up a specific subprotocol. ++ /// Translates a string representation of a protocol list to a ++ /// SupportedProtocols instance. + /// - /// # Returns ++ /// # Examples + /// - /// A `Result` whose `Ok` value is a `HashMap<Proto, <Version>>` holding all - /// subprotocols and versions currently supported by tor. ++ /// ``` ++ /// use protover::SupportedProtocols; + /// - /// The returned `Result`'s `Err` value is an `&'static str` with a - /// description of the error. ++ /// 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(" ")) ++ } + - /// Get the unique version numbers supported by a subprotocol. - /// - /// # Inputs - /// - /// * `version_string`, a string comprised of "[0-9,-]" - /// - /// # Returns - /// - /// A `Result` whose `Ok` value is a `HashSet<u32>` holding all of the unique - /// version numbers. If there were ranges in the `version_string`, then these - /// are expanded, i.e. `"1-3"` would expand to `HashSet<u32>::new([1, 2, 3])`. - /// The returned HashSet is *unordered*. - /// - /// The returned `Result`'s `Err` value is an `&'static str` with a description - /// of the error. - /// - /// # Errors - /// - /// This function will error if: - /// - /// * the `version_string` is empty or contains an equals (`"="`) sign, - /// * the expansion of a version range produces an error (see - /// `expand_version_range`), - /// * any single version number is not parseable as an `u32` in radix 10, or - /// * there are greater than 2^16 version numbers to expand. - /// - fn get_versions(version_string: &str) -> Result<HashSet<u32>, &'static str> { - if version_string.is_empty() { - return Err("version string is empty"); ++ /// Translate the supported tor versions from a string into a ++ /// HashMap, which is useful when looking up a specific ++ /// subprotocol. + /// + fn tor_supported() -> Result<Self, &'static str> { - Self::from_proto_entries(SUPPORTED_PROTOCOLS.iter().map(|n| *n)) ++ Self::from_proto_entries_string(get_supported_protocols()) } + }
- let mut versions = HashSet::<u32>::new(); + type Version = u32; + + /// Set of versions for a protocol. + #[derive(Debug, PartialEq, Eq)] + pub struct Versions(HashSet<Version>); + + impl Versions { + /// Get the unique version numbers supported by a subprotocol. + /// + /// # Inputs + /// + /// * `version_string`, a string comprised of "[0-9,-]" + /// + /// # Returns + /// + /// A `Result` whose `Ok` value is a `HashSet<u32>` holding all of the unique + /// version numbers. If there were ranges in the `version_string`, then these + /// are expanded, i.e. `"1-3"` would expand to `HashSet<u32>::new([1, 2, 3])`. + /// The returned HashSet is *unordered*. + /// + /// The returned `Result`'s `Err` value is an `&'static str` with a description + /// of the error. + /// + /// # Errors + /// + /// This function will error if: + /// + /// * the `version_string` is empty or contains an equals (`"="`) sign, + /// * the expansion of a version range produces an error (see + /// `expand_version_range`), + /// * any single version number is not parseable as an `u32` in radix 10, or + /// * there are greater than 2^16 version numbers to expand. + /// + fn from_version_string( + version_string: &str, + ) -> Result<Self, &'static str> { + if version_string.is_empty() { + return Err("version string is empty"); + }
- for piece in version_string.split(",") { - if piece.contains("-") { - for p in expand_version_range(piece)? { - versions.insert(p); + let mut versions = HashSet::<Version>::new(); + + for piece in version_string.split(",") { + if piece.contains("-") { + for p in expand_version_range(piece)? { + versions.insert(p); + } + } else { + versions.insert(u32::from_str(piece).or( + Err("invalid protocol entry"), + )?); } - } else { - versions.insert(u32::from_str(piece).or( - Err("invalid protocol entry"), - )?); - }
- if versions.len() > MAX_PROTOCOLS_TO_EXPAND as usize { - return Err("Too many versions to expand"); + if versions.len() > MAX_PROTOCOLS_TO_EXPAND as usize { + return Err("Too many versions to expand"); + } } + Ok(Versions(versions)) } - Ok(versions) }
tor-commits@lists.torproject.org