rexcli 0.18.4

Replix admin CLI tool
//
// Copyright (c) 2020 RepliXio Ltd. All rights reserved.
// Use is subject to license terms.
//

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> Into<T> for Output<T>
// where
//     T: de::DeserializeOwned,
// {
//     fn into(self) -> T {
//         match self {
//             Output::Raw(text) => todo!(),
//             Output::Typed(data) => data,
//         }
//     }
// }

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"),
        }
    }
}