refactoring
Signed-off-by: Walker Crouse <walker.crouse@coop.co.uk>
This commit is contained in:
parent
3316b9a0e3
commit
426851e66a
@ -5,6 +5,7 @@ use avahi_sys::{
|
|||||||
avahi_string_list_length, avahi_string_list_new, avahi_string_list_to_string, AvahiStringList,
|
avahi_string_list_length, avahi_string_list_new, avahi_string_list_to_string, AvahiStringList,
|
||||||
};
|
};
|
||||||
use libc::{c_char, c_void};
|
use libc::{c_char, c_void};
|
||||||
|
use std::marker::PhantomData;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -64,20 +65,27 @@ impl Drop for ManagedAvahiStringList {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(new)]
|
#[derive(new)]
|
||||||
pub struct AvahiStringListNode(*mut AvahiStringList);
|
pub struct AvahiStringListNode<'a> {
|
||||||
|
list: *mut AvahiStringList,
|
||||||
|
phantom: PhantomData<&'a AvahiStringList>,
|
||||||
|
}
|
||||||
|
|
||||||
impl AvahiStringListNode {
|
impl<'a> AvahiStringListNode<'a> {
|
||||||
pub fn get_pair(&mut self) -> AvahiPair {
|
pub fn get_pair(&mut self) -> AvahiPair {
|
||||||
let mut key: *mut c_char = ptr::null_mut();
|
let mut key: *mut c_char = ptr::null_mut();
|
||||||
let mut value: *mut c_char = ptr::null_mut();
|
let mut value: *mut c_char = ptr::null_mut();
|
||||||
let mut value_size: usize = 0;
|
let mut value_size: usize = 0;
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
avahi_string_list_get_pair(self.0, &mut key, &mut value, &mut value_size);
|
avahi_string_list_get_pair(self.list, &mut key, &mut value, &mut value_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
AvahiPair::new(key.into(), value.into(), value_size)
|
AvahiPair::new(key.into(), value.into(), value_size)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn remove(&mut self) {
|
||||||
|
unsafe { avahi_string_list_free(self.list) };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(new, Getters)]
|
#[derive(new, Getters)]
|
||||||
@ -91,8 +99,12 @@ pub struct AvahiPair {
|
|||||||
pub struct AvahiString(*mut c_char);
|
pub struct AvahiString(*mut c_char);
|
||||||
|
|
||||||
impl AvahiString {
|
impl AvahiString {
|
||||||
pub fn as_str(&self) -> &str {
|
pub fn as_str(&self) -> Option<&str> {
|
||||||
unsafe { c_str::raw_to_str(self.0) }
|
if self.0.is_null() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(unsafe { c_str::raw_to_str(self.0) })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,12 +114,6 @@ impl From<*mut c_char> for AvahiString {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToString for AvahiString {
|
|
||||||
fn to_string(&self) -> String {
|
|
||||||
self.as_str().to_string()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for AvahiString {
|
impl Drop for AvahiString {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
if !self.0.is_null() {
|
if !self.0.is_null() {
|
||||||
@ -152,10 +158,10 @@ mod tests {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.get_pair();
|
.get_pair();
|
||||||
|
|
||||||
assert_eq!(pair1.key().as_str(), "foo");
|
assert_eq!(pair1.key().as_str().unwrap(), "foo");
|
||||||
assert_eq!(pair1.value().as_str(), "bar");
|
assert_eq!(pair1.value().as_str().unwrap(), "bar");
|
||||||
assert_eq!(pair2.key().as_str(), "hello");
|
assert_eq!(pair2.key().as_str().unwrap(), "hello");
|
||||||
assert_eq!(pair2.value().as_str(), "world");
|
assert_eq!(pair2.value().as_str().unwrap(), "world");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -175,7 +181,7 @@ mod tests {
|
|||||||
|
|
||||||
let pair = list.find(key.as_ptr() as *const c_char).unwrap().get_pair();
|
let pair = list.find(key.as_ptr() as *const c_char).unwrap().get_pair();
|
||||||
|
|
||||||
assert_eq!(pair.value().as_str(), "bar");
|
assert_eq!(pair.value().as_str().unwrap(), "bar");
|
||||||
|
|
||||||
let value = c_string!("baz");
|
let value = c_string!("baz");
|
||||||
|
|
||||||
@ -186,7 +192,27 @@ mod tests {
|
|||||||
|
|
||||||
let pair = list.find(key.as_ptr() as *const c_char).unwrap().get_pair();
|
let pair = list.find(key.as_ptr() as *const c_char).unwrap().get_pair();
|
||||||
|
|
||||||
assert_eq!(pair.value().as_str(), "baz");
|
assert_eq!(pair.value().as_str().unwrap(), "baz");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn remove_node_success() {
|
||||||
|
crate::tests::setup();
|
||||||
|
|
||||||
|
let mut list = ManagedAvahiStringList::new();
|
||||||
|
let key = c_string!("foo");
|
||||||
|
let value = c_string!("bar");
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
list.add_pair(
|
||||||
|
key.as_ptr() as *const c_char,
|
||||||
|
value.as_ptr() as *const c_char,
|
||||||
|
);
|
||||||
|
|
||||||
|
list.find(key.as_ptr() as *const c_char).unwrap().remove();
|
||||||
|
|
||||||
|
assert_eq!(list.length(), 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -222,7 +248,7 @@ mod tests {
|
|||||||
value.as_ptr() as *const c_char,
|
value.as_ptr() as *const c_char,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(list.to_string().as_str(), "\"foo=bar\"");
|
assert_eq!(list.to_string().as_str().unwrap(), "\"foo=bar\"");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,72 +1,84 @@
|
|||||||
|
use super::string_list::ManagedAvahiStringList;
|
||||||
use crate::Result;
|
use crate::Result;
|
||||||
|
use libc::c_char;
|
||||||
|
use std::cell::UnsafeCell;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone, PartialEq, Eq)]
|
#[derive(Debug, Default)]
|
||||||
pub struct AvahiTxtRecord(HashMap<String, String>);
|
pub struct AvahiTxtRecord(UnsafeCell<ManagedAvahiStringList>);
|
||||||
|
|
||||||
impl AvahiTxtRecord {
|
impl AvahiTxtRecord {
|
||||||
/// Constructs a new TXT record
|
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self(HashMap::new())
|
Self::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Inserts the specified value at the specified key.
|
/// Inserts the specified value at the specified key.
|
||||||
pub fn insert(&mut self, key: &str, value: &str) -> Result<()> {
|
pub fn insert(&mut self, key: &str, value: &str) -> Result<()> {
|
||||||
self.0.insert(key.to_string(), value.to_string());
|
unsafe {
|
||||||
|
self.inner().add_pair(
|
||||||
|
c_string!(key).as_ptr() as *const c_char,
|
||||||
|
c_string!(value).as_ptr() as *const c_char,
|
||||||
|
);
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the value at the specified key or `None` if no such key exists.
|
/// Returns the value at the specified key or `None` if no such key exists.
|
||||||
pub fn get(&self, key: &str) -> Option<&str> {
|
///
|
||||||
self.0.get(key).map(|s| s.as_str())
|
/// This function returns a owned `String` because there are no guarantees that the
|
||||||
|
/// implementation provides access to the underlying value pointer.
|
||||||
|
pub fn get(&self, key: &str) -> Option<String> {
|
||||||
|
unsafe {
|
||||||
|
self.inner()
|
||||||
|
.find(c_string!(key).as_ptr() as *const c_char)?
|
||||||
|
.get_pair()
|
||||||
|
.value()
|
||||||
|
.as_str()
|
||||||
|
.map(|s| s.to_string())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Removes the value at the specified key. Returns `Err` if no such key exists.
|
/// Removes the value at the specified key. Returns `Err` if no such key exists.
|
||||||
pub fn remove(&mut self, key: &str) -> Result<()> {
|
pub fn remove(&mut self, key: &str) -> Result<()> {
|
||||||
match self.0.remove(key) {
|
unsafe {
|
||||||
None => Err("no such key in TXT record".into()),
|
match self.inner().find(c_string!(key).as_ptr() as *const c_char) {
|
||||||
Some(_) => Ok(()),
|
None => Err("no such key".into()),
|
||||||
|
Some(node) => {
|
||||||
|
node.remove();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if the TXT record contains the specified key.
|
/// Returns true if the TXT record contains the specified key.
|
||||||
pub fn contains_key(&self, key: &str) -> bool {
|
pub fn contains_key(&self, key: &str) -> bool {
|
||||||
self.0.contains_key(key)
|
self.inner()
|
||||||
|
.find(c_string!(key).as_ptr() as *const c_char)
|
||||||
|
.is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the amount of entries in the TXT record.
|
/// Returns the amount of entries in the TXT record.
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
self.0.len()
|
self.inner().length() as usize
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if there are no entries in the record.
|
// /// Returns a new `txt_record::Iter` for iterating over the record as you would a `HashMap`.
|
||||||
pub fn is_empty(&self) -> bool {
|
// pub fn iter<'a>(&'a self) -> Box<dyn Iterator<Item = (String, String)> + 'a> {
|
||||||
self.len() == 0
|
// Box::new(Iter::new(self))
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
|
// /// Returns a new `txt_record::Iter` over the records keys.
|
||||||
|
// pub fn keys<'a>(&'a self) -> Box<dyn Iterator<Item = String> + 'a> {
|
||||||
|
// Box::new(Keys(Iter::new(self)))
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /// Returns a new `txt_record::Iter` over the records values.
|
||||||
|
// pub fn values<'a>(&'a self) -> Box<dyn Iterator<Item = String> + 'a> {
|
||||||
|
// Box::new(Values(Iter::new(self)))
|
||||||
|
// }
|
||||||
|
|
||||||
/// Returns a new `txt_record::Iter` for iterating over the record as you would a `HashMap`.
|
fn inner(&self) -> &mut ManagedAvahiStringList {
|
||||||
pub fn iter<'a>(&'a self) -> Box<dyn Iterator<Item = (String, &'a str)> + 'a> {
|
&mut *self.0.get()
|
||||||
Box::new(self.0.iter().map(|(k, v)| (k.to_string(), v.as_str())))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a new `txt_record::Iter` over the records keys.
|
|
||||||
pub fn keys<'a>(&'a self) -> Box<dyn Iterator<Item = String> + 'a> {
|
|
||||||
Box::new(self.0.keys().map(|k| k.to_string()))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a new `txt_record::Iter` over the records values.
|
|
||||||
pub fn values<'a>(&'a self) -> Box<dyn Iterator<Item = &'a str> + 'a> {
|
|
||||||
Box::new(self.0.values().map(|v| v.as_str()))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a new `HashMap` with this record's keys and values.
|
|
||||||
pub fn to_map(&self) -> HashMap<String, String> {
|
|
||||||
self.0.clone()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<HashMap<String, String>> for AvahiTxtRecord {
|
|
||||||
fn from(map: HashMap<String, String>) -> AvahiTxtRecord {
|
|
||||||
Self(map)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,10 @@ impl BonjourTxtRecord {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the value at the specified key or `None` if no such key exists.
|
/// Returns the value at the specified key or `None` if no such key exists.
|
||||||
pub fn get(&self, key: &str) -> Option<&str> {
|
///
|
||||||
|
/// This function returns a owned `String` because there are no guarantees that the
|
||||||
|
/// implementation provides access to the underlying value pointer.
|
||||||
|
pub fn get(&self, key: &str) -> Option<String> {
|
||||||
let mut value_len: u8 = 0;
|
let mut value_len: u8 = 0;
|
||||||
|
|
||||||
let value_raw = unsafe {
|
let value_raw = unsafe {
|
||||||
@ -42,7 +45,7 @@ impl BonjourTxtRecord {
|
|||||||
if value_raw.is_null() {
|
if value_raw.is_null() {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(unsafe { c_str::raw_to_str(value_raw as *const c_char) })
|
Some(unsafe { c_str::raw_to_str(value_raw as *const c_char).to_string() })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,13 +70,8 @@ impl BonjourTxtRecord {
|
|||||||
self.0.get_count() as usize
|
self.0.get_count() as usize
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if there are no entries in the record.
|
|
||||||
pub fn is_empty(&self) -> bool {
|
|
||||||
self.len() == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a new `txt_record::Iter` for iterating over the record as you would a `HashMap`.
|
/// Returns a new `txt_record::Iter` for iterating over the record as you would a `HashMap`.
|
||||||
pub fn iter<'a>(&'a self) -> Box<dyn Iterator<Item = (String, &'a str)> + 'a> {
|
pub fn iter<'a>(&'a self) -> Box<dyn Iterator<Item = (String, String)> + 'a> {
|
||||||
Box::new(Iter::new(self))
|
Box::new(Iter::new(self))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,48 +81,9 @@ impl BonjourTxtRecord {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a new `txt_record::Iter` over the records values.
|
/// Returns a new `txt_record::Iter` over the records values.
|
||||||
pub fn values<'a>(&'a self) -> Box<dyn Iterator<Item = &'a str> + 'a> {
|
pub fn values<'a>(&'a self) -> Box<dyn Iterator<Item = String> + 'a> {
|
||||||
Box::new(Values(Iter::new(self)))
|
Box::new(Values(Iter::new(self)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a new `HashMap` with this record's keys and values.
|
|
||||||
pub fn to_map(&self) -> HashMap<String, String> {
|
|
||||||
let mut m = HashMap::new();
|
|
||||||
for (key, value) in self.iter() {
|
|
||||||
m.insert(key, value.to_string());
|
|
||||||
}
|
|
||||||
m
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<HashMap<String, String>> for BonjourTxtRecord {
|
|
||||||
fn from(map: HashMap<String, String>) -> BonjourTxtRecord {
|
|
||||||
let mut record = BonjourTxtRecord::new();
|
|
||||||
for (key, value) in map {
|
|
||||||
record.insert(&key, &value).unwrap();
|
|
||||||
}
|
|
||||||
record
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Clone for BonjourTxtRecord {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
self.to_map().into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialEq for BonjourTxtRecord {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
self.to_map() == other.to_map()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Eq for BonjourTxtRecord {}
|
|
||||||
|
|
||||||
impl Default for BonjourTxtRecord {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::new()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An `Iterator` that allows iteration over a [`BonjourTxtRecord`] similar to a `HashMap`.
|
/// An `Iterator` that allows iteration over a [`BonjourTxtRecord`] similar to a `HashMap`.
|
||||||
@ -140,7 +99,7 @@ impl Iter<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Iterator for Iter<'a> {
|
impl<'a> Iterator for Iter<'a> {
|
||||||
type Item = (String, &'a str);
|
type Item = (String, String);
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
if self.index == self.record.len() {
|
if self.index == self.record.len() {
|
||||||
@ -170,7 +129,7 @@ impl<'a> Iterator for Iter<'a> {
|
|||||||
.trim_matches(char::from(0))
|
.trim_matches(char::from(0))
|
||||||
.to_string();
|
.to_string();
|
||||||
|
|
||||||
let value = unsafe { c_str::raw_to_str(value as *const c_char) };
|
let value = unsafe { c_str::raw_to_str(value as *const c_char).to_string() };
|
||||||
|
|
||||||
self.index += 1;
|
self.index += 1;
|
||||||
|
|
||||||
@ -193,7 +152,7 @@ impl Iterator for Keys<'_> {
|
|||||||
pub struct Values<'a>(Iter<'a>);
|
pub struct Values<'a>(Iter<'a>);
|
||||||
|
|
||||||
impl<'a> Iterator for Values<'a> {
|
impl<'a> Iterator for Values<'a> {
|
||||||
type Item = &'a str;
|
type Item = String;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
self.0.next().map(|e| e.1)
|
self.0.next().map(|e| e.1)
|
||||||
|
@ -1,110 +1,110 @@
|
|||||||
use crate::TxtRecord;
|
// use crate::TxtRecord;
|
||||||
use std::collections::HashMap;
|
// use std::collections::HashMap;
|
||||||
|
//
|
||||||
#[test]
|
// #[test]
|
||||||
fn insert_get_success() {
|
// fn insert_get_success() {
|
||||||
super::setup();
|
// super::setup();
|
||||||
let mut record = TxtRecord::new();
|
// let mut record = TxtRecord::new();
|
||||||
record.insert("foo", "bar").unwrap();
|
// record.insert("foo", "bar").unwrap();
|
||||||
assert_eq!(&record["foo"], "bar");
|
// assert_eq!(&record["foo"], "bar");
|
||||||
assert_eq!(record.get("baz"), None);
|
// assert_eq!(record.get("baz"), None);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
#[test]
|
// #[test]
|
||||||
fn remove_success() {
|
// fn remove_success() {
|
||||||
super::setup();
|
// super::setup();
|
||||||
let mut record = TxtRecord::new();
|
// let mut record = TxtRecord::new();
|
||||||
record.insert("foo", "bar").unwrap();
|
// record.insert("foo", "bar").unwrap();
|
||||||
record.remove("foo").unwrap();
|
// record.remove("foo").unwrap();
|
||||||
assert!(record.get("foo").is_none());
|
// assert!(record.get("foo").is_none());
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
#[test]
|
// #[test]
|
||||||
fn contains_key_success() {
|
// fn contains_key_success() {
|
||||||
super::setup();
|
// super::setup();
|
||||||
let mut record = TxtRecord::new();
|
// let mut record = TxtRecord::new();
|
||||||
record.insert("foo", "bar").unwrap();
|
// record.insert("foo", "bar").unwrap();
|
||||||
assert!(record.contains_key("foo"));
|
// assert!(record.contains_key("foo"));
|
||||||
assert!(!record.contains_key("baz"));
|
// assert!(!record.contains_key("baz"));
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
#[test]
|
// #[test]
|
||||||
fn len_success() {
|
// fn len_success() {
|
||||||
super::setup();
|
// super::setup();
|
||||||
let mut record = TxtRecord::new();
|
// let mut record = TxtRecord::new();
|
||||||
record.insert("foo", "bar").unwrap();
|
// record.insert("foo", "bar").unwrap();
|
||||||
assert_eq!(record.len(), 1);
|
// assert_eq!(record.len(), 1);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
#[test]
|
// #[test]
|
||||||
#[ignore]
|
// #[ignore]
|
||||||
fn iter_success() {
|
// fn iter_success() {
|
||||||
super::setup();
|
// super::setup();
|
||||||
|
//
|
||||||
debug!("iter_success()");
|
// debug!("iter_success()");
|
||||||
|
//
|
||||||
let mut record = TxtRecord::new();
|
// let mut record = TxtRecord::new();
|
||||||
record.insert("foo", "bar").unwrap();
|
// record.insert("foo", "bar").unwrap();
|
||||||
record.insert("baz", "qux").unwrap();
|
// record.insert("baz", "qux").unwrap();
|
||||||
record.insert("hello", "world").unwrap();
|
// record.insert("hello", "world").unwrap();
|
||||||
|
//
|
||||||
for (key, value) in record.iter() {
|
// for (key, value) in record.iter() {
|
||||||
debug!("({:?}, {:?})", key, value);
|
// debug!("({:?}, {:?})", key, value);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
#[test]
|
// #[test]
|
||||||
#[ignore]
|
// #[ignore]
|
||||||
fn keys_success() {
|
// fn keys_success() {
|
||||||
super::setup();
|
// super::setup();
|
||||||
|
//
|
||||||
debug!("keys_success()");
|
// debug!("keys_success()");
|
||||||
|
//
|
||||||
let mut record = TxtRecord::new();
|
// let mut record = TxtRecord::new();
|
||||||
record.insert("foo", "bar").unwrap();
|
// record.insert("foo", "bar").unwrap();
|
||||||
record.insert("baz", "qux").unwrap();
|
// record.insert("baz", "qux").unwrap();
|
||||||
record.insert("hello", "world").unwrap();
|
// record.insert("hello", "world").unwrap();
|
||||||
|
//
|
||||||
for key in record.keys() {
|
// for key in record.keys() {
|
||||||
debug!("{:?}", key);
|
// debug!("{:?}", key);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
#[test]
|
// #[test]
|
||||||
#[ignore]
|
// #[ignore]
|
||||||
fn values_success() {
|
// fn values_success() {
|
||||||
super::setup();
|
// super::setup();
|
||||||
|
//
|
||||||
debug!("values_success()");
|
// debug!("values_success()");
|
||||||
|
//
|
||||||
let mut record = TxtRecord::new();
|
// let mut record = TxtRecord::new();
|
||||||
record.insert("foo", "bar").unwrap();
|
// record.insert("foo", "bar").unwrap();
|
||||||
record.insert("baz", "qux").unwrap();
|
// record.insert("baz", "qux").unwrap();
|
||||||
record.insert("hello", "world").unwrap();
|
// record.insert("hello", "world").unwrap();
|
||||||
|
//
|
||||||
for value in record.values() {
|
// for value in record.values() {
|
||||||
debug!("{:?}", value);
|
// debug!("{:?}", value);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
#[test]
|
// #[test]
|
||||||
fn from_hashmap_success() {
|
// fn from_hashmap_success() {
|
||||||
super::setup();
|
// super::setup();
|
||||||
|
//
|
||||||
let mut map = HashMap::new();
|
// let mut map = HashMap::new();
|
||||||
map.insert("foo", "bar");
|
// map.insert("foo", "bar");
|
||||||
|
//
|
||||||
let record: TxtRecord = map.into();
|
// let record: TxtRecord = map.into();
|
||||||
|
//
|
||||||
assert_eq!(&record["foo"], "bar");
|
// assert_eq!(&record["foo"], "bar");
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
#[test]
|
// #[test]
|
||||||
fn clone_success() {
|
// fn clone_success() {
|
||||||
super::setup();
|
// super::setup();
|
||||||
|
//
|
||||||
let mut record = TxtRecord::new();
|
// let mut record = TxtRecord::new();
|
||||||
record.insert("foo", "bar").unwrap();
|
// record.insert("foo", "bar").unwrap();
|
||||||
|
//
|
||||||
assert_eq!(record.clone(), record);
|
// assert_eq!(record.clone(), record);
|
||||||
}
|
// }
|
||||||
|
@ -2,13 +2,14 @@
|
|||||||
|
|
||||||
use crate::TxtRecord;
|
use crate::TxtRecord;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::ops::Index;
|
|
||||||
|
|
||||||
impl Index<&str> for TxtRecord {
|
impl From<HashMap<String, String>> for TxtRecord {
|
||||||
type Output = str;
|
fn from(map: HashMap<String, String>) -> TxtRecord {
|
||||||
|
let mut record = TxtRecord::new();
|
||||||
fn index(&self, key: &str) -> &Self::Output {
|
for (key, value) in map {
|
||||||
self.get(key).unwrap()
|
record.insert(&key, &value).unwrap();
|
||||||
|
}
|
||||||
|
record
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -20,3 +21,39 @@ impl From<HashMap<&str, &str>> for TxtRecord {
|
|||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TxtRecord {
|
||||||
|
/// Returns true if there are no entries in the record.
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.len() == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a new `HashMap` with this record's keys and values.
|
||||||
|
pub fn to_map(&self) -> HashMap<String, String> {
|
||||||
|
let mut m = HashMap::new();
|
||||||
|
for (key, value) in self.iter() {
|
||||||
|
m.insert(key, value.to_string());
|
||||||
|
}
|
||||||
|
m
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Clone for TxtRecord {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
self.to_map().into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for TxtRecord {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.to_map() == other.to_map()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for TxtRecord {}
|
||||||
|
|
||||||
|
impl Default for TxtRecord {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user