From 3ee9533fafc8cbe8d1e0de670518cbfa9a9b8378 Mon Sep 17 00:00:00 2001 From: artus40 Date: Wed, 13 Feb 2019 16:01:24 +0100 Subject: [PATCH] working on rust side --- cookbook/src/lib.rs | 8 ++++ planner/src/solver.rs | 17 +++++-- web/src/main.rs | 72 ++++++++++++++++++++++++++++-- web/vue/src/components/Planner.vue | 20 ++++++++- 4 files changed, 108 insertions(+), 9 deletions(-) diff --git a/cookbook/src/lib.rs b/cookbook/src/lib.rs index da23aa0..26ef8ac 100644 --- a/cookbook/src/lib.rs +++ b/cookbook/src/lib.rs @@ -38,6 +38,14 @@ pub mod recipes { .execute(conn) .is_ok() } + + pub fn get(conn: &SqliteConnection, recipe_id: i32) -> Option { + use self::schema::recipes::dsl::*; + + recipes.filter(id.eq(recipe_id)) + .first(conn) + .ok() + } } pub mod ingredients { diff --git a/planner/src/solver.rs b/planner/src/solver.rs index 75b9a39..bda4b87 100644 --- a/planner/src/solver.rs +++ b/planner/src/solver.rs @@ -19,7 +19,7 @@ pub type DomainValues<'a, V> = Vec<&'a V>; /// The domain of values that can be assigned to variables #[derive(Clone)] pub struct Domain { - values: Vec + pub values: Vec } impl Domain { @@ -51,6 +51,7 @@ impl Domain { .filter(|v: &&V| filter_func(*v)) .collect() } + } impl fmt::Debug for Domain { @@ -118,7 +119,12 @@ impl<'a,V, K: Eq + Hash + Clone> Problem<'a, V, K> { { let mut solutions: Vec> = vec![]; let mut stack: Vec> = vec![]; - stack.append(&mut self._push_updates().unwrap()); + if let Some(mut init_updates) = self._push_updates() { + stack.append(&mut init_updates); + } else { + panic!("Could not initialize !"); + } + loop { let node = stack.pop(); if node.is_none() { break; }; @@ -150,7 +156,12 @@ impl<'a,V, K: Eq + Hash + Clone> Problem<'a, V, K> { K: Clone + fmt::Debug, { let mut stack: Vec> = vec![]; - stack.append(&mut self._push_updates().unwrap()); + if let Some(mut init_updates) = self._push_updates() { + stack.append(&mut init_updates); + } else { + panic!("Could not initialize !"); + } + loop { let node = stack.pop(); if node.is_none() { diff --git a/web/src/main.rs b/web/src/main.rs index 01ee0a5..d218ccb 100644 --- a/web/src/main.rs +++ b/web/src/main.rs @@ -37,7 +37,7 @@ mod api { pub struct CookbookDbConn(diesel::SqliteConnection); /// A serializable wrapper for [`cookbook::recipes::Recipe`] - #[derive(Serialize)] + #[derive(Serialize, Deserialize, Debug)] pub struct RecipeObject { id: i32, title: String, @@ -76,13 +76,13 @@ mod api { Json( recipes::delete(&conn, id) ) } - #[derive(Serialize)] + #[derive(Serialize, Deserialize, Debug)] pub struct TemplateItems { key: (String, String), value: Option, } - #[derive(Serialize)] + #[derive(Serialize, Deserialize)] pub struct TemplateObject { items: Vec } @@ -118,6 +118,65 @@ mod api { panic!("No solution at all !"); } } + + + #[post("/solver/complete", data="")] + pub fn complete_problem(conn: CookbookDbConn, partial: Json>) -> Json { + use planner::{ + template, + solver::{Domain, Problem} + }; + + println!("{:?}", partial); + println!("Building problem"); + let possible_values = recipes::load_all(&conn); + let domain = Domain::new(possible_values); + let mut problem = Problem::build(); + for (var, dom, ini) in template::Template::generate_variables(&domain) { + // Let's hack for now + // BUGGY because template does not generate every variables, needs refactoring + // Find variable in partial + let initial_id = partial.iter().find_map(|slot| { + if slot.value.is_none() { return None; }; + //println!("{:?} vs {:?}", slot, var); + if slot.key.0 == var.0 + && slot.key.1 == format!("{:?}",var.1) + { + let id = slot.value.as_ref().unwrap().id; + println!("found initial : recipe with id {}", id); + return Some(id); + } else { + return None; + } + }); + let ini = if let Some(id) = initial_id { + let new_ini = domain.values.iter().find(|r| r.id == id); + println!("Overrided {:?}", new_ini); + new_ini + } else { + ini + }; + // If found, override initial value + problem = problem.add_variable(var, dom, ini); + } + let mut problem = problem + .add_constraint(|_| true) + .finish(); + if let Some(one_result) = problem.solve_one() { + Json(TemplateObject { + items: one_result + .into_iter() + .map(|(k,v)| { + TemplateItems { + key: (format!("{}", k.0), format!("{:?}", k.1)), + value: v.map(|r| RecipeObject::from(&conn, r.clone())), + }}) + .collect(), + }) + } else { + panic!("No solution at all !"); + } + } } fn main() -> Result<(), Error> { @@ -137,7 +196,12 @@ fn main() -> Result<(), Error> { rocket::ignite() .attach(api::CookbookDbConn::fairing()) .mount("/", routes![index, files]) - .mount("/api", routes![api::recipes_list, api::delete_recipe, api::one_solution]) + .mount("/api", routes![ + api::recipes_list, + api::delete_recipe, + api::one_solution, + api::complete_problem, + ]) .attach(cors) .launch(); Ok(()) diff --git a/web/vue/src/components/Planner.vue b/web/vue/src/components/Planner.vue index 3216c42..beee6fd 100644 --- a/web/vue/src/components/Planner.vue +++ b/web/vue/src/components/Planner.vue @@ -1,6 +1,6 @@