use anyhow::{self, Result};
use std::{ops::Deref, path, str};
use structopt::StructOpt;
use thiserror::Error;
#[derive(Error, Debug)]
pub enum CliError {
#[error("unknown code generation backend '{0}'")]
UnknownBackend(String),
#[error("unknown output artifact '{0}'")]
UnknownArtifact(String),
#[error(transparent)]
LibraryError(#[from] humblegen::LibError),
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum Backend {
Rust,
Elm,
Docs,
}
impl str::FromStr for Backend {
type Err = CliError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_uppercase().as_str() {
"RUST" => Ok(Backend::Rust),
"ELM" => Ok(Backend::Elm),
"DOCS" | "DOC" | "DOCUMENTATION" => Ok(Backend::Docs),
_ => Err(CliError::UnknownBackend(s.to_string())),
}
}
}
#[derive(Default)]
pub(crate) struct Artifact(humblegen::Artifact);
impl str::FromStr for Artifact {
type Err = CliError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_uppercase().as_str() {
"TYPES" => Ok(Artifact(humblegen::Artifact::TypesOnly)),
"CLIENT" => Ok(Artifact(humblegen::Artifact::ClientEndpoints)),
"SERVER" => Ok(Artifact(humblegen::Artifact::ServerEndpoints)),
_ => Err(CliError::UnknownArtifact(s.to_string())),
}
}
}
impl ToString for Artifact {
fn to_string(&self) -> String {
match self.0 {
humblegen::Artifact::TypesOnly => "TYPES".to_string(),
humblegen::Artifact::ClientEndpoints => "CLIENT".to_string(),
humblegen::Artifact::ServerEndpoints => "SERVER".to_string(),
}
}
}
impl Deref for Artifact {
type Target = humblegen::Artifact;
fn deref(&self) -> &Self::Target {
&self.0
}
}
#[derive(StructOpt)]
#[structopt(about = "generate code from humble protocol spec")]
pub(crate) struct CliArgs {
#[structopt(short = "l", long = "language")]
pub(crate) backend: Backend,
#[structopt(short = "a", long = "artifacts", default_value)]
pub(crate) artifacts: Artifact,
pub(crate) input: path::PathBuf,
#[structopt(short = "o", long = "output")]
pub(crate) output: path::PathBuf,
#[structopt(long, default_value = "\"Api\"")]
pub(crate) elm_module_root: String,
}
impl CliArgs {
pub fn code_generator(&self) -> Result<Box<dyn humblegen::CodeGenerator>, CliError> {
match self.backend {
Backend::Rust => Ok(Box::new(
humblegen::backend::rust::Generator::new(*self.artifacts)
.map_err(CliError::LibraryError)?,
)),
Backend::Elm => Ok(Box::new(
humblegen::backend::elm::Generator::new(
*self.artifacts,
self.elm_module_root.clone(),
)
.map_err(CliError::LibraryError)?,
)),
Backend::Docs => Ok(Box::new(humblegen::backend::docs::Generator::default())),
}
}
}