Skip to main content

asimov_patterns/
output_format.rs

1// This is free and unencumbered software released into the public domain.
2
3//! Standard output formats with application-defined extensions.
4
5use alloc::string::String;
6use core::{fmt, str::FromStr};
7
8/// An output format for a listing.
9///
10/// The standard command-line names are `jsonl` and `url`. Other names are
11/// parsed through `T`, which defaults to [`String`] to accept arbitrary names.
12/// Use an enum implementing [`FromStr`] to restrict custom formats.
13/// [`Display`](fmt::Display) delegates custom format names to `T`.
14///
15/// The default is [`Jsonl`](Self::Jsonl). An unset
16/// [`crate::ListerOptions::output`] still omits the option entirely.
17#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
18pub enum OutputFormat<T = String> {
19    /// Line-delimited JSON (`jsonl`).
20    #[default]
21    Jsonl,
22    /// Resource URLs (`url`).
23    Url,
24    /// An application-defined format.
25    Other(T),
26}
27
28impl<T: fmt::Display> fmt::Display for OutputFormat<T> {
29    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30        match self {
31            Self::Jsonl => f.write_str("jsonl"),
32            Self::Url => f.write_str("url"),
33            Self::Other(value) => value.fmt(f),
34        }
35    }
36}
37
38impl<T: FromStr> FromStr for OutputFormat<T> {
39    type Err = T::Err;
40
41    fn from_str(value: &str) -> Result<Self, Self::Err> {
42        match value {
43            "jsonl" => Ok(Self::Jsonl),
44            "url" => Ok(Self::Url),
45            _ => value.parse().map(Self::Other),
46        }
47    }
48}
49
50impl<T: AsRef<str>> OutputFormat<T> {
51    /// Returns the command-line format name without allocating.
52    pub fn as_str(&self) -> &str {
53        match self {
54            Self::Jsonl => "jsonl",
55            Self::Url => "url",
56            Self::Other(value) => value.as_ref(),
57        }
58    }
59}
60
61impl<T: AsRef<str>> AsRef<str> for OutputFormat<T> {
62    fn as_ref(&self) -> &str {
63        self.as_str()
64    }
65}
66
67impl From<String> for OutputFormat<String> {
68    fn from(value: String) -> Self {
69        match value.as_str() {
70            "jsonl" => Self::Jsonl,
71            "url" => Self::Url,
72            _ => Self::Other(value),
73        }
74    }
75}
76
77impl From<&str> for OutputFormat<String> {
78    fn from(value: &str) -> Self {
79        match value {
80            "jsonl" => Self::Jsonl,
81            "url" => Self::Url,
82            _ => Self::Other(value.into()),
83        }
84    }
85}