Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 52d26253 authored by Archie Pusaka's avatar Archie Pusaka
Browse files

Floss: hcidoc: Sort the addresses in informational rule

Sorted information is easier to navigate, so sort the addresses
before printing them out.

Bug: 293397988
Test: Run hcidoc with report 91055564245
Change-Id: I4fdc9e7dc5736fc15e699283f9d530ac7f31a8e3
parent 3018ea95
Loading
Loading
Loading
Loading
+59 −13
Original line number Diff line number Diff line
///! Rule group for general information.
use chrono::NaiveDateTime;
use std::cmp::Ordering;
use std::collections::{HashMap, HashSet};
use std::convert::Into;
use std::fmt;
@@ -17,7 +18,7 @@ type ConnectionHandle = u16;

const INVALID_TS: NaiveDateTime = NaiveDateTime::MAX;

#[derive(Copy, Clone)]
#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord)]
enum AddressType {
    None,
    BREDR,
@@ -108,10 +109,7 @@ impl DeviceInformation {
            acl_state: AclState::None,
        }
    }
}

impl fmt::Display for DeviceInformation {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
    fn print_names(names: &HashSet<String>) -> String {
        if names.len() > 1 {
            format!("{:?}", names)
@@ -119,13 +117,16 @@ impl fmt::Display for DeviceInformation {
            names.iter().next().unwrap_or(&String::from("<Unknown name>")).to_owned()
        }
    }
}

impl fmt::Display for DeviceInformation {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let _ = writeln!(
            f,
            "{address} ({address_type}, {device_names}), {num_connections} connections",
            address = self.address,
            address_type = self.address_type,
            device_names = print_names(&self.names),
            device_names = DeviceInformation::print_names(&self.names),
            num_connections = self.acls.len()
        );
        for acl in &self.acls {
@@ -161,7 +162,7 @@ impl fmt::Display for AclInformation {

        writeln!(
            f,
            "> Handle: {handle}, {initiator}, {timestamp_info}",
            "  Handle: {handle}, {initiator}, {timestamp_info}",
            handle = self.handle,
            initiator = self.initiator,
            timestamp_info = print_timestamps(self.start_time, self.end_time)
@@ -416,13 +417,58 @@ impl Rule for InformationalRule {
    }

    fn report(&self, writer: &mut dyn Write) {
        /* Sort when displaying the addresses, from the most to the least important:
         * (1) Device with connections > Device without connections
         * (2) Device with known name > Device with unknown name
         * (3) BREDR > LE > Dual
         * (4) Name, lexicographically (case sensitive)
         * (5) Address, alphabetically
         */
        fn sort_addresses(a: &DeviceInformation, b: &DeviceInformation) -> Ordering {
            let connection_order = a.acls.is_empty().cmp(&b.acls.is_empty());
            if connection_order != Ordering::Equal {
                return connection_order;
            }

            let known_name_order = a.names.is_empty().cmp(&b.names.is_empty());
            if known_name_order != Ordering::Equal {
                return known_name_order;
            }

            let address_type_order = a.address_type.cmp(&b.address_type);
            if address_type_order != Ordering::Equal {
                return address_type_order;
            }

            let a_name = format!("{}", DeviceInformation::print_names(&a.names));
            let b_name = format!("{}", DeviceInformation::print_names(&b.names));
            let name_order = a_name.cmp(&b_name);
            if name_order != Ordering::Equal {
                return name_order;
            }

            let a_address = <[u8; 6]>::from(a.address);
            let b_address = <[u8; 6]>::from(b.address);
            for i in (0..6).rev() {
                let address_order = a_address[i].cmp(&b_address[i]);
                if address_order != Ordering::Equal {
                    return address_order;
                }
            }
            // This shouldn't be executed
            return Ordering::Equal;
        }

        if self.devices.is_empty() {
            return;
        }

        let mut addresses: Vec<Address> = self.devices.keys().cloned().collect();
        addresses.sort_unstable_by(|a, b| sort_addresses(&self.devices[a], &self.devices[b]));

        let _ = writeln!(writer, "InformationalRule report:");
        for (_, info) in &self.devices {
            let _ = write!(writer, "{}", info);
        for address in addresses {
            let _ = write!(writer, "{}", self.devices[&address]);
        }
    }