#![allow(non_snake_case)]
#![allow(non_upper_case_globals)] #![allow(dead_code)]
use crate::ported::hashtable::{
Hashtable, Hashtable_delete, Hashtable_foreach, Hashtable_get, Hashtable_new,
};
use crate::ported::linux::platform::{
Platform_dynamicColumnName, Platform_dynamicColumnWriteField, Platform_dynamicColumns,
Platform_dynamicColumnsDone,
};
use crate::ported::object::{Object, ObjectClass, Object_class};
use crate::ported::process::Process;
use crate::ported::richstring::RichString;
use crate::ported::table::Table;
pub const DYNAMIC_MAX_COLUMN_WIDTH: i32 = 64;
pub const DYNAMIC_DEFAULT_COLUMN_WIDTH: i32 = -5;
pub struct DynamicColumn {
pub name: String,
pub heading: Option<String>,
pub caption: Option<String>,
pub description: Option<String>,
pub width: i32,
pub enabled: bool,
pub table: *const Table,
}
static DynamicColumn_class: ObjectClass = ObjectClass {
extends: Some(&Object_class),
};
impl Object for DynamicColumn {
fn klass(&self) -> &'static ObjectClass {
&DynamicColumn_class
}
}
pub struct DynamicIterator<'a> {
pub name: &'a str,
pub data: Option<&'a DynamicColumn>,
pub key: u32,
}
pub fn DynamicColumn_compare<'a>(
key: u32,
value: &'a DynamicColumn,
iter: &mut DynamicIterator<'a>,
) {
if iter.name == value.name {
iter.data = Some(value);
iter.key = key;
}
}
pub fn DynamicColumns_new() -> Hashtable {
Platform_dynamicColumns().unwrap_or_else(|| Hashtable_new(0, true))
}
pub fn DynamicColumns_delete(dynamics: Option<Hashtable>) {
if let Some(dynamics) = dynamics {
Platform_dynamicColumnsDone(&dynamics);
Hashtable_delete(dynamics);
}
}
pub fn DynamicColumn_name(key: u32) -> Option<&'static str> {
Platform_dynamicColumnName(key)
}
pub fn DynamicColumn_done(this: &mut DynamicColumn) {
this.heading = None;
this.caption = None;
this.description = None;
}
pub fn DynamicColumn_search<'a>(
dynamics: Option<&'a Hashtable>,
name: &str,
key: Option<&mut u32>,
) -> Option<&'a DynamicColumn> {
let mut matched_key: u32 = 0;
let mut matched = false;
if let Some(dynamics) = dynamics {
Hashtable_foreach(dynamics, &mut |k, value| {
let any: &dyn core::any::Any = value;
let column = any
.downcast_ref::<DynamicColumn>()
.expect("DynamicColumn_search: hashtable value is not a DynamicColumn");
let mut iter = DynamicIterator {
name,
data: None,
key: 0,
};
DynamicColumn_compare(k, column, &mut iter);
if iter.data.is_some() {
matched = true;
matched_key = iter.key;
}
});
}
if let Some(key) = key {
*key = matched_key;
}
if matched {
dynamics
.and_then(|d| Hashtable_get(d, matched_key))
.and_then(|o| {
let any: &dyn core::any::Any = o;
any.downcast_ref::<DynamicColumn>()
})
} else {
None
}
}
pub fn DynamicColumn_lookup(dynamics: &Hashtable, key: u32) -> Option<&DynamicColumn> {
Hashtable_get(dynamics, key).and_then(|o| {
let any: &dyn core::any::Any = o;
any.downcast_ref::<DynamicColumn>()
})
}
pub fn DynamicColumn_writeField(proc: &Process, str: &mut RichString, key: u32) -> bool {
Platform_dynamicColumnWriteField(proc, str, key)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::ported::hashtable::{Hashtable_count, Hashtable_put};
fn col(name: &str) -> DynamicColumn {
DynamicColumn {
name: name.to_string(),
heading: None,
caption: None,
description: None,
width: DYNAMIC_DEFAULT_COLUMN_WIDTH,
enabled: false,
table: core::ptr::null(),
}
}
fn registry(names: &[(u32, &str)]) -> crate::ported::hashtable::Hashtable {
let mut ht = Hashtable_new(0, false);
for &(k, n) in names {
Hashtable_put(&mut ht, k, Box::new(col(n)));
}
ht
}
#[test]
fn lookup_returns_column_for_present_key() {
let ht = registry(&[(1, "cpu"), (2, "mem"), (100, "io")]);
assert_eq!(DynamicColumn_lookup(&ht, 1).unwrap().name, "cpu");
assert_eq!(DynamicColumn_lookup(&ht, 2).unwrap().name, "mem");
assert_eq!(DynamicColumn_lookup(&ht, 100).unwrap().name, "io");
}
#[test]
fn lookup_returns_none_for_absent_key() {
let ht = registry(&[(1, "cpu")]);
assert!(DynamicColumn_lookup(&ht, 999).is_none());
}
#[test]
fn search_finds_by_name_and_writes_key() {
let ht = registry(&[(10, "cpu"), (20, "mem"), (30, "io")]);
let mut key: u32 = 0;
let found = DynamicColumn_search(Some(&ht), "mem", Some(&mut key));
assert_eq!(found.unwrap().name, "mem");
assert_eq!(key, 20);
}
#[test]
fn search_key_out_param_is_optional() {
let ht = registry(&[(5, "cpu")]);
let found = DynamicColumn_search(Some(&ht), "cpu", None);
assert_eq!(found.unwrap().name, "cpu");
}
#[test]
fn search_miss_returns_none_and_zeroes_key() {
let ht = registry(&[(1, "cpu"), (2, "mem")]);
let mut key: u32 = 12345;
let found = DynamicColumn_search(Some(&ht), "nonexistent", Some(&mut key));
assert!(found.is_none());
assert_eq!(key, 0);
}
#[test]
fn search_null_table_returns_none() {
let mut key: u32 = 7;
let found = DynamicColumn_search(None, "cpu", Some(&mut key));
assert!(found.is_none());
assert_eq!(key, 0);
}
#[test]
fn search_is_case_sensitive_like_string_eq() {
let ht = registry(&[(1, "CPU")]);
let mut key: u32 = 0;
assert!(DynamicColumn_search(Some(&ht), "cpu", Some(&mut key)).is_none());
assert_eq!(key, 0);
assert_eq!(
DynamicColumn_search(Some(&ht), "CPU", None).unwrap().name,
"CPU"
);
}
#[test]
fn search_result_matches_lookup_of_returned_key() {
let ht = registry(&[(3, "alpha"), (17, "beta"), (42, "gamma")]);
for name in ["alpha", "beta", "gamma"] {
let mut key: u32 = 0;
let s = DynamicColumn_search(Some(&ht), name, Some(&mut key)).unwrap();
let l = DynamicColumn_lookup(&ht, key).unwrap();
assert_eq!(s.name, name);
assert_eq!(l.name, name);
assert!(std::ptr::eq(s, l));
}
}
#[test]
fn compare_records_match_and_key() {
let cpu = col("cpu");
let mut iter = DynamicIterator {
name: "cpu",
data: None,
key: 0,
};
DynamicColumn_compare(7, &cpu, &mut iter);
assert_eq!(iter.key, 7);
assert!(matches!(iter.data, Some(c) if c.name == "cpu"));
}
#[test]
fn compare_ignores_non_match() {
let mem = col("mem");
let mut iter = DynamicIterator {
name: "cpu",
data: None,
key: 0,
};
DynamicColumn_compare(3, &mem, &mut iter);
assert_eq!(iter.key, 0);
assert!(iter.data.is_none());
}
#[test]
fn compare_is_exact_case_sensitive_strcmp() {
let upper = col("CPU");
let mut iter = DynamicIterator {
name: "cpu",
data: None,
key: 0,
};
DynamicColumn_compare(9, &upper, &mut iter);
assert_eq!(iter.key, 0);
assert!(iter.data.is_none());
}
#[test]
fn new_returns_empty_owning_registry() {
let ht = DynamicColumns_new();
assert_eq!(Hashtable_count(&ht), 0);
}
#[test]
fn name_is_none_on_this_platform() {
assert!(DynamicColumn_name(0).is_none());
assert!(DynamicColumn_name(12345).is_none());
}
#[test]
fn compare_last_match_wins() {
let a = col("dup");
let b = col("dup");
let mut iter = DynamicIterator {
name: "dup",
data: None,
key: 0,
};
DynamicColumn_compare(1, &a, &mut iter);
DynamicColumn_compare(2, &b, &mut iter);
assert_eq!(iter.key, 2);
assert!(std::ptr::eq(iter.data.unwrap(), &b));
}
}