use std::{fmt, ops};
use serde::de;
use serde_json as json;
use crate::show::Show;
#[derive(Debug)]
pub(crate) enum Output<T> {
Raw(String),
Typed(T),
Value(json::Value),
}
impl<T> Output<T> {
pub(crate) fn is_typed(&self) -> bool {
matches!(self, Self::Typed(_))
}
}
impl<T> Show for Output<T>
where
T: Show,
{
fn show(self) -> String {
match self {
Self::Raw(text) => text,
Self::Typed(data) => data.show(),
Self::Value(value) => value.to_string(),
}
}
}
pub(crate) trait IntoOutput {
type Err;
fn into_output<T>(self, raw: bool, json: bool) -> Result<Output<T>, Self::Err>
where
T: de::DeserializeOwned + fmt::Debug;
}
impl IntoOutput for attohttpc::Response {
type Err = attohttpc::Error;
fn into_output<T>(self, raw: bool, json: bool) -> Result<Output<T>, <Self as IntoOutput>::Err>
where
T: de::DeserializeOwned + fmt::Debug,
{
if raw {
self.text().map(Output::Raw)
} else if json {
self.json().map(Output::Value)
} else {
self.json().map(Output::Typed)
}
}
}
impl<T> ops::Deref for Output<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
match self {
Self::Raw(_) => panic!("Deref is not implemented for Output::Raw"),
Self::Typed(data) => data,
Self::Value(_) => panic!("Deref is not implemented for Output::Value"),
}
}
}
impl<T> IntoIterator for Output<T>
where
T: IntoIterator,
{
type Item = <T as IntoIterator>::Item;
type IntoIter = <T as IntoIterator>::IntoIter;
fn into_iter(self) -> Self::IntoIter {
match self {
Self::Raw(_) => panic!("IntoIterator is not implemented for Output::Raw"),
Self::Typed(data) => data.into_iter(),
Self::Value(_) => panic!("IntoIterator is not implemented for Output::Value"),
}
}
}