Skip to content

Commit

Permalink
refactoring get_properties and TxtProperties (#88)
Browse files Browse the repository at this point in the history
* `get_properties` returns `&TxtProperties`.
* `TxtProperties` now has `iter()`.
  • Loading branch information
keepsimple1 authored Feb 21, 2023
1 parent e1026d0 commit f3d0033
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 29 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ default = ["async", "logging"]
flume = { version = "0.10", default-features = false } # channel between threads
if-addrs = "0.7" # get local IP addresses
log = { version = "0.4.14", optional = true } # logging
polling = "2.4" # select/poll sockets
polling = "2.1" # select/poll sockets
socket2 = { version = "0.4", features = ["all"] } # socket APIs

[dev-dependencies]
Expand Down
76 changes: 49 additions & 27 deletions src/service_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,7 @@ impl ServiceInfo {
/// implements [`IntoTxtProperties`] trait. It supports:
/// - `HashMap<String, String>`
/// - `Option<HashMap<String, String>>`
/// - `&[(&str, &str)]`
/// - `&[(String, String)]`
/// - slice of tuple: `&[(K, V)]` where `K` and `V` are [`std::string::ToString`].
///
/// `host_ipv4` can be one or more IPv4 addresses, in a type that implements
/// [`AsIpv4Addrs`] trait. It supports:
Expand Down Expand Up @@ -136,25 +135,21 @@ impl ServiceInfo {

/// Returns the properties from TXT records.
#[inline]
pub fn get_properties(&self) -> &[TxtProperty] {
&self.txt_properties.properties
pub fn get_properties(&self) -> &TxtProperties {
&self.txt_properties
}

/// Returns a property for a given `name`, where `name` is
/// Returns a property for a given `key`, where `key` is
/// case insensitive.
pub fn get_property(&self, name: &str) -> Option<&TxtProperty> {
let key = name.to_lowercase();
self.txt_properties
.properties
.iter()
.find(|&prop| prop.key.to_lowercase() == key)
pub fn get_property(&self, key: &str) -> Option<&TxtProperty> {
self.txt_properties.get(key)
}

/// Returns a property value string for a given `key`, where `key` is
/// case insensitive.
#[inline]
pub fn get_property_val(&self, key: &str) -> Option<&str> {
self.get_property(key).map(|x| x.val())
self.txt_properties.get_property_val(key)
}

/// Returns the service's hostname.
Expand Down Expand Up @@ -229,7 +224,7 @@ impl ServiceInfo {
}

pub(crate) fn generate_txt(&self) -> Vec<u8> {
encode_txt(self.get_properties())
encode_txt(self.get_properties().iter())
}

pub(crate) fn set_port(&mut self, port: u16) {
Expand Down Expand Up @@ -335,6 +330,38 @@ pub struct TxtProperties {
properties: Vec<TxtProperty>,
}

impl TxtProperties {
/// Returns an iterator for all properties.
pub fn iter(&self) -> impl Iterator<Item = &TxtProperty> {
self.properties.iter()
}

/// Returns the number of properties.
pub fn len(&self) -> usize {
self.properties.len()
}

/// Returns if the properties are empty.
pub fn is_empty(&self) -> bool {
self.properties.is_empty()
}

/// Returns a property for a given `key`, where `key` is
/// case insensitive.
pub fn get(&self, key: &str) -> Option<&TxtProperty> {
let key = key.to_lowercase();
self.properties
.iter()
.find(|&prop| prop.key.to_lowercase() == key)
}

/// Returns a property value string for a given `key`, where `key` is
/// case insensitive.
pub fn get_property_val(&self, key: &str) -> Option<&str> {
self.get(key).map(|x| x.val())
}
}

/// Represents a property in a TXT record.
#[derive(Debug, Clone, PartialEq)]
pub struct TxtProperty {
Expand All @@ -359,24 +386,19 @@ impl TxtProperty {
}

/// Supports constructing from a tuple.
impl From<&(&str, &str)> for TxtProperty {
fn from(prop: &(&str, &str)) -> Self {
impl<K, V> From<&(K, V)> for TxtProperty
where
K: ToString,
V: ToString,
{
fn from(prop: &(K, V)) -> Self {
TxtProperty {
key: prop.0.to_string(),
val: prop.1.to_string(),
}
}
}

impl From<&(String, String)> for TxtProperty {
fn from(prop: &(String, String)) -> Self {
TxtProperty {
key: prop.0.clone(),
val: prop.1.clone(),
}
}
}

/// This trait allows for converting inputs into [`TxtProperties`].
pub trait IntoTxtProperties {
fn into_txt_properties(self) -> TxtProperties;
Expand Down Expand Up @@ -432,9 +454,9 @@ where
}

// Convert from properties key/value pairs to DNS TXT record content
fn encode_txt(properties: &[TxtProperty]) -> Vec<u8> {
fn encode_txt<'a>(properties: impl Iterator<Item = &'a TxtProperty>) -> Vec<u8> {
let mut bytes = Vec::new();
for prop in properties.iter() {
for prop in properties {
let s = format!("{}={}", prop.key, prop.val);
bytes.push(s.len().try_into().unwrap());
bytes.extend_from_slice(s.as_bytes());
Expand Down Expand Up @@ -511,7 +533,7 @@ mod tests {
];

// test encode
let encoded = encode_txt(&properties);
let encoded = encode_txt(properties.iter());
assert_eq!(
encoded.len(),
"key1=".len() + "value1".len() + "key2=".len() + "value2".len() + 2
Expand Down
17 changes: 16 additions & 1 deletion tests/mdns_test.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use if_addrs::{IfAddr, Ifv4Addr};
use mdns_sd::{Error, ServiceDaemon, ServiceEvent, ServiceInfo, UnregisterStatus};
use mdns_sd::{
Error, IntoTxtProperties, ServiceDaemon, ServiceEvent, ServiceInfo, UnregisterStatus,
};
use std::collections::HashMap;
use std::net::Ipv4Addr;
use std::sync::{Arc, Mutex};
Expand Down Expand Up @@ -296,6 +298,19 @@ fn service_txt_properties_case_insensitive() {
assert_eq!(prop_mixed.key(), "prop_Cap_Lower");
}

#[test]
fn test_into_txt_properties() {
// Verify (&str, String) tuple is supported.
let properties = vec![("key1", String::from("val1"))];
let txt_props = properties.into_txt_properties();
assert_eq!(txt_props.get_property_val("key1").unwrap(), "val1");

// Verify (String, String) tuple is supported.
let properties = vec![(String::from("key2"), String::from("val2"))];
let txt_props = properties.into_txt_properties();
assert_eq!(txt_props.get_property_val("key2").unwrap(), "val2");
}

#[test]
fn service_with_invalid_addr() {
// Create a daemon
Expand Down

0 comments on commit f3d0033

Please sign in to comment.