#![allow(non_snake_case)]
#![allow(non_upper_case_globals)] #![allow(dead_code)]
use crate::ported::crt::{ColorElements, ColorScheme};
use crate::ported::meter::{
Meter, MeterClass, Meter_class, METERMODE_DEFAULT_SUPPORTED, TEXT_METERMODE,
};
use crate::ported::object::ObjectClass;
use crate::ported::processtable::ProcessTable;
use crate::ported::richstring::{RichString, RichString_appendAscii, RichString_appendnAscii};
pub fn TasksMeter_updateValues(this: &mut Meter) {
let host = unsafe { &*this.host };
let pt = unsafe {
&*(host
.processTable
.expect("TasksMeter_updateValues: host->processTable")
as *const ProcessTable)
};
this.values[0] = pt.kernelThreads as f64;
this.values[1] = pt.userlandThreads as f64;
this.values[2] = pt
.totalTasks
.wrapping_sub(pt.kernelThreads)
.wrapping_sub(pt.userlandThreads) as f64;
this.values[3] = u32::min(pt.runningTasks, host.activeCPUs) as f64;
this.txtBuffer = format!(
"{}/{}",
u32::min(pt.runningTasks, host.activeCPUs),
pt.totalTasks
);
}
pub fn TasksMeter_display(this: &Meter, out: &mut RichString) {
let scheme = ColorScheme::active();
let settings = unsafe {
(*this.host)
.settings
.as_ref()
.expect("TasksMeter_display: host->settings")
};
let buffer = format!("{}", this.values[2] as i32);
RichString_appendnAscii(
out,
ColorElements::METER_VALUE.packed(scheme),
buffer.as_bytes(),
buffer.len(),
);
RichString_appendAscii(
out,
if settings.hideUserlandThreads {
ColorElements::METER_SHADOW.packed(scheme)
} else {
ColorElements::METER_TEXT.packed(scheme)
},
b", ",
);
let buffer = format!("{}", this.values[1] as i32);
RichString_appendnAscii(
out,
if settings.hideUserlandThreads {
ColorElements::METER_SHADOW.packed(scheme)
} else {
ColorElements::TASKS_RUNNING.packed(scheme)
},
buffer.as_bytes(),
buffer.len(),
);
RichString_appendAscii(
out,
if settings.hideUserlandThreads {
ColorElements::METER_SHADOW.packed(scheme)
} else {
ColorElements::METER_TEXT.packed(scheme)
},
b" thr",
);
RichString_appendAscii(
out,
if settings.hideKernelThreads {
ColorElements::METER_SHADOW.packed(scheme)
} else {
ColorElements::METER_TEXT.packed(scheme)
},
b", ",
);
let buffer = format!("{}", this.values[0] as i32);
RichString_appendnAscii(
out,
if settings.hideKernelThreads {
ColorElements::METER_SHADOW.packed(scheme)
} else {
ColorElements::TASKS_RUNNING.packed(scheme)
},
buffer.as_bytes(),
buffer.len(),
);
RichString_appendAscii(
out,
if settings.hideKernelThreads {
ColorElements::METER_SHADOW.packed(scheme)
} else {
ColorElements::METER_TEXT.packed(scheme)
},
b" kthr",
);
RichString_appendAscii(out, ColorElements::METER_TEXT.packed(scheme), b"; ");
let buffer = format!("{}", this.values[3] as i32);
RichString_appendnAscii(
out,
ColorElements::TASKS_RUNNING.packed(scheme),
buffer.as_bytes(),
buffer.len(),
);
RichString_appendAscii(out, ColorElements::METER_TEXT.packed(scheme), b" running");
}
static TasksMeter_attributes: [i32; 4] = [
ColorElements::CPU_SYSTEM as i32,
ColorElements::PROCESS_THREAD as i32,
ColorElements::PROCESS as i32,
ColorElements::TASKS_RUNNING as i32,
];
pub static TasksMeter_class: MeterClass = MeterClass {
super_: ObjectClass {
extends: Some(&Meter_class.super_),
},
display: Some(TasksMeter_display),
init: None,
done: None,
updateMode: None,
updateValues: Some(TasksMeter_updateValues),
draw: None,
getCaption: None,
getUiName: None,
defaultMode: TEXT_METERMODE,
supportedModes: METERMODE_DEFAULT_SUPPORTED,
total: 1.0,
attributes: &TasksMeter_attributes,
name: "Tasks",
uiName: "Task counter",
caption: "Tasks: ",
description: None,
maxItems: 4,
isMultiColumn: false,
isPercentChart: false,
};
#[cfg(test)]
mod tests {
use super::*;
fn meter(
totalTasks: u32,
runningTasks: u32,
userlandThreads: u32,
kernelThreads: u32,
activeCPUs: u32,
) -> Meter {
meter_hidden(
totalTasks,
runningTasks,
userlandThreads,
kernelThreads,
activeCPUs,
false,
false,
)
}
#[allow(clippy::too_many_arguments)]
fn meter_hidden(
totalTasks: u32,
runningTasks: u32,
userlandThreads: u32,
kernelThreads: u32,
activeCPUs: u32,
hideUserland: bool,
hideKernel: bool,
) -> Meter {
use crate::ported::machine::Machine;
use crate::ported::settings::Settings;
use crate::ported::table::Table;
let mut pt = Box::new(ProcessTable::empty());
pt.totalTasks = totalTasks;
pt.runningTasks = runningTasks;
pt.userlandThreads = userlandThreads;
pt.kernelThreads = kernelThreads;
let pt: &'static ProcessTable = Box::leak(pt);
let mut m = Box::new(Machine::default());
m.activeCPUs = activeCPUs;
m.processTable = Some(&pt.super_ as *const Table as *mut Table);
m.settings = Some(Settings {
hideUserlandThreads: hideUserland,
hideKernelThreads: hideKernel,
..Default::default()
});
let m: &'static Machine = Box::leak(m);
Meter {
values: vec![0.0; 4],
txtBuffer: String::new(),
host: m as *const Machine,
..Meter::empty()
}
}
fn text(r: &RichString) -> String {
(0..r.chlen as usize).map(|i| r.chptr[i].chars).collect()
}
#[test]
fn typical_counts_and_text() {
let mut m = meter(100, 3, 40, 10, 8);
TasksMeter_updateValues(&mut m);
assert_eq!(m.values[0], 10.0); assert_eq!(m.values[1], 40.0); assert_eq!(m.values[2], 50.0); assert_eq!(m.values[3], 3.0); assert_eq!(m.txtBuffer, "3/100"); }
#[test]
fn minimum_clamps_running_to_active_cpus() {
let mut m = meter(200, 12, 0, 0, 4);
TasksMeter_updateValues(&mut m);
assert_eq!(m.values[3], 4.0);
assert_eq!(m.txtBuffer, "4/200");
}
#[test]
fn minimum_keeps_running_when_below_active_cpus() {
let mut m = meter(50, 2, 0, 0, 16);
TasksMeter_updateValues(&mut m);
assert_eq!(m.values[3], 2.0);
assert_eq!(m.txtBuffer, "2/50");
}
#[test]
fn unsigned_subtraction_wraps_like_c() {
let mut m = meter(0, 0, 0, 1, 1);
TasksMeter_updateValues(&mut m);
assert_eq!(m.values[2], u32::MAX as f64); }
#[test]
fn all_threads_no_userland_tasks() {
let mut m = meter(64, 0, 40, 24, 8);
TasksMeter_updateValues(&mut m);
assert_eq!(m.values[2], 0.0);
assert_eq!(m.txtBuffer, "0/64"); }
#[test]
fn display_full_text() {
let mut m = meter(100, 3, 40, 10, 8);
TasksMeter_updateValues(&mut m);
let mut out = RichString::new();
TasksMeter_display(&m, &mut out);
assert_eq!(text(&out), "50, 40 thr, 10 kthr; 3 running");
}
#[test]
fn display_truncates_double_toward_zero() {
let mut m = meter(0, 0, 0, 0, 0);
m.values = vec![1.9, 2.9, 3.9, 4.9];
let mut out = RichString::new();
TasksMeter_display(&m, &mut out);
assert_eq!(text(&out), "3, 2 thr, 1 kthr; 4 running");
}
#[test]
fn display_text_unaffected_by_hide_flags() {
let mut m = meter_hidden(100, 3, 40, 10, 8, true, true);
TasksMeter_updateValues(&mut m);
let mut out = RichString::new();
TasksMeter_display(&m, &mut out);
assert_eq!(text(&out), "50, 40 thr, 10 kthr; 3 running");
}
}