///|
pub struct ImageStatistics {
segment_count_value : Int
occupied_bytes_value : Int
address_span_value : UInt64
gap_bytes_value : UInt64
largest_segment_bytes_value : Int
largest_gap_bytes_value : UInt64
lowest_address_value : UInt64?
highest_address_value : UInt64?
} derive(Eq, Debug)
///|
/// Calculate sparse-image metrics without materializing missing addresses.
pub fn analyze_image(image : FirmwareImage) -> ImageStatistics {
let segments = image.segments()
let gaps = image.gaps()
let occupied = image.total_bytes()
let mut gap_bytes = 0UL
let mut largest_gap = 0UL
let mut largest_segment = 0
for gap in gaps {
let length = gap.length()
gap_bytes = gap_bytes + length
if length > largest_gap {
largest_gap = length
}
}
for segment in segments {
if segment.length() > largest_segment {
largest_segment = segment.length()
}
}
let span = match (image.lowest_address(), image.highest_address()) {
(Some(lowest), Some(highest)) => highest - lowest + 1UL
_ => 0UL
}
{
segment_count_value: segments.length(),
occupied_bytes_value: occupied,
address_span_value: span,
gap_bytes_value: gap_bytes,
largest_segment_bytes_value: largest_segment,
largest_gap_bytes_value: largest_gap,
lowest_address_value: image.lowest_address(),
highest_address_value: image.highest_address(),
}
}
///|
pub fn ImageStatistics::segment_count(self : ImageStatistics) -> Int {
self.segment_count_value
}
///|
pub fn ImageStatistics::occupied_bytes(self : ImageStatistics) -> Int {
self.occupied_bytes_value
}
///|
pub fn ImageStatistics::address_span(self : ImageStatistics) -> UInt64 {
self.address_span_value
}
///|
pub fn ImageStatistics::gap_bytes(self : ImageStatistics) -> UInt64 {
self.gap_bytes_value
}
///|
pub fn ImageStatistics::largest_segment_bytes(self : ImageStatistics) -> Int {
self.largest_segment_bytes_value
}
///|
pub fn ImageStatistics::largest_gap_bytes(self : ImageStatistics) -> UInt64 {
self.largest_gap_bytes_value
}
///|
pub fn ImageStatistics::lowest_address(self : ImageStatistics) -> UInt64? {
self.lowest_address_value
}
///|
pub fn ImageStatistics::highest_address(self : ImageStatistics) -> UInt64? {
self.highest_address_value
}
///|
pub fn ImageStatistics::density(self : ImageStatistics) -> Double {
if self.address_span_value == 0UL {
0.0
} else {
self.occupied_bytes_value.to_double() / self.address_span_value.to_double()
}
}
///|
pub fn ImageStatistics::average_segment_bytes(self : ImageStatistics) -> Double {
if self.segment_count_value == 0 {
0.0
} else {
self.occupied_bytes_value.to_double() / self.segment_count_value.to_double()
}
}
///|
pub fn render_statistics_text(statistics : ImageStatistics) -> String {
let mut result = "firmware-statistics segments=" +
statistics.segment_count().to_string() +
" occupied=" +
statistics.occupied_bytes().to_string() +
" span=" +
statistics.address_span().to_string() +
" gap-bytes=" +
statistics.gap_bytes().to_string() +
" largest-segment=" +
statistics.largest_segment_bytes().to_string() +
" largest-gap=" +
statistics.largest_gap_bytes().to_string()
match statistics.lowest_address() {
Some(value) => result = result + " lowest=" + hex_address(value)
None => ()
}
match statistics.highest_address() {
Some(value) => result = result + " highest=" + hex_address(value)
None => ()
}
result
}
///|
pub fn render_statistics_json(statistics : ImageStatistics) -> String {
Json::object({
"type": Json::string("firmware_image_statistics"),
"segment_count": Json::number(statistics.segment_count().to_double()),
"occupied_bytes": Json::number(statistics.occupied_bytes().to_double()),
"address_span": Json::string(statistics.address_span().to_string()),
"gap_bytes": Json::string(statistics.gap_bytes().to_string()),
"largest_segment_bytes": Json::number(
statistics.largest_segment_bytes().to_double(),
),
"largest_gap_bytes": Json::string(
statistics.largest_gap_bytes().to_string(),
),
"lowest_address": optional_address_json(statistics.lowest_address()),
"highest_address": optional_address_json(statistics.highest_address()),
"density": Json::number(statistics.density()),
"average_segment_bytes": Json::number(statistics.average_segment_bytes()),
}).stringify()
}