trustchain_core/
display.rs

1//! Utilities to display DID.
2use ssi::did::{Document, Service, ServiceEndpoint};
3use ssi::one_or_many::OneOrMany;
4use std::fmt;
5
6use crate::TRUSTCHAIN_SERVICE_ID_VALUE;
7
8/// Truncates a string to be of maximum length `max_chars` and adds ellipsis.
9fn truncate(s: &str, max_chars: usize) -> String {
10    match s.char_indices().nth(max_chars) {
11        None => s.to_string(),
12        Some((idx, _)) => s[..idx - 3].to_string() + "...",
13    }
14}
15
16/// Extracts the service endpoint string from a DID `Document` if exactly one service with
17/// "id": `TrustchainID` is present.
18fn get_service_endpoint_string(doc: &Document) -> Option<String> {
19    match doc.select_service(TRUSTCHAIN_SERVICE_ID_VALUE) {
20        Some(Service {
21            service_endpoint: Some(OneOrMany::One(ServiceEndpoint::URI(service_endpoint))),
22            ..
23        }) => Some(service_endpoint.to_string()),
24        _ => None,
25    }
26}
27
28/// A struct for displaying a DID in a box.
29pub struct PrettyDID {
30    did: String,
31    level: usize,
32    endpoint: Option<String>,
33    max_width: usize,
34}
35
36impl PrettyDID {
37    pub fn new(doc: &Document, level: usize, max_width: usize) -> Self {
38        let endpoint = get_service_endpoint_string(doc);
39        Self {
40            did: doc.id.to_string(),
41            level,
42            endpoint,
43            max_width,
44        }
45    }
46    pub fn get_width(&self) -> usize {
47        format!(" DID: {} ", self.did).len().min(self.max_width)
48    }
49    fn get_text_width(&self) -> usize {
50        self.get_width() - 2
51    }
52    pub fn get_strings(&self) -> [String; 3] {
53        let text_width = self.get_text_width();
54        let level_string = truncate(&format!("Level: {}", self.level), text_width);
55        let did_string = truncate(&format!("DID: {}", self.did), text_width);
56        let endpoint_string = match &self.endpoint {
57            Some(s) => truncate(&format!("Endpoint: {}", s), text_width),
58            _ => truncate(&format!("Endpoint: {}", ""), text_width),
59        };
60        [level_string, did_string, endpoint_string]
61    }
62    pub fn to_node_string(&self) -> String {
63        let strings = self.get_strings();
64        strings.join("\n")
65    }
66}
67
68impl fmt::Display for PrettyDID {
69    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
70        // Style:
71        // "+---------------+"
72        // "| level: ...    |"
73        // "| did: ...      |"  ✅
74        // "| endpoint: ... |"
75        // "+---------------+"
76        let box_width = self.get_width();
77        let text_width = box_width - 2;
78        let [level_string, did_string, endpoint_string] = self.get_strings();
79        writeln!(f, "+{}+", "-".repeat(box_width))?;
80        writeln!(f, "| {0:<1$} |   ", level_string, text_width)?;
81        writeln!(f, "| {0:<1$} |  ✅", did_string, text_width)?;
82        writeln!(f, "| {0:<1$} |   ", endpoint_string, text_width)?;
83        writeln!(f, "+{}+", "-".repeat(box_width))?;
84        Ok(())
85    }
86}