problem set generator
1
2use axum::{http::{HeaderMap, header}, response::IntoResponse};
3use dyn_fmt::AsStrFormatExt;
4use genpdf::{Document, elements::{self, Paragraph}, style};
5use rand::random_range;
6use crate::GenpdfState;
7use strum_macros::{Display, EnumString};
8
9
10#[derive(Debug,EnumString,Display,PartialEq)]
11pub enum Subject {
12 Math,
13 Physics
14}
15
16#[derive(Debug,Display,PartialEq)]
17pub enum Theme {
18 Math(MathTheme),
19 Physics(PhysTheme)
20}
21
22
23#[derive(Debug,EnumString,Display,PartialEq)]
24pub enum PhysTheme {
25 LawMotion,
26 Momentum,
27 Energy,
28}
29
30#[derive(Debug,EnumString,Display,PartialEq)]
31pub enum MathTheme {
32 ParametricEquations,
33 InfiniteSequenceSeries,
34 PartialDerivatives,
35
36}
37
38pub struct Question<F>
39 where F: Fn(&[f32])-> f32
40 {
41 pub subject: Subject,
42 pub theme: Theme,
43 pub text: &'static str,
44 pub var_conditions: &'static [(i32,i32)],
45 pub ans_expression: F
46}
47
48#[derive(Debug,Display)]
49pub enum QuestionParseError {
50 QuestionFileParseError,
51 Strum(strum::ParseError)
52}
53
54
55impl<F> Question<F>
56 where F: Fn(&[f32])-> f32
57{
58 pub fn generate_question(&self) -> (String,String) {
59 let vars:Vec<i32> = self.var_conditions.iter().map(|x| {
60 random_range(x.0..x.1)
61 }).collect();
62 let text = self.text.format(&vars[..]);
63
64 let answer = (self.ans_expression)(vars.iter().map(|x| *x as f32).collect::<Vec<f32>>().iter().as_slice());
65
66 (text.to_string(),format!("{}",answer))
67 }
68
69}
70
71
72
73pub fn build_document_base(state:GenpdfState) -> Document {
74
75 let mut doc = genpdf::Document::new(state.font_family);
76 doc.set_title("Test document title");
77 let mut decorator = genpdf::SimplePageDecorator::new();
78 decorator.set_margins(10);
79 doc.set_page_decorator(decorator);
80 doc.set_hyphenator(state.hyphenator);
81 let mut title = Paragraph::default();
82 title.push_styled("title", style::Effect::Bold);
83 title.set_alignment(genpdf::Alignment::Center);
84 doc.push(title);
85
86 doc.push(elements::Break::new(5));
87 doc
88}
89
90pub fn build_response(doc: Document) -> impl IntoResponse {
91
92 let mut headers = HeaderMap::new();
93 headers.insert(header::CONTENT_TYPE, "application/pdf".parse().unwrap());
94 let mut w: Vec<u8> = vec![];
95 let _ = doc.render(&mut w).expect("error during pdf rendering");
96 (headers,w)
97}