From 80ee37c2ee3e3bf807ee2675f6295a3386ebeaeb Mon Sep 17 00:00:00 2001
From: Dmitry <b4tm4n@mail.ru>
Date: Mon, 19 Aug 2019 19:03:35 +0300
Subject: [PATCH] saved distribution for rand

---
 src/main.rs | 36 +++++++++++++++++++++++++++++-------
 1 file changed, 29 insertions(+), 7 deletions(-)

diff --git a/src/main.rs b/src/main.rs
index 8174811..40dbbd0 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -21,7 +21,8 @@ use actix_web::{
     App, Error, HttpRequest, HttpResponse, HttpServer, Result,
 };
 
-use rand::seq::IteratorRandom;
+use rand::distributions::Uniform;
+use rand::Rng;
 
 
 use ledb::{Options, Storage};
@@ -102,6 +103,21 @@ struct Question {
 struct AppState {
     storage: Storage,
     template: tera::Tera,
+    database_distribution: Uniform<u32>,
+}
+
+fn get_database_distribution(storage: &Storage) -> Uniform<u32> {
+    let collection = storage
+        .collection("questions")
+        .expect("collection \"questions\"");
+    let last_id = collection.last_id().expect("\"questions\" last_id");
+
+    rand::distributions::Uniform::new_inclusive(1u32, last_id)
+}
+
+fn random_question_id(database_distribution: &Uniform<u32>) -> u32 {
+    let mut rng = rand::thread_rng();
+    rng.sample(database_distribution)
 }
 
 fn get_question(storage: &Storage, id: u32) -> Result<Option<Question>, Error> {
@@ -134,7 +150,12 @@ fn show_question_details(template_file: &str, data: web::Data<AppState>, id: web
 
         if question.is_some() {
             let question = question.unwrap();
-            let body = data.template.render(template_file, &question).unwrap();
+            let mut context = serde_json::to_value(question).expect("question serialize");
+            if context.is_object() {
+                let next_id = random_question_id(&data.database_distribution);
+                context["next"] = serde_json::to_value(next_id).expect("question id serialize");
+            }
+            let body = data.template.render(template_file, &context).expect("template render - show_question_details");
             Ok(HttpResponse::Ok().content_type("text/html").body(body))
         } else {
             Ok(HttpResponse::PermanentRedirect()
@@ -159,10 +180,7 @@ fn show_answer(data: web::Data<AppState>, id: web::Path<u32>) -> Result<HttpResp
 }
 
 fn index(data: web::Data<AppState>, _req: HttpRequest) -> Result<HttpResponse, Error> {
-    let collection = data.storage.collection("questions").expect("collection questions");
-    let mut rng = rand::thread_rng();
-    let last_id = collection.last_id().expect("questions last id");
-    let id = (1..=last_id).choose(&mut rng).expect("random id");
+    let id = random_question_id(&data.database_distribution);
 
     let url = format!("/q/{}", id);
 
@@ -184,10 +202,14 @@ fn main() {
     let storage = Storage::new("db", options).expect("db open");
 
     HttpServer::new(move || {
-        let data = AppState {
+        let mut data = AppState {
             storage: storage.clone(),
             template: compile_templates!("./templates/**/*"),
+            database_distribution: Uniform::new(1, 3),
         };
+        data.database_distribution = get_database_distribution(&data.storage);
+        let data = data;
+
         App::new()
             .wrap(Logger::default())
             .data(data)