more work on TxtRecord
Signed-off-by: Walker Crouse <walker.crouse@coop.co.uk>
This commit is contained in:
parent
426851e66a
commit
0881c308bd
7
Cargo.lock
generated
7
Cargo.lock
generated
@ -288,6 +288,12 @@ dependencies = [
|
|||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "maplit"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
version = "2.3.3"
|
version = "2.3.3"
|
||||||
@ -510,6 +516,7 @@ dependencies = [
|
|||||||
"env_logger",
|
"env_logger",
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
|
"maplit",
|
||||||
"serde",
|
"serde",
|
||||||
"zeroconf-macros",
|
"zeroconf-macros",
|
||||||
]
|
]
|
||||||
|
@ -31,6 +31,7 @@ use std::any::Any;
|
|||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use zeroconf::{MdnsService, ServiceRegistration};
|
use zeroconf::{MdnsService, ServiceRegistration};
|
||||||
|
use zeroconf::prelude::*;
|
||||||
|
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug)]
|
||||||
pub struct Context {
|
pub struct Context {
|
||||||
|
@ -2,6 +2,7 @@ use std::any::Any;
|
|||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use zeroconf::{MdnsService, ServiceRegistration, TxtRecord};
|
use zeroconf::{MdnsService, ServiceRegistration, TxtRecord};
|
||||||
|
use zeroconf::prelude::*;
|
||||||
|
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug)]
|
||||||
pub struct Context {
|
pub struct Context {
|
||||||
|
@ -18,6 +18,7 @@ derive-getters = "0.2.0"
|
|||||||
derive_builder = "0.9.0"
|
derive_builder = "0.9.0"
|
||||||
derive-new = "0.5.8"
|
derive-new = "0.5.8"
|
||||||
log = "0.4.11"
|
log = "0.4.11"
|
||||||
|
maplit = "1.0.2"
|
||||||
libc = "0.2.77"
|
libc = "0.2.77"
|
||||||
zeroconf-macros = { path = "../zeroconf-macros", version = "0.1.1" }
|
zeroconf-macros = { path = "../zeroconf-macros", version = "0.1.1" }
|
||||||
|
|
||||||
|
@ -21,50 +21,51 @@
|
|||||||
//! use std::sync::{Arc, Mutex};
|
//! use std::sync::{Arc, Mutex};
|
||||||
//! use std::time::Duration;
|
//! use std::time::Duration;
|
||||||
//! use zeroconf::{MdnsService, ServiceRegistration, TxtRecord};
|
//! use zeroconf::{MdnsService, ServiceRegistration, TxtRecord};
|
||||||
//!
|
//! use zeroconf::prelude::*;
|
||||||
|
//!
|
||||||
//! #[derive(Default, Debug)]
|
//! #[derive(Default, Debug)]
|
||||||
//! pub struct Context {
|
//! pub struct Context {
|
||||||
//! service_name: String,
|
//! service_name: String,
|
||||||
//! }
|
//! }
|
||||||
//!
|
//!
|
||||||
//! fn main() {
|
//! fn main() {
|
||||||
//! let mut service = MdnsService::new("_http._tcp", 8080);
|
//! let mut service = MdnsService::new("_http._tcp", 8080);
|
||||||
//! let mut txt_record = TxtRecord::new();
|
//! let mut txt_record = TxtRecord::new();
|
||||||
//! let context: Arc<Mutex<Context>> = Arc::default();
|
//! let context: Arc<Mutex<Context>> = Arc::default();
|
||||||
//!
|
//!
|
||||||
//! txt_record.insert("foo", "bar").unwrap();
|
//! txt_record.insert("foo", "bar").unwrap();
|
||||||
//!
|
//!
|
||||||
//! service.set_registered_callback(Box::new(on_service_registered));
|
//! service.set_registered_callback(Box::new(on_service_registered));
|
||||||
//! service.set_context(Box::new(context));
|
//! service.set_context(Box::new(context));
|
||||||
//! service.set_txt_record(txt_record);
|
//! service.set_txt_record(txt_record);
|
||||||
//!
|
//!
|
||||||
//! let event_loop = service.register().unwrap();
|
//! let event_loop = service.register().unwrap();
|
||||||
//!
|
//!
|
||||||
//! loop {
|
//! loop {
|
||||||
//! // calling `poll()` will keep this service alive
|
//! // calling `poll()` will keep this service alive
|
||||||
//! event_loop.poll(Duration::from_secs(0)).unwrap();
|
//! event_loop.poll(Duration::from_secs(0)).unwrap();
|
||||||
//! }
|
//! }
|
||||||
//! }
|
//! }
|
||||||
//!
|
//!
|
||||||
//! fn on_service_registered(
|
//! fn on_service_registered(
|
||||||
//! result: zeroconf::Result<ServiceRegistration>,
|
//! result: zeroconf::Result<ServiceRegistration>,
|
||||||
//! context: Option<Arc<dyn Any>>,
|
//! context: Option<Arc<dyn Any>>,
|
||||||
//! ) {
|
//! ) {
|
||||||
//! let service = result.unwrap();
|
//! let service = result.unwrap();
|
||||||
//!
|
//!
|
||||||
//! println!("Service registered: {:?}", service);
|
//! println!("Service registered: {:?}", service);
|
||||||
//!
|
//!
|
||||||
//! let context = context
|
//! let context = context
|
||||||
//! .as_ref()
|
//! .as_ref()
|
||||||
//! .unwrap()
|
//! .unwrap()
|
||||||
//! .downcast_ref::<Arc<Mutex<Context>>>()
|
//! .downcast_ref::<Arc<Mutex<Context>>>()
|
||||||
//! .unwrap()
|
//! .unwrap()
|
||||||
//! .clone();
|
//! .clone();
|
||||||
//!
|
//!
|
||||||
//! context.lock().unwrap().service_name = service.name().clone();
|
//! context.lock().unwrap().service_name = service.name().clone();
|
||||||
//!
|
//!
|
||||||
//! println!("Context: {:?}", context);
|
//! println!("Context: {:?}", context);
|
||||||
//!
|
//!
|
||||||
//! // ...
|
//! // ...
|
||||||
//! }
|
//! }
|
||||||
//! ```
|
//! ```
|
||||||
@ -124,6 +125,10 @@ extern crate log;
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate derive_new;
|
extern crate derive_new;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[macro_use]
|
||||||
|
extern crate maplit;
|
||||||
|
|
||||||
mod discovery;
|
mod discovery;
|
||||||
mod registration;
|
mod registration;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
@ -136,6 +141,7 @@ mod txt_record;
|
|||||||
pub mod builder;
|
pub mod builder;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod ffi;
|
pub mod ffi;
|
||||||
|
pub mod prelude;
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
pub mod linux;
|
pub mod linux;
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
use crate::ffi::c_str;
|
use crate::ffi::c_str;
|
||||||
use avahi_sys::{
|
use avahi_sys::{
|
||||||
avahi_free, avahi_string_list_add_pair, avahi_string_list_copy, avahi_string_list_equal,
|
avahi_free, avahi_string_list_add_pair, avahi_string_list_copy, avahi_string_list_equal,
|
||||||
avahi_string_list_find, avahi_string_list_free, avahi_string_list_get_pair,
|
avahi_string_list_find, avahi_string_list_free, avahi_string_list_get_next,
|
||||||
avahi_string_list_length, avahi_string_list_new, avahi_string_list_to_string, AvahiStringList,
|
avahi_string_list_get_pair, 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::marker::PhantomData;
|
||||||
@ -29,6 +30,10 @@ impl ManagedAvahiStringList {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn head(&mut self) -> AvahiStringListNode {
|
||||||
|
AvahiStringListNode::new(self.0)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn length(&self) -> u32 {
|
pub fn length(&self) -> u32 {
|
||||||
unsafe { avahi_string_list_length(self.0) }
|
unsafe { avahi_string_list_length(self.0) }
|
||||||
}
|
}
|
||||||
@ -71,6 +76,15 @@ pub struct AvahiStringListNode<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> AvahiStringListNode<'a> {
|
impl<'a> AvahiStringListNode<'a> {
|
||||||
|
pub fn next(self) -> Option<AvahiStringListNode<'a>> {
|
||||||
|
let next = unsafe { avahi_string_list_get_next(self.list) };
|
||||||
|
if next.is_null() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(AvahiStringListNode::new(next))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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();
|
||||||
@ -82,10 +96,6 @@ impl<'a> AvahiStringListNode<'a> {
|
|||||||
|
|
||||||
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)]
|
||||||
@ -125,6 +135,7 @@ impl Drop for AvahiString {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn add_get_pair_success() {
|
fn add_get_pair_success() {
|
||||||
@ -196,26 +207,6 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn length_success() {
|
fn length_success() {
|
||||||
crate::tests::setup();
|
crate::tests::setup();
|
||||||
@ -269,4 +260,49 @@ mod tests {
|
|||||||
assert_eq!(list.clone(), list);
|
assert_eq!(list.clone(), list);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn iterate_success() {
|
||||||
|
crate::tests::setup();
|
||||||
|
|
||||||
|
let mut list = ManagedAvahiStringList::new();
|
||||||
|
let key1 = c_string!("foo");
|
||||||
|
let value1 = c_string!("bar");
|
||||||
|
let key2 = c_string!("hello");
|
||||||
|
let value2 = c_string!("world");
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
list.add_pair(
|
||||||
|
key1.as_ptr() as *const c_char,
|
||||||
|
value1.as_ptr() as *const c_char,
|
||||||
|
);
|
||||||
|
|
||||||
|
list.add_pair(
|
||||||
|
key2.as_ptr() as *const c_char,
|
||||||
|
value2.as_ptr() as *const c_char,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut node = Some(list.head());
|
||||||
|
let mut map = HashMap::new();
|
||||||
|
|
||||||
|
while node.is_some() {
|
||||||
|
let mut n = node.unwrap();
|
||||||
|
let pair = n.get_pair();
|
||||||
|
|
||||||
|
map.insert(
|
||||||
|
pair.key().as_str().unwrap().to_string(),
|
||||||
|
pair.value().as_str().unwrap().to_string(),
|
||||||
|
);
|
||||||
|
|
||||||
|
node = n.next();
|
||||||
|
}
|
||||||
|
|
||||||
|
let expected: HashMap<String, String> = hashmap! {
|
||||||
|
"foo".to_string() => "bar".to_string(),
|
||||||
|
"hello".to_string() => "world".to_string()
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(map, expected);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,19 +1,24 @@
|
|||||||
use super::string_list::ManagedAvahiStringList;
|
use super::string_list::{AvahiStringListNode, ManagedAvahiStringList};
|
||||||
|
use crate::txt_record::TTxtRecord;
|
||||||
use crate::Result;
|
use crate::Result;
|
||||||
use libc::c_char;
|
use libc::c_char;
|
||||||
use std::cell::UnsafeCell;
|
use std::cell::UnsafeCell;
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug)]
|
||||||
pub struct AvahiTxtRecord(UnsafeCell<ManagedAvahiStringList>);
|
pub struct AvahiTxtRecord(UnsafeCell<ManagedAvahiStringList>);
|
||||||
|
|
||||||
impl AvahiTxtRecord {
|
impl AvahiTxtRecord {
|
||||||
pub fn new() -> Self {
|
fn inner(&self) -> &mut ManagedAvahiStringList {
|
||||||
Self::default()
|
unsafe { &mut *self.0.get() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TTxtRecord for AvahiTxtRecord {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self(UnsafeCell::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Inserts the specified value at the specified key.
|
fn insert(&mut self, key: &str, value: &str) -> Result<()> {
|
||||||
pub fn insert(&mut self, key: &str, value: &str) -> Result<()> {
|
|
||||||
unsafe {
|
unsafe {
|
||||||
self.inner().add_pair(
|
self.inner().add_pair(
|
||||||
c_string!(key).as_ptr() as *const c_char,
|
c_string!(key).as_ptr() as *const c_char,
|
||||||
@ -23,11 +28,7 @@ impl AvahiTxtRecord {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the value at the specified key or `None` if no such key exists.
|
fn get(&self, key: &str) -> Option<String> {
|
||||||
///
|
|
||||||
/// 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 {
|
unsafe {
|
||||||
self.inner()
|
self.inner()
|
||||||
.find(c_string!(key).as_ptr() as *const c_char)?
|
.find(c_string!(key).as_ptr() as *const c_char)?
|
||||||
@ -38,47 +39,96 @@ impl AvahiTxtRecord {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Removes the value at the specified key. Returns `Err` if no such key exists.
|
fn remove(&mut self, key: &str) -> Result<()> {
|
||||||
pub fn remove(&mut self, key: &str) -> Result<()> {
|
let mut list = ManagedAvahiStringList::new();
|
||||||
unsafe {
|
let mut map = self.to_map();
|
||||||
match self.inner().find(c_string!(key).as_ptr() as *const c_char) {
|
|
||||||
None => Err("no such key".into()),
|
map.remove(key);
|
||||||
Some(node) => {
|
|
||||||
node.remove();
|
for (key, value) in map {
|
||||||
Ok(())
|
unsafe {
|
||||||
}
|
list.add_pair(
|
||||||
|
c_string!(key).as_ptr() as *const c_char,
|
||||||
|
c_string!(value).as_ptr() as *const c_char,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.0 = UnsafeCell::new(list);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn contains_key(&self, key: &str) -> bool {
|
||||||
|
unsafe {
|
||||||
|
self.inner()
|
||||||
|
.find(c_string!(key).as_ptr() as *const c_char)
|
||||||
|
.is_some()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if the TXT record contains the specified key.
|
fn len(&self) -> usize {
|
||||||
pub fn contains_key(&self, key: &str) -> bool {
|
|
||||||
self.inner()
|
|
||||||
.find(c_string!(key).as_ptr() as *const c_char)
|
|
||||||
.is_some()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the amount of entries in the TXT record.
|
|
||||||
pub fn len(&self) -> usize {
|
|
||||||
self.inner().length() as usize
|
self.inner().length() as usize
|
||||||
}
|
}
|
||||||
|
|
||||||
// /// Returns a new `txt_record::Iter` for iterating over the record as you would a `HashMap`.
|
fn iter<'a>(&'a self) -> Box<dyn Iterator<Item = (String, String)> + 'a> {
|
||||||
// pub fn iter<'a>(&'a self) -> Box<dyn Iterator<Item = (String, String)> + 'a> {
|
Box::new(Iter::new(self.inner().head()))
|
||||||
// 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)))
|
|
||||||
// }
|
|
||||||
|
|
||||||
fn inner(&self) -> &mut ManagedAvahiStringList {
|
fn keys<'a>(&'a self) -> Box<dyn Iterator<Item = String> + 'a> {
|
||||||
&mut *self.0.get()
|
Box::new(Keys(Iter::new(self.inner().head())))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn values<'a>(&'a self) -> Box<dyn Iterator<Item = String> + 'a> {
|
||||||
|
Box::new(Values(Iter::new(self.inner().head())))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Iter<'a> {
|
||||||
|
node: Option<AvahiStringListNode<'a>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Iter<'a> {
|
||||||
|
pub fn new(node: AvahiStringListNode<'a>) -> Self {
|
||||||
|
Self { node: Some(node) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Iterator for Iter<'_> {
|
||||||
|
type Item = (String, String);
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
if self.node.is_none() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut n = self.node.take().unwrap();
|
||||||
|
let pair = n.get_pair();
|
||||||
|
self.node = n.next();
|
||||||
|
|
||||||
|
Some((
|
||||||
|
pair.key().as_str().unwrap().to_string(),
|
||||||
|
pair.value().as_str().unwrap().to_string(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Keys<'a>(Iter<'a>);
|
||||||
|
|
||||||
|
impl Iterator for Keys<'_> {
|
||||||
|
type Item = String;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
self.0.next().map(|e| e.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Values<'a>(Iter<'a>);
|
||||||
|
|
||||||
|
impl Iterator for Values<'_> {
|
||||||
|
type Item = String;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
self.0.next().map(|e| e.1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use super::txt_record_ref::ManagedTXTRecordRef;
|
use super::txt_record_ref::ManagedTXTRecordRef;
|
||||||
use crate::ffi::c_str;
|
use crate::ffi::c_str;
|
||||||
|
use crate::txt_record::TTxtRecord;
|
||||||
use crate::Result;
|
use crate::Result;
|
||||||
use libc::{c_char, c_void};
|
use libc::{c_char, c_void};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
@ -10,14 +11,12 @@ use std::{mem, ptr};
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct BonjourTxtRecord(pub(crate) ManagedTXTRecordRef);
|
pub struct BonjourTxtRecord(pub(crate) ManagedTXTRecordRef);
|
||||||
|
|
||||||
impl BonjourTxtRecord {
|
impl TTxtRecord for BonjourTxtRecord {
|
||||||
/// Constructs a new TXT recoord
|
fn new() -> Self {
|
||||||
pub fn new() -> Self {
|
|
||||||
Self(ManagedTXTRecordRef::new())
|
Self(ManagedTXTRecordRef::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Inserts the specified value at the specified key.
|
fn insert(&mut self, key: &str, value: &str) -> Result<()> {
|
||||||
pub fn insert(&mut self, key: &str, value: &str) -> Result<()> {
|
|
||||||
let key = c_string!(key);
|
let key = c_string!(key);
|
||||||
let value = c_string!(value);
|
let value = c_string!(value);
|
||||||
let value_size = mem::size_of_val(&value) as u8;
|
let value_size = mem::size_of_val(&value) as u8;
|
||||||
@ -30,11 +29,7 @@ impl BonjourTxtRecord {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the value at the specified key or `None` if no such key exists.
|
fn get(&self, key: &str) -> Option<String> {
|
||||||
///
|
|
||||||
/// 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 {
|
||||||
@ -49,39 +44,33 @@ impl BonjourTxtRecord {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Removes the value at the specified key. Returns `Err` if no such key exists.
|
fn remove(&mut self, key: &str) -> Result<()> {
|
||||||
pub fn remove(&mut self, key: &str) -> Result<()> {
|
|
||||||
unsafe {
|
unsafe {
|
||||||
self.0
|
self.0
|
||||||
.remove_value(c_string!(key).as_ptr() as *const c_char)
|
.remove_value(c_string!(key).as_ptr() as *const c_char)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if the TXT record contains the specified key.
|
fn contains_key(&self, key: &str) -> bool {
|
||||||
pub fn contains_key(&self, key: &str) -> bool {
|
|
||||||
unsafe {
|
unsafe {
|
||||||
self.0
|
self.0
|
||||||
.contains_key(c_string!(key).as_ptr() as *const c_char)
|
.contains_key(c_string!(key).as_ptr() as *const c_char)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the amount of entries in the TXT record.
|
fn len(&self) -> usize {
|
||||||
pub fn len(&self) -> usize {
|
|
||||||
self.0.get_count() as usize
|
self.0.get_count() as usize
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a new `txt_record::Iter` for iterating over the record as you would a `HashMap`.
|
fn iter<'a>(&'a self) -> Box<dyn Iterator<Item = (String, String)> + 'a> {
|
||||||
pub fn iter<'a>(&'a self) -> Box<dyn Iterator<Item = (String, String)> + 'a> {
|
|
||||||
Box::new(Iter::new(self))
|
Box::new(Iter::new(self))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a new `txt_record::Iter` over the records keys.
|
fn keys<'a>(&'a self) -> Box<dyn Iterator<Item = String> + 'a> {
|
||||||
pub fn keys<'a>(&'a self) -> Box<dyn Iterator<Item = String> + 'a> {
|
|
||||||
Box::new(Keys(Iter::new(self)))
|
Box::new(Keys(Iter::new(self)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a new `txt_record::Iter` over the records values.
|
fn values<'a>(&'a self) -> Box<dyn Iterator<Item = String> + '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)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -98,7 +87,7 @@ impl Iter<'_> {
|
|||||||
const KEY_LEN: u16 = 256;
|
const KEY_LEN: u16 = 256;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Iterator for Iter<'a> {
|
impl Iterator for Iter<'_> {
|
||||||
type Item = (String, String);
|
type Item = (String, String);
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
1
zeroconf/src/prelude.rs
Normal file
1
zeroconf/src/prelude.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
pub use crate::txt_record::TTxtRecord;
|
@ -1,110 +1,111 @@
|
|||||||
// use crate::TxtRecord;
|
use crate::prelude::*;
|
||||||
// use std::collections::HashMap;
|
use crate::TxtRecord;
|
||||||
//
|
use std::collections::HashMap;
|
||||||
// #[test]
|
|
||||||
// fn insert_get_success() {
|
#[test]
|
||||||
// super::setup();
|
fn insert_get_success() {
|
||||||
// let mut record = TxtRecord::new();
|
super::setup();
|
||||||
// record.insert("foo", "bar").unwrap();
|
let mut record = TxtRecord::new();
|
||||||
// assert_eq!(&record["foo"], "bar");
|
record.insert("foo", "bar").unwrap();
|
||||||
// assert_eq!(record.get("baz"), None);
|
assert_eq!(record.get("foo").unwrap(), "bar");
|
||||||
// }
|
assert_eq!(record.get("baz"), None);
|
||||||
//
|
}
|
||||||
// #[test]
|
|
||||||
// fn remove_success() {
|
#[test]
|
||||||
// super::setup();
|
fn remove_success() {
|
||||||
// let mut record = TxtRecord::new();
|
super::setup();
|
||||||
// record.insert("foo", "bar").unwrap();
|
let mut record = TxtRecord::new();
|
||||||
// record.remove("foo").unwrap();
|
record.insert("foo", "bar").unwrap();
|
||||||
// assert!(record.get("foo").is_none());
|
record.remove("foo").unwrap();
|
||||||
// }
|
assert!(record.get("foo").is_none());
|
||||||
//
|
}
|
||||||
// #[test]
|
|
||||||
// fn contains_key_success() {
|
#[test]
|
||||||
// super::setup();
|
fn contains_key_success() {
|
||||||
// let mut record = TxtRecord::new();
|
super::setup();
|
||||||
// record.insert("foo", "bar").unwrap();
|
let mut record = TxtRecord::new();
|
||||||
// assert!(record.contains_key("foo"));
|
record.insert("foo", "bar").unwrap();
|
||||||
// assert!(!record.contains_key("baz"));
|
assert!(record.contains_key("foo"));
|
||||||
// }
|
assert!(!record.contains_key("baz"));
|
||||||
//
|
}
|
||||||
// #[test]
|
|
||||||
// fn len_success() {
|
#[test]
|
||||||
// super::setup();
|
fn len_success() {
|
||||||
// let mut record = TxtRecord::new();
|
super::setup();
|
||||||
// record.insert("foo", "bar").unwrap();
|
let mut record = TxtRecord::new();
|
||||||
// assert_eq!(record.len(), 1);
|
record.insert("foo", "bar").unwrap();
|
||||||
// }
|
assert_eq!(record.len(), 1);
|
||||||
//
|
}
|
||||||
// #[test]
|
|
||||||
// #[ignore]
|
#[test]
|
||||||
// fn iter_success() {
|
#[ignore]
|
||||||
// super::setup();
|
fn iter_success() {
|
||||||
//
|
super::setup();
|
||||||
// debug!("iter_success()");
|
|
||||||
//
|
debug!("iter_success()");
|
||||||
// let mut record = TxtRecord::new();
|
|
||||||
// record.insert("foo", "bar").unwrap();
|
let mut record = TxtRecord::new();
|
||||||
// record.insert("baz", "qux").unwrap();
|
record.insert("foo", "bar").unwrap();
|
||||||
// record.insert("hello", "world").unwrap();
|
record.insert("baz", "qux").unwrap();
|
||||||
//
|
record.insert("hello", "world").unwrap();
|
||||||
// for (key, value) in record.iter() {
|
|
||||||
// debug!("({:?}, {:?})", key, value);
|
for (key, value) in record.iter() {
|
||||||
// }
|
debug!("({:?}, {:?})", key, value);
|
||||||
// }
|
}
|
||||||
//
|
}
|
||||||
// #[test]
|
|
||||||
// #[ignore]
|
#[test]
|
||||||
// fn keys_success() {
|
#[ignore]
|
||||||
// super::setup();
|
fn keys_success() {
|
||||||
//
|
super::setup();
|
||||||
// debug!("keys_success()");
|
|
||||||
//
|
debug!("keys_success()");
|
||||||
// let mut record = TxtRecord::new();
|
|
||||||
// record.insert("foo", "bar").unwrap();
|
let mut record = TxtRecord::new();
|
||||||
// record.insert("baz", "qux").unwrap();
|
record.insert("foo", "bar").unwrap();
|
||||||
// record.insert("hello", "world").unwrap();
|
record.insert("baz", "qux").unwrap();
|
||||||
//
|
record.insert("hello", "world").unwrap();
|
||||||
// for key in record.keys() {
|
|
||||||
// debug!("{:?}", key);
|
for key in record.keys() {
|
||||||
// }
|
debug!("{:?}", key);
|
||||||
// }
|
}
|
||||||
//
|
}
|
||||||
// #[test]
|
|
||||||
// #[ignore]
|
#[test]
|
||||||
// fn values_success() {
|
#[ignore]
|
||||||
// super::setup();
|
fn values_success() {
|
||||||
//
|
super::setup();
|
||||||
// debug!("values_success()");
|
|
||||||
//
|
debug!("values_success()");
|
||||||
// let mut record = TxtRecord::new();
|
|
||||||
// record.insert("foo", "bar").unwrap();
|
let mut record = TxtRecord::new();
|
||||||
// record.insert("baz", "qux").unwrap();
|
record.insert("foo", "bar").unwrap();
|
||||||
// record.insert("hello", "world").unwrap();
|
record.insert("baz", "qux").unwrap();
|
||||||
//
|
record.insert("hello", "world").unwrap();
|
||||||
// for value in record.values() {
|
|
||||||
// debug!("{:?}", value);
|
for value in record.values() {
|
||||||
// }
|
debug!("{:?}", value);
|
||||||
// }
|
}
|
||||||
//
|
}
|
||||||
// #[test]
|
|
||||||
// fn from_hashmap_success() {
|
#[test]
|
||||||
// super::setup();
|
fn from_hashmap_success() {
|
||||||
//
|
super::setup();
|
||||||
// let mut map = HashMap::new();
|
|
||||||
// map.insert("foo", "bar");
|
let mut map = HashMap::new();
|
||||||
//
|
map.insert("foo", "bar");
|
||||||
// let record: TxtRecord = map.into();
|
|
||||||
//
|
let record: TxtRecord = map.into();
|
||||||
// assert_eq!(&record["foo"], "bar");
|
|
||||||
// }
|
assert_eq!(record.get("foo").unwrap(), "bar");
|
||||||
//
|
}
|
||||||
// #[test]
|
|
||||||
// fn clone_success() {
|
#[test]
|
||||||
// super::setup();
|
fn clone_success() {
|
||||||
//
|
super::setup();
|
||||||
// let mut record = TxtRecord::new();
|
|
||||||
// record.insert("foo", "bar").unwrap();
|
let mut record = TxtRecord::new();
|
||||||
//
|
record.insert("foo", "bar").unwrap();
|
||||||
// assert_eq!(record.clone(), record);
|
|
||||||
// }
|
assert_eq!(record.clone(), record);
|
||||||
|
}
|
||||||
|
@ -1,8 +1,54 @@
|
|||||||
//! TxtRecord utilities common to all platforms
|
//! TxtRecord utilities common to all platforms
|
||||||
|
|
||||||
use crate::TxtRecord;
|
use crate::{Result, TxtRecord};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
pub trait TTxtRecord {
|
||||||
|
/// Constructs a new TXT record
|
||||||
|
fn new() -> Self;
|
||||||
|
|
||||||
|
/// Inserts the specified value at the specified key.
|
||||||
|
fn insert(&mut self, key: &str, value: &str) -> Result<()>;
|
||||||
|
|
||||||
|
/// Returns the value at the specified key or `None` if no such key exists.
|
||||||
|
///
|
||||||
|
/// This function returns a owned `String` because there are no guarantees that the
|
||||||
|
/// implementation provides access to the underlying value pointer.
|
||||||
|
fn get(&self, key: &str) -> Option<String>;
|
||||||
|
|
||||||
|
/// Removes the value at the specified key. Returns `Err` if no such key exists.
|
||||||
|
fn remove(&mut self, key: &str) -> Result<()>;
|
||||||
|
|
||||||
|
/// Returns true if the TXT record contains the specified key.
|
||||||
|
fn contains_key(&self, key: &str) -> bool;
|
||||||
|
|
||||||
|
/// Returns the amount of entries in the TXT record.
|
||||||
|
fn len(&self) -> usize;
|
||||||
|
|
||||||
|
/// Returns a new iterator for iterating over the record as you would a `HashMap`.
|
||||||
|
fn iter<'a>(&'a self) -> Box<dyn Iterator<Item = (String, String)> + 'a>;
|
||||||
|
|
||||||
|
/// Returns a new iterator over the records keys.
|
||||||
|
fn keys<'a>(&'a self) -> Box<dyn Iterator<Item = String> + 'a>;
|
||||||
|
|
||||||
|
/// Returns a new iterator over the records values.
|
||||||
|
fn values<'a>(&'a self) -> Box<dyn Iterator<Item = String> + 'a>;
|
||||||
|
|
||||||
|
/// Returns true if there are no entries in the record.
|
||||||
|
fn is_empty(&self) -> bool {
|
||||||
|
self.len() == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a new `HashMap` with this record's keys and values.
|
||||||
|
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 TxtRecord {
|
impl From<HashMap<String, String>> for TxtRecord {
|
||||||
fn from(map: HashMap<String, String>) -> TxtRecord {
|
fn from(map: HashMap<String, String>) -> TxtRecord {
|
||||||
let mut record = TxtRecord::new();
|
let mut record = TxtRecord::new();
|
||||||
@ -22,22 +68,6 @@ impl From<HashMap<&str, &str>> for TxtRecord {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
impl Clone for TxtRecord {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
self.to_map().into()
|
self.to_map().into()
|
||||||
@ -50,7 +80,7 @@ impl PartialEq for TxtRecord {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eq for TxtRecord {}
|
// impl Eq for TxtRecord {}
|
||||||
|
|
||||||
impl Default for TxtRecord {
|
impl Default for TxtRecord {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
|
Loading…
Reference in New Issue
Block a user