cargo_fnstack/
lib.rs

1use anyhow::Result;
2use std::path::PathBuf;
3
4#[derive(Debug, Default)]
5pub struct ProjectOptions {
6    pub name: String,
7    pub path: PathBuf,
8
9    pub init_git: bool,
10
11    pub web_server: WebServer,
12    pub websocket_server: Option<WebsocketServer>,
13    pub database: Option<Database>,
14
15    pub docker: bool,
16}
17
18impl ProjectOptions {
19    pub fn prompt() -> Result<Self> {
20        let mut options = ProjectOptions::default();
21
22        let project_name = inquire::Text::new("Project name: ")
23            .with_initial_value("my-awesome-project")
24            .prompt()?;
25        options.name = project_name;
26        options.path = PathBuf::from("./").join(&options.name);
27
28        let init_git = inquire::Confirm::new("Initialize git repository?").prompt()?;
29        options.init_git = init_git;
30
31        let web_server =
32            inquire::Select::new("Select web server:", WebServer::variants()).prompt()?;
33        options.web_server = WebServer::from_str(web_server).unwrap();
34
35        let websocket_server = inquire::Select::new(
36            "Select websocket server:",
37            WebsocketServer::variants(&options),
38        )
39        .prompt()?;
40        options.websocket_server = WebsocketServer::from_str(websocket_server);
41
42        let database =
43            inquire::Select::new("Select database:", Database::variants(&options)).prompt()?;
44        options.database = Database::from_str(database);
45
46        if options.web_server != WebServer::Cloudflare {
47            let use_docker = inquire::Confirm::new("Use docker?").prompt()?;
48            options.docker = use_docker;
49        }
50
51        Ok(options)
52    }
53}
54
55#[derive(Debug, Default, PartialEq, Eq)]
56pub enum WebServer {
57    #[default]
58    Actix,
59    Axum,
60    Cloudflare,
61}
62
63impl<'a> WebServer {
64    pub fn variants() -> Vec<&'a str> {
65        vec!["Actix", "Axum", "Cloudflare (Workers)"]
66    }
67
68    pub fn from_str(s: &str) -> Option<Self> {
69        match s {
70            "Actix" => Some(WebServer::Actix),
71            "Axum" => Some(WebServer::Axum),
72            "Cloudflare (Workers)" => Some(WebServer::Cloudflare),
73            _ => None,
74        }
75    }
76
77    pub fn to_str(&self) -> &'a str {
78        match self {
79            WebServer::Actix => "Actix",
80            WebServer::Axum => "Axum",
81            WebServer::Cloudflare => "Cloudflare",
82        }
83    }
84}
85
86#[derive(Debug, Default, PartialEq, Eq)]
87pub enum WebsocketServer {
88    #[default]
89    Actix,
90    Tungstenite,
91    On,
92    Off,
93}
94
95impl<'a> WebsocketServer {
96    pub fn variants(options: &ProjectOptions) -> Vec<&'a str> {
97        match options.web_server {
98            WebServer::Actix => vec!["Tungstenite", "Off"],
99            WebServer::Axum => vec!["Tungstenite", "Off"],
100            WebServer::Cloudflare => vec!["On", "Off"],
101        }
102    }
103
104    pub fn from_str(s: &str) -> Option<Self> {
105        match s {
106            "Actix" => Some(WebsocketServer::Actix),
107            "Tungstenite" => Some(WebsocketServer::Tungstenite),
108            "On" => Some(WebsocketServer::On),
109            _ => None,
110        }
111    }
112}
113
114#[derive(Debug, Default, PartialEq, Eq)]
115pub enum Database {
116    #[default]
117    Postgres,
118    Off,
119}
120
121impl<'a> Database {
122    pub fn variants(options: &ProjectOptions) -> Vec<&'a str> {
123        match options.web_server {
124            WebServer::Actix => vec!["Postgres(SQLX)", "Off"],
125            WebServer::Axum => vec!["Postgres(SQLX)", "Off"],
126            WebServer::Cloudflare => vec!["TODO: Cloudflare", "Off"],
127        }
128    }
129
130    pub fn from_str(s: &str) -> Option<Self> {
131        match s {
132            "Postgres(SQLX)" => Some(Database::Postgres),
133            _ => None,
134        }
135    }
136}