mod branding;
mod encode_format;
mod ockam_abac;
mod output_format;
mod utils;
pub use branding::OutputBranding;
pub use encode_format::EncodeFormat;
pub use output_format::OutputFormat;
pub use utils::*;
use crate::Result;
use crate::terminal::fmt;
use itertools::Itertools;
use ockam_core::api::Reply;
use std::fmt::{Display, Write};
pub trait Output {
fn item(&self) -> Result<String>;
fn as_list_item(&self) -> Result<String> {
Ok(self
.item()?
.lines()
.map(|l| l.strip_prefix(fmt::PADDING).unwrap_or(l))
.join("\n"))
}
fn padded_display(&self) -> String
where
Self: Display,
{
self.iter_output().pad().to_string()
}
fn iter_output(&self) -> OutputIter
where
Self: Display,
{
OutputIter::new(self.to_string())
}
}
impl Output for String {
fn item(&self) -> Result<String> {
Ok(self.clone())
}
}
impl Output for &str {
fn item(&self) -> Result<String> {
Ok(self.to_string())
}
}
impl Output for Vec<u8> {
fn item(&self) -> Result<String> {
Ok(hex::encode(self))
}
}
impl<T: Output> Output for Reply<T> {
fn item(&self) -> Result<String> {
match self {
Reply::Successful(t) => t.item(),
Reply::Failed(e, status) => {
let mut output = String::new();
if let Some(m) = e.message() {
writeln!(output, "Failed request: {m}")?;
} else {
writeln!(output, "Failed request")?;
};
if let Some(status) = status {
writeln!(output, "status: {status}")?;
}
Ok(output)
}
}
}
}
pub struct OutputIter {
contents: String,
}
impl Display for OutputIter {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.contents)
}
}
impl OutputIter {
pub fn new(contents: String) -> Self {
Self { contents }
}
pub fn pad(self) -> Self {
let contents = self
.contents
.lines()
.map(|s| format!("{}{}", fmt::PADDING, s))
.collect::<Vec<String>>()
.join("\n");
Self { contents }
}
pub fn indent(self) -> Self {
let contents = self
.contents
.lines()
.map(|s| format!("{}{}", fmt::INDENTATION, s))
.collect::<Vec<String>>()
.join("\n");
Self { contents }
}
}