plottery_project/
project_main.rs1use bincode::serialize;
2use clap::{Parser, Subcommand};
3use plottery_lib::Layer;
4use std::error::Error;
5use std::io::{self, Read, Write};
6use std::path::PathBuf;
7
8use crate::project_param::ProjectParam;
9use crate::project_params_definition::PlotteryParams;
10use crate::project_params_list_wrapper::ProjectParamsListWrapper;
11
12#[derive(Debug, Clone, Subcommand)]
13enum RunCommand {
14 Svg {
15 path: Option<String>,
16 scale: Option<f32>,
17 },
18 StdOut {
19 #[arg(long, short)]
20 piped_params: Option<bool>,
21 },
22 NamedPipe {
23 #[arg(long, short)]
24 piped_params: Option<bool>,
25 pipe_path: String,
26 },
27 Dry {},
28 Params {},
29}
30
31#[derive(Parser, Debug)]
32#[command(
33 about = "Plotter-project executable.",
34 long_about = "Can be used to run the project and e.g. directly open as .svg."
35)]
36struct Args {
37 #[command(subcommand)]
38 command: RunCommand,
39}
40
41fn read_params_from_stdin() -> Result<Vec<ProjectParam>, Box<dyn Error>> {
42 let mut buffer = Vec::new();
43 io::stdin().read_to_end(&mut buffer)?;
44 let params_list_wrapper: ProjectParamsListWrapper = bincode::deserialize(&buffer)?;
45 Ok(params_list_wrapper.list)
46}
47
48pub fn run_project<P, F>(generate_function: F) -> Result<(), Box<dyn Error>>
49where
50 P: PlotteryParams,
51 F: Fn(P) -> Layer,
52{
53 let args = Args::parse();
54 match args.command {
55 RunCommand::Svg { path, scale } => {
56 let scale = scale.unwrap_or(10.0);
57
58 match path {
59 Some(path_string) => {
60 let path = PathBuf::from(&path_string);
61 if path.is_dir() {
62 panic!(
63 "Failed to write .svg - Path '{}' is a directory.",
64 path_string
65 );
66 }
67 let art = generate_function(P::new_with_defaults());
68 art.write_svg(path, scale)?;
69 }
70 None => {
71 let path = std::env::temp_dir().join("temp_cli.svg");
72 let art = generate_function(P::new_with_defaults());
73 art.write_svg(path.clone(), scale)?;
74
75 open::that_in_background(path)
76 .join()
77 .expect("Failed to join background process for opening SVG")
78 .expect("Failed to open SVG file in default viewer");
79 }
80 }
81 }
82 RunCommand::StdOut { piped_params } => {
83 let wait_for_stdin = piped_params.unwrap_or(false);
84
85 let params = if wait_for_stdin {
86 let list = read_params_from_stdin()?;
87 P::new_from_list(list)
88 } else {
89 P::new_with_defaults()
90 };
91
92 let mut stdout = io::stdout().lock();
93 let art = generate_function(params);
94 let binary = art
95 .to_binary()
96 .expect("Failed to convert layer to binary format");
97 stdout.write_all(&binary)?;
98 }
99 RunCommand::NamedPipe {
100 piped_params,
101 pipe_path,
102 } => {
103 let wait_for_stdin = piped_params.unwrap_or(false);
104
105 let params = if wait_for_stdin {
106 let list = read_params_from_stdin()?;
107 P::new_from_list(list)
108 } else {
109 P::new_with_defaults()
110 };
111
112 let art = generate_function(params);
113 let binary = art
114 .to_binary()
115 .expect("Failed to convert layer to binary format");
116
117 let mut file = std::fs::OpenOptions::new()
118 .write(true)
119 .create(true)
120 .truncate(true)
121 .open(&pipe_path)
122 .expect("Failed to open pipe.");
123 file.write_all(&binary)?;
124 }
125 RunCommand::Dry {} => {
126 generate_function(P::new_with_defaults());
127 }
128 RunCommand::Params {} => {
129 let mut stdout = io::stdout().lock();
130 let params_list = ProjectParamsListWrapper::new(P::param_defaults_list());
131 let binary = serialize(¶ms_list)?;
132 stdout.write_all(&binary)?;
133 }
134 }
135 Ok(())
136}