use std::collections::{
linked_list::{Iter, IterMut},
LinkedList,
};
use std::sync::Arc;
use crate::{Udev, UdevDevice};
pub type UdevEntryList = LinkedList<UdevEntry>;
#[repr(C)]
#[derive(Clone, Debug, Default, PartialEq)]
pub struct UdevList {
udev: Arc<Udev>,
list: UdevEntryList,
entries_cur: usize,
entries_max: usize,
unique: bool,
}
impl UdevList {
pub const fn new(udev: Arc<Udev>) -> Self {
Self {
udev,
list: LinkedList::new(),
entries_cur: 0,
entries_max: 0,
unique: true,
}
}
pub const fn create(udev: Arc<Udev>, list: UdevEntryList) -> Self {
Self {
udev,
list,
entries_cur: 0,
entries_max: 0,
unique: true,
}
}
pub fn iter(&self) -> Iter<UdevEntry> {
self.list.iter()
}
pub fn iter_mut(&mut self) -> IterMut<UdevEntry> {
self.list.iter_mut()
}
pub fn list(&self) -> &UdevEntryList {
&self.list
}
pub fn list_mut(&mut self) -> &mut UdevEntryList {
&mut self.list
}
pub fn set_list<L: Into<UdevEntryList>>(&mut self, list: L) {
self.list = list.into();
}
pub fn with_list<L: Into<UdevEntryList>>(mut self, list: L) -> Self {
self.set_list(list);
self
}
pub fn len(&self) -> usize {
self.list.len()
}
pub fn is_empty(&self) -> bool {
self.list.is_empty()
}
pub fn clear(&mut self) {
self.list.clear();
}
pub fn entry(&self) -> Option<&UdevEntry> {
self.list.front()
}
pub fn entry_mut(&mut self) -> Option<&mut UdevEntry> {
self.list.front_mut()
}
pub fn entry_by_name(&self, name: &str) -> Option<&UdevEntry> {
self.list.iter().find(|e| e.name() == name)
}
pub fn entry_by_name_mut(&mut self, name: &str) -> Option<&mut UdevEntry> {
self.list.iter_mut().find(|e| e.name() == name)
}
pub fn next_entry(&self) -> Option<&UdevEntry> {
self.list.iter().nth(self.entries_cur)
}
pub fn next_entry_mut(&mut self) -> Option<&mut UdevEntry> {
self.list.iter_mut().nth(self.entries_cur)
}
pub fn add_entry(&mut self, name: &str, value: &str) -> Option<&UdevEntry> {
if self.unique() && self.entry_by_name(name).is_some() {
let existing = self.entry_by_name_mut(name).unwrap();
log::trace!("Updating property, {name}: {} => {value}", existing.value());
existing.set_value(value);
Some(existing)
} else {
log::trace!("Adding property, {name}: {value}");
self.list
.push_back(UdevEntry::new().with_name(name).with_value(value));
self.list.back()
}
}
pub fn remove_entry(&mut self, name: &str) {
if let Some(pos) = self.list.iter().position(|e| e.name() == name) {
let mut ext = self.list.split_off(pos);
if ext.len() > 1 {
ext.pop_front();
self.list.append(&mut ext);
}
}
}
pub const fn entries_cur(&self) -> usize {
self.entries_cur
}
pub const fn entries_max(&self) -> usize {
self.entries_max
}
pub const fn unique(&self) -> bool {
self.unique
}
pub fn has_tag(&self, device: &UdevDevice) -> bool {
if self.is_empty() {
true
} else {
self.iter()
.filter(|e| device.tags_list().entry_by_name(e.name()).is_some())
.count()
!= 0
}
}
}
#[repr(C)]
#[derive(Clone, Debug, Default, PartialEq)]
pub struct UdevEntry {
name: String,
value: String,
num: i32,
}
impl UdevEntry {
pub const fn new() -> Self {
Self {
name: String::new(),
value: String::new(),
num: 0,
}
}
pub fn name(&self) -> &str {
self.name.as_str()
}
pub fn set_name<N: Into<String>>(&mut self, name: N) {
self.name = name.into();
}
pub fn with_name<N: Into<String>>(mut self, name: N) -> Self {
self.set_name(name);
self
}
pub fn value(&self) -> &str {
self.value.as_str()
}
pub fn set_value<N: Into<String>>(&mut self, value: N) {
self.value = value.into();
}
pub fn with_value<N: Into<String>>(mut self, value: N) -> Self {
self.set_value(value);
self
}
pub const fn num(&self) -> i32 {
self.num
}
pub fn set_num(&mut self, num: i32) {
self.num = num;
}
pub fn with_num(mut self, num: i32) -> Self {
self.set_num(num);
self
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_udev_entry() {
let mut null_entry = UdevEntry::new();
let exp_name = "test_name";
let exp_value = "test_value";
let exp_num = 42;
let exp_entry = UdevEntry::new()
.with_name(exp_name)
.with_value(exp_value)
.with_num(exp_num);
assert_eq!(null_entry.name(), "");
assert_eq!(null_entry.value(), "");
assert_eq!(null_entry.num(), 0);
assert_eq!(exp_entry.name(), exp_name);
assert_eq!(exp_entry.value(), exp_value);
assert_eq!(exp_entry.num(), exp_num);
null_entry.set_name(exp_name);
assert_eq!(null_entry.name(), exp_name);
null_entry.set_value(exp_value);
assert_eq!(null_entry.value(), exp_value);
null_entry.set_num(exp_num);
assert_eq!(null_entry.num(), exp_num);
assert_eq!(null_entry, exp_entry);
}
}